Linux 4.20-rc4
-----BEGIN PGP SIGNATURE----- iQFSBAABCAA8FiEEq68RxlopcLEwq+PEeb4+QwBBGIYFAlv7H/seHHRvcnZhbGRz QGxpbnV4LWZvdW5kYXRpb24ub3JnAAoJEHm+PkMAQRiGhasH/AvNibkzTAPQR7jE r/R7NIaFUdPpaHYpLpoYIdSWkqpeWtN3q4eldJKWcpFCaE83EzDVu1PRw79rt/lm JIYbZ2SZWbTB7d2TLEiEF2bFXr+OF8MVc1tSAsP5xTMvV6mIz7+i2xr9R0D4YrKY ejd+ExF3HimuRf557Uey1MGsRIhedHsHjHbWjvR1MuKzvUv9nAL+1E2KJbfPXacp LGXElCYcPXoKw+GxMS7C28idgLoEJoS/eVieRiMGsGlgEe/MuaNMU+GRLMde9lI0 c/G/4uumJTHVY7npOjuNt1+2FoLVt8oLlhPcB06R7FIwJN+TupLQifqBkIe2saT6 R6ExonQ= =+/RR -----END PGP SIGNATURE----- Merge v4.20-rc4 into drm-next Requested by Boris Brezillon for some vc4 fixes that are needed for future vc4 work. Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
		
						commit
						1ec28f8b8a
					
				
							
								
								
									
										4
									
								
								CREDITS
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								CREDITS
									
									
									
									
									
								
							| @ -2204,6 +2204,10 @@ S: Post Office Box 371 | ||||
| S: North Little Rock, Arkansas 72115 | ||||
| S: USA | ||||
| 
 | ||||
| N: Christopher Li | ||||
| E: sparse@chrisli.org | ||||
| D: Sparse maintainer 2009 - 2018 | ||||
| 
 | ||||
| N: Stephan Linz | ||||
| E: linz@mazet.de | ||||
| E: Stephan.Linz@gmx.de | ||||
|  | ||||
| @ -4713,6 +4713,8 @@ | ||||
| 					prevent spurious wakeup); | ||||
| 				n = USB_QUIRK_DELAY_CTRL_MSG (Device needs a | ||||
| 					pause after every control message); | ||||
| 				o = USB_QUIRK_HUB_SLOW_RESET (Hub needs extra | ||||
| 					delay after resetting its port); | ||||
| 			Example: quirks=0781:5580:bk,0a5c:5834:gij | ||||
| 
 | ||||
| 	usbhid.mousepoll= | ||||
|  | ||||
| @ -32,16 +32,17 @@ Disclosure and embargoed information | ||||
| The security list is not a disclosure channel.  For that, see Coordination | ||||
| below. | ||||
| 
 | ||||
| Once a robust fix has been developed, our preference is to release the | ||||
| fix in a timely fashion, treating it no differently than any of the other | ||||
| thousands of changes and fixes the Linux kernel project releases every | ||||
| month. | ||||
| Once a robust fix has been developed, the release process starts.  Fixes | ||||
| for publicly known bugs are released immediately. | ||||
| 
 | ||||
| However, at the request of the reporter, we will postpone releasing the | ||||
| fix for up to 5 business days after the date of the report or after the | ||||
| embargo has lifted; whichever comes first.  The only exception to that | ||||
| rule is if the bug is publicly known, in which case the preference is to | ||||
| release the fix as soon as it's available. | ||||
| Although our preference is to release fixes for publicly undisclosed bugs | ||||
| as soon as they become available, this may be postponed at the request of | ||||
| the reporter or an affected party for up to 7 calendar days from the start | ||||
| of the release process, with an exceptional extension to 14 calendar days | ||||
| if it is agreed that the criticality of the bug requires more time.  The | ||||
| only valid reason for deferring the publication of a fix is to accommodate | ||||
| the logistics of QA and large scale rollouts which require release | ||||
| coordination. | ||||
| 
 | ||||
| Whilst embargoed information may be shared with trusted individuals in | ||||
| order to develop a fix, such information will not be published alongside | ||||
|  | ||||
| @ -74,7 +74,8 @@ using :c:func:`xa_load`.  xa_store will overwrite any entry with the | ||||
| new entry and return the previous entry stored at that index.  You can | ||||
| use :c:func:`xa_erase` instead of calling :c:func:`xa_store` with a | ||||
| ``NULL`` entry.  There is no difference between an entry that has never | ||||
| been stored to and one that has most recently had ``NULL`` stored to it. | ||||
| been stored to, one that has been erased and one that has most recently | ||||
| had ``NULL`` stored to it. | ||||
| 
 | ||||
| You can conditionally replace an entry at an index by using | ||||
| :c:func:`xa_cmpxchg`.  Like :c:func:`cmpxchg`, it will only succeed if | ||||
| @ -105,23 +106,44 @@ may result in the entry being marked at some, but not all of the other | ||||
| indices.  Storing into one index may result in the entry retrieved by | ||||
| some, but not all of the other indices changing. | ||||
| 
 | ||||
| Sometimes you need to ensure that a subsequent call to :c:func:`xa_store` | ||||
| will not need to allocate memory.  The :c:func:`xa_reserve` function | ||||
| will store a reserved entry at the indicated index.  Users of the normal | ||||
| API will see this entry as containing ``NULL``.  If you do not need to | ||||
| use the reserved entry, you can call :c:func:`xa_release` to remove the | ||||
| unused entry.  If another user has stored to the entry in the meantime, | ||||
| :c:func:`xa_release` will do nothing; if instead you want the entry to | ||||
| become ``NULL``, you should use :c:func:`xa_erase`. | ||||
| 
 | ||||
| If all entries in the array are ``NULL``, the :c:func:`xa_empty` function | ||||
| will return ``true``. | ||||
| 
 | ||||
| Finally, you can remove all entries from an XArray by calling | ||||
| :c:func:`xa_destroy`.  If the XArray entries are pointers, you may wish | ||||
| to free the entries first.  You can do this by iterating over all present | ||||
| entries in the XArray using the :c:func:`xa_for_each` iterator. | ||||
| 
 | ||||
| ID assignment | ||||
| ------------- | ||||
| Allocating XArrays | ||||
| ------------------ | ||||
| 
 | ||||
| If you use :c:func:`DEFINE_XARRAY_ALLOC` to define the XArray, or | ||||
| initialise it by passing ``XA_FLAGS_ALLOC`` to :c:func:`xa_init_flags`, | ||||
| the XArray changes to track whether entries are in use or not. | ||||
| 
 | ||||
| You can call :c:func:`xa_alloc` to store the entry at any unused index | ||||
| in the XArray.  If you need to modify the array from interrupt context, | ||||
| you can use :c:func:`xa_alloc_bh` or :c:func:`xa_alloc_irq` to disable | ||||
| interrupts while allocating the ID.  Unlike :c:func:`xa_store`, allocating | ||||
| a ``NULL`` pointer does not delete an entry.  Instead it reserves an | ||||
| entry like :c:func:`xa_reserve` and you can release it using either | ||||
| :c:func:`xa_erase` or :c:func:`xa_release`.  To use ID assignment, the | ||||
| XArray must be defined with :c:func:`DEFINE_XARRAY_ALLOC`, or initialised | ||||
| by passing ``XA_FLAGS_ALLOC`` to :c:func:`xa_init_flags`, | ||||
| interrupts while allocating the ID. | ||||
| 
 | ||||
| Using :c:func:`xa_store`, :c:func:`xa_cmpxchg` or :c:func:`xa_insert` | ||||
| will mark the entry as being allocated.  Unlike a normal XArray, storing | ||||
| ``NULL`` will mark the entry as being in use, like :c:func:`xa_reserve`. | ||||
| To free an entry, use :c:func:`xa_erase` (or :c:func:`xa_release` if | ||||
| you only want to free the entry if it's ``NULL``). | ||||
| 
 | ||||
| You cannot use ``XA_MARK_0`` with an allocating XArray as this mark | ||||
| is used to track whether an entry is free or not.  The other marks are | ||||
| available for your use. | ||||
| 
 | ||||
| Memory allocation | ||||
| ----------------- | ||||
| @ -158,6 +180,8 @@ Takes RCU read lock: | ||||
| 
 | ||||
| Takes xa_lock internally: | ||||
|  * :c:func:`xa_store` | ||||
|  * :c:func:`xa_store_bh` | ||||
|  * :c:func:`xa_store_irq` | ||||
|  * :c:func:`xa_insert` | ||||
|  * :c:func:`xa_erase` | ||||
|  * :c:func:`xa_erase_bh` | ||||
| @ -167,6 +191,9 @@ Takes xa_lock internally: | ||||
|  * :c:func:`xa_alloc` | ||||
|  * :c:func:`xa_alloc_bh` | ||||
|  * :c:func:`xa_alloc_irq` | ||||
|  * :c:func:`xa_reserve` | ||||
|  * :c:func:`xa_reserve_bh` | ||||
|  * :c:func:`xa_reserve_irq` | ||||
|  * :c:func:`xa_destroy` | ||||
|  * :c:func:`xa_set_mark` | ||||
|  * :c:func:`xa_clear_mark` | ||||
| @ -177,6 +204,7 @@ Assumes xa_lock held on entry: | ||||
|  * :c:func:`__xa_erase` | ||||
|  * :c:func:`__xa_cmpxchg` | ||||
|  * :c:func:`__xa_alloc` | ||||
|  * :c:func:`__xa_reserve` | ||||
|  * :c:func:`__xa_set_mark` | ||||
|  * :c:func:`__xa_clear_mark` | ||||
| 
 | ||||
| @ -234,7 +262,8 @@ Sharing the XArray with interrupt context is also possible, either | ||||
| using :c:func:`xa_lock_irqsave` in both the interrupt handler and process | ||||
| context, or :c:func:`xa_lock_irq` in process context and :c:func:`xa_lock` | ||||
| in the interrupt handler.  Some of the more common patterns have helper | ||||
| functions such as :c:func:`xa_erase_bh` and :c:func:`xa_erase_irq`. | ||||
| functions such as :c:func:`xa_store_bh`, :c:func:`xa_store_irq`, | ||||
| :c:func:`xa_erase_bh` and :c:func:`xa_erase_irq`. | ||||
| 
 | ||||
| Sometimes you need to protect access to the XArray with a mutex because | ||||
| that lock sits above another mutex in the locking hierarchy.  That does | ||||
| @ -322,7 +351,8 @@ to :c:func:`xas_retry`, and retry the operation if it returns ``true``. | ||||
|      - :c:func:`xa_is_zero` | ||||
|      - Zero entries appear as ``NULL`` through the Normal API, but occupy | ||||
|        an entry in the XArray which can be used to reserve the index for | ||||
|        future use. | ||||
|        future use.  This is used by allocating XArrays for allocated entries | ||||
|        which are ``NULL``. | ||||
| 
 | ||||
| Other internal entries may be added in the future.  As far as possible, they | ||||
| will be handled by :c:func:`xas_retry`. | ||||
|  | ||||
| @ -17,7 +17,7 @@ Example: | ||||
| 		reg = <1>; | ||||
| 		clocks = <&clk32m>; | ||||
| 		interrupt-parent = <&gpio4>; | ||||
| 		interrupts = <13 IRQ_TYPE_EDGE_RISING>; | ||||
| 		interrupts = <13 IRQ_TYPE_LEVEL_HIGH>; | ||||
| 		vdd-supply = <®5v0>; | ||||
| 		xceiver-supply = <®5v0>; | ||||
| 	}; | ||||
|  | ||||
| @ -5,6 +5,7 @@ Required properties: | ||||
| - compatible: "renesas,can-r8a7743" if CAN controller is a part of R8A7743 SoC. | ||||
| 	      "renesas,can-r8a7744" if CAN controller is a part of R8A7744 SoC. | ||||
| 	      "renesas,can-r8a7745" if CAN controller is a part of R8A7745 SoC. | ||||
| 	      "renesas,can-r8a774a1" if CAN controller is a part of R8A774A1 SoC. | ||||
| 	      "renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC. | ||||
| 	      "renesas,can-r8a7779" if CAN controller is a part of R8A7779 SoC. | ||||
| 	      "renesas,can-r8a7790" if CAN controller is a part of R8A7790 SoC. | ||||
| @ -14,26 +15,32 @@ Required properties: | ||||
| 	      "renesas,can-r8a7794" if CAN controller is a part of R8A7794 SoC. | ||||
| 	      "renesas,can-r8a7795" if CAN controller is a part of R8A7795 SoC. | ||||
| 	      "renesas,can-r8a7796" if CAN controller is a part of R8A7796 SoC. | ||||
| 	      "renesas,can-r8a77965" if CAN controller is a part of R8A77965 SoC. | ||||
| 	      "renesas,rcar-gen1-can" for a generic R-Car Gen1 compatible device. | ||||
| 	      "renesas,rcar-gen2-can" for a generic R-Car Gen2 or RZ/G1 | ||||
| 	      compatible device. | ||||
| 	      "renesas,rcar-gen3-can" for a generic R-Car Gen3 compatible device. | ||||
| 	      "renesas,rcar-gen3-can" for a generic R-Car Gen3 or RZ/G2 | ||||
| 	      compatible device. | ||||
| 	      When compatible with the generic version, nodes must list the | ||||
| 	      SoC-specific version corresponding to the platform first | ||||
| 	      followed by the generic version. | ||||
| 
 | ||||
| - reg: physical base address and size of the R-Car CAN register map. | ||||
| - interrupts: interrupt specifier for the sole interrupt. | ||||
| - clocks: phandles and clock specifiers for 3 CAN clock inputs. | ||||
| - clock-names: 3 clock input name strings: "clkp1", "clkp2", "can_clk". | ||||
| - clocks: phandles and clock specifiers for 2 CAN clock inputs for RZ/G2 | ||||
| 	  devices. | ||||
| 	  phandles and clock specifiers for 3 CAN clock inputs for every other | ||||
| 	  SoC. | ||||
| - clock-names: 2 clock input name strings for RZ/G2: "clkp1", "can_clk". | ||||
| 	       3 clock input name strings for every other SoC: "clkp1", "clkp2", | ||||
| 	       "can_clk". | ||||
| - pinctrl-0: pin control group to be used for this controller. | ||||
| - pinctrl-names: must be "default". | ||||
| 
 | ||||
| Required properties for "renesas,can-r8a7795" and "renesas,can-r8a7796" | ||||
| compatible: | ||||
| In R8A7795 and R8A7796 SoCs, "clkp2" can be CANFD clock. This is a div6 clock | ||||
| and can be used by both CAN and CAN FD controller at the same time. It needs to | ||||
| be scaled to maximum frequency if any of these controllers use it. This is done | ||||
| Required properties for R8A7795, R8A7796 and R8A77965: | ||||
| For the denoted SoCs, "clkp2" can be CANFD clock. This is a div6 clock and can | ||||
| be used by both CAN and CAN FD controller at the same time. It needs to be | ||||
| scaled to maximum frequency if any of these controllers use it. This is done | ||||
| using the below properties: | ||||
| 
 | ||||
| - assigned-clocks: phandle of clkp2(CANFD) clock. | ||||
| @ -42,8 +49,9 @@ using the below properties: | ||||
| Optional properties: | ||||
| - renesas,can-clock-select: R-Car CAN Clock Source Select. Valid values are: | ||||
| 			    <0x0> (default) : Peripheral clock (clkp1) | ||||
| 			    <0x1> : Peripheral clock (clkp2) | ||||
| 			    <0x3> : Externally input clock | ||||
| 			    <0x1> : Peripheral clock (clkp2) (not supported by | ||||
| 				    RZ/G2 devices) | ||||
| 			    <0x3> : External input clock | ||||
| 
 | ||||
| Example | ||||
| ------- | ||||
|  | ||||
| @ -7,7 +7,7 @@ limitations. | ||||
| Current Binding | ||||
| --------------- | ||||
| 
 | ||||
| Switches are true Linux devices and can be probes by any means. Once | ||||
| Switches are true Linux devices and can be probed by any means. Once | ||||
| probed, they register to the DSA framework, passing a node | ||||
| pointer. This node is expected to fulfil the following binding, and | ||||
| may contain additional properties as required by the device it is | ||||
|  | ||||
| @ -190,16 +190,7 @@ A few EV_REL codes have special meanings: | ||||
| * REL_WHEEL, REL_HWHEEL: | ||||
| 
 | ||||
|   - These codes are used for vertical and horizontal scroll wheels, | ||||
|     respectively. The value is the number of "notches" moved on the wheel, the | ||||
|     physical size of which varies by device. For high-resolution wheels (which | ||||
|     report multiple events for each notch of movement, or do not have notches) | ||||
|     this may be an approximation based on the high-resolution scroll events. | ||||
| 
 | ||||
| * REL_WHEEL_HI_RES: | ||||
| 
 | ||||
|   - If a vertical scroll wheel supports high-resolution scrolling, this code | ||||
|     will be emitted in addition to REL_WHEEL. The value is the (approximate) | ||||
|     distance travelled by the user's finger, in microns. | ||||
|     respectively. | ||||
| 
 | ||||
| EV_ABS | ||||
| ------ | ||||
|  | ||||
| @ -40,7 +40,7 @@ To use the :ref:`format` ioctls applications set the ``type`` field of the | ||||
| the desired operation. Both drivers and applications must set the remainder of | ||||
| the :c:type:`v4l2_format` structure to 0. | ||||
| 
 | ||||
| .. _v4l2-meta-format: | ||||
| .. c:type:: v4l2_meta_format | ||||
| 
 | ||||
| .. tabularcolumns:: |p{1.4cm}|p{2.2cm}|p{13.9cm}| | ||||
| 
 | ||||
|  | ||||
| @ -132,6 +132,11 @@ The format as returned by :ref:`VIDIOC_TRY_FMT <VIDIOC_G_FMT>` must be identical | ||||
|       - ``sdr`` | ||||
|       - Definition of a data format, see :ref:`pixfmt`, used by SDR | ||||
| 	capture and output devices. | ||||
|     * - | ||||
|       - struct :c:type:`v4l2_meta_format` | ||||
|       - ``meta`` | ||||
|       - Definition of a metadata format, see :ref:`meta-formats`, used by | ||||
| 	metadata capture devices. | ||||
|     * - | ||||
|       - __u8 | ||||
|       - ``raw_data``\ [200] | ||||
|  | ||||
| @ -1056,18 +1056,23 @@ The kernel interface functions are as follows: | ||||
| 
 | ||||
| 	u32 rxrpc_kernel_check_life(struct socket *sock, | ||||
| 				    struct rxrpc_call *call); | ||||
| 	void rxrpc_kernel_probe_life(struct socket *sock, | ||||
| 				     struct rxrpc_call *call); | ||||
| 
 | ||||
|      This returns a number that is updated when ACKs are received from the peer | ||||
|      (notably including PING RESPONSE ACKs which we can elicit by sending PING | ||||
|      ACKs to see if the call still exists on the server).  The caller should | ||||
|      compare the numbers of two calls to see if the call is still alive after | ||||
|      waiting for a suitable interval. | ||||
|      The first function returns a number that is updated when ACKs are received | ||||
|      from the peer (notably including PING RESPONSE ACKs which we can elicit by | ||||
|      sending PING ACKs to see if the call still exists on the server).  The | ||||
|      caller should compare the numbers of two calls to see if the call is still | ||||
|      alive after waiting for a suitable interval. | ||||
| 
 | ||||
|      This allows the caller to work out if the server is still contactable and | ||||
|      if the call is still alive on the server whilst waiting for the server to | ||||
|      process a client operation. | ||||
| 
 | ||||
|      This function may transmit a PING ACK. | ||||
|      The second function causes a ping ACK to be transmitted to try to provoke | ||||
|      the peer into responding, which would then cause the value returned by the | ||||
|      first function to change.  Note that this must be called in TASK_RUNNING | ||||
|      state. | ||||
| 
 | ||||
|  (*) Get reply timestamp. | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										48
									
								
								MAINTAINERS
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								MAINTAINERS
									
									
									
									
									
								
							| @ -180,6 +180,7 @@ F:	drivers/net/hamradio/6pack.c | ||||
| 
 | ||||
| 8169 10/100/1000 GIGABIT ETHERNET DRIVER | ||||
| M:	Realtek linux nic maintainers <nic_swsd@realtek.com> | ||||
| M:	Heiner Kallweit <hkallweit1@gmail.com> | ||||
| L:	netdev@vger.kernel.org | ||||
| S:	Maintained | ||||
| F:	drivers/net/ethernet/realtek/r8169.c | ||||
| @ -717,7 +718,7 @@ F:	include/linux/mfd/altera-a10sr.h | ||||
| F:	include/dt-bindings/reset/altr,rst-mgr-a10sr.h | ||||
| 
 | ||||
| ALTERA TRIPLE SPEED ETHERNET DRIVER | ||||
| M:	Vince Bridgers <vbridger@opensource.altera.com> | ||||
| M:	Thor Thayer <thor.thayer@linux.intel.com> | ||||
| L:	netdev@vger.kernel.org | ||||
| L:	nios2-dev@lists.rocketboards.org (moderated for non-subscribers) | ||||
| S:	Maintained | ||||
| @ -3276,6 +3277,12 @@ F:	include/uapi/linux/caif/ | ||||
| F:	include/net/caif/ | ||||
| F:	net/caif/ | ||||
| 
 | ||||
| CAKE QDISC | ||||
| M:	Toke Høiland-Jørgensen <toke@toke.dk> | ||||
| L:	cake@lists.bufferbloat.net (moderated for non-subscribers) | ||||
| S:	Maintained | ||||
| F:	net/sched/sch_cake.c | ||||
| 
 | ||||
| CALGARY x86-64 IOMMU | ||||
| M:	Muli Ben-Yehuda <mulix@mulix.org> | ||||
| M:	Jon Mason <jdmason@kudzu.us> | ||||
| @ -5541,6 +5548,7 @@ F:	net/bridge/ | ||||
| ETHERNET PHY LIBRARY | ||||
| M:	Andrew Lunn <andrew@lunn.ch> | ||||
| M:	Florian Fainelli <f.fainelli@gmail.com> | ||||
| M:	Heiner Kallweit <hkallweit1@gmail.com> | ||||
| L:	netdev@vger.kernel.org | ||||
| S:	Maintained | ||||
| F:	Documentation/ABI/testing/sysfs-bus-mdio | ||||
| @ -6312,6 +6320,7 @@ F:	tools/testing/selftests/gpio/ | ||||
| 
 | ||||
| GPIO SUBSYSTEM | ||||
| M:	Linus Walleij <linus.walleij@linaro.org> | ||||
| M:	Bartosz Golaszewski <bgolaszewski@baylibre.com> | ||||
| L:	linux-gpio@vger.kernel.org | ||||
| T:	git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git | ||||
| S:	Maintained | ||||
| @ -7449,6 +7458,20 @@ S:	Maintained | ||||
| F:	Documentation/fb/intelfb.txt | ||||
| F:	drivers/video/fbdev/intelfb/ | ||||
| 
 | ||||
| INTEL GPIO DRIVERS | ||||
| M:	Andy Shevchenko <andriy.shevchenko@linux.intel.com> | ||||
| L:	linux-gpio@vger.kernel.org | ||||
| S:	Maintained | ||||
| T:	git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git | ||||
| F:	drivers/gpio/gpio-ich.c | ||||
| F:	drivers/gpio/gpio-intel-mid.c | ||||
| F:	drivers/gpio/gpio-lynxpoint.c | ||||
| F:	drivers/gpio/gpio-merrifield.c | ||||
| F:	drivers/gpio/gpio-ml-ioh.c | ||||
| F:	drivers/gpio/gpio-pch.c | ||||
| F:	drivers/gpio/gpio-sch.c | ||||
| F:	drivers/gpio/gpio-sodaville.c | ||||
| 
 | ||||
| INTEL GVT-g DRIVERS (Intel GPU Virtualization) | ||||
| M:	Zhenyu Wang <zhenyuw@linux.intel.com> | ||||
| M:	Zhi Wang <zhi.a.wang@intel.com> | ||||
| @ -7459,12 +7482,6 @@ T:	git https://github.com/intel/gvt-linux.git | ||||
| S:	Supported | ||||
| F:	drivers/gpu/drm/i915/gvt/ | ||||
| 
 | ||||
| INTEL PMIC GPIO DRIVER | ||||
| R:	Andy Shevchenko <andriy.shevchenko@linux.intel.com> | ||||
| S:	Maintained | ||||
| F:	drivers/gpio/gpio-*cove.c | ||||
| F:	drivers/gpio/gpio-msic.c | ||||
| 
 | ||||
| INTEL HID EVENT DRIVER | ||||
| M:	Alex Hung <alex.hung@canonical.com> | ||||
| L:	platform-driver-x86@vger.kernel.org | ||||
| @ -7552,12 +7569,6 @@ W:	https://01.org/linux-acpi | ||||
| S:	Supported | ||||
| F:	drivers/platform/x86/intel_menlow.c | ||||
| 
 | ||||
| INTEL MERRIFIELD GPIO DRIVER | ||||
| M:	Andy Shevchenko <andriy.shevchenko@linux.intel.com> | ||||
| L:	linux-gpio@vger.kernel.org | ||||
| S:	Maintained | ||||
| F:	drivers/gpio/gpio-merrifield.c | ||||
| 
 | ||||
| INTEL MIC DRIVERS (mic) | ||||
| M:	Sudeep Dutt <sudeep.dutt@intel.com> | ||||
| M:	Ashutosh Dixit <ashutosh.dixit@intel.com> | ||||
| @ -7590,6 +7601,13 @@ F:	drivers/platform/x86/intel_punit_ipc.c | ||||
| F:	arch/x86/include/asm/intel_pmc_ipc.h | ||||
| F:	arch/x86/include/asm/intel_punit_ipc.h | ||||
| 
 | ||||
| INTEL PMIC GPIO DRIVERS | ||||
| M:	Andy Shevchenko <andriy.shevchenko@linux.intel.com> | ||||
| S:	Maintained | ||||
| T:	git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git | ||||
| F:	drivers/gpio/gpio-*cove.c | ||||
| F:	drivers/gpio/gpio-msic.c | ||||
| 
 | ||||
| INTEL MULTIFUNCTION PMIC DEVICE DRIVERS | ||||
| R:	Andy Shevchenko <andriy.shevchenko@linux.intel.com> | ||||
| S:	Maintained | ||||
| @ -13991,11 +14009,10 @@ F:	drivers/tty/serial/sunzilog.h | ||||
| F:	drivers/tty/vcc.c | ||||
| 
 | ||||
| SPARSE CHECKER | ||||
| M:	"Christopher Li" <sparse@chrisli.org> | ||||
| M:	"Luc Van Oostenryck" <luc.vanoostenryck@gmail.com> | ||||
| L:	linux-sparse@vger.kernel.org | ||||
| W:	https://sparse.wiki.kernel.org/ | ||||
| T:	git git://git.kernel.org/pub/scm/devel/sparse/sparse.git | ||||
| T:	git git://git.kernel.org/pub/scm/devel/sparse/chrisl/sparse.git | ||||
| S:	Maintained | ||||
| F:	include/linux/compiler.h | ||||
| 
 | ||||
| @ -14092,6 +14109,7 @@ F:	Documentation/devicetree/bindings/iio/proximity/vl53l0x.txt | ||||
| 
 | ||||
| STABLE BRANCH | ||||
| M:	Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||||
| M:	Sasha Levin <sashal@kernel.org> | ||||
| L:	stable@vger.kernel.org | ||||
| S:	Supported | ||||
| F:	Documentation/process/stable-kernel-rules.rst | ||||
|  | ||||
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							| @ -2,8 +2,8 @@ | ||||
| VERSION = 4 | ||||
| PATCHLEVEL = 20 | ||||
| SUBLEVEL = 0 | ||||
| EXTRAVERSION = -rc3 | ||||
| NAME = "People's Front" | ||||
| EXTRAVERSION = -rc4 | ||||
| NAME = Shy Crocodile | ||||
| 
 | ||||
| # *DOCUMENTATION*
 | ||||
| # To see a list of typical targets execute "make help"
 | ||||
|  | ||||
| @ -468,7 +468,7 @@ | ||||
| 			 SCTLR_ELx_SA     | SCTLR_ELx_I    | SCTLR_ELx_WXN | \ | ||||
| 			 SCTLR_ELx_DSSBS | ENDIAN_CLEAR_EL2 | SCTLR_EL2_RES0) | ||||
| 
 | ||||
| #if (SCTLR_EL2_SET ^ SCTLR_EL2_CLEAR) != 0xffffffffffffffff | ||||
| #if (SCTLR_EL2_SET ^ SCTLR_EL2_CLEAR) != 0xffffffffffffffffUL | ||||
| #error "Inconsistent SCTLR_EL2 set/clear bits" | ||||
| #endif | ||||
| 
 | ||||
| @ -509,7 +509,7 @@ | ||||
| 			 SCTLR_EL1_UMA | SCTLR_ELx_WXN     | ENDIAN_CLEAR_EL1 |\ | ||||
| 			 SCTLR_ELx_DSSBS | SCTLR_EL1_NTWI  | SCTLR_EL1_RES0) | ||||
| 
 | ||||
| #if (SCTLR_EL1_SET ^ SCTLR_EL1_CLEAR) != 0xffffffffffffffff | ||||
| #if (SCTLR_EL1_SET ^ SCTLR_EL1_CLEAR) != 0xffffffffffffffffUL | ||||
| #error "Inconsistent SCTLR_EL1 set/clear bits" | ||||
| #endif | ||||
| 
 | ||||
|  | ||||
| @ -1333,7 +1333,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = { | ||||
| 		.cpu_enable = cpu_enable_hw_dbm, | ||||
| 	}, | ||||
| #endif | ||||
| #ifdef CONFIG_ARM64_SSBD | ||||
| 	{ | ||||
| 		.desc = "CRC32 instructions", | ||||
| 		.capability = ARM64_HAS_CRC32, | ||||
| @ -1343,6 +1342,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = { | ||||
| 		.field_pos = ID_AA64ISAR0_CRC32_SHIFT, | ||||
| 		.min_field_value = 1, | ||||
| 	}, | ||||
| #ifdef CONFIG_ARM64_SSBD | ||||
| 	{ | ||||
| 		.desc = "Speculative Store Bypassing Safe (SSBS)", | ||||
| 		.capability = ARM64_SSBS, | ||||
|  | ||||
| @ -140,6 +140,7 @@ CONFIG_RTC_CLASS=y | ||||
| CONFIG_RTC_DRV_DS1307=y | ||||
| CONFIG_STAGING=y | ||||
| CONFIG_OCTEON_ETHERNET=y | ||||
| CONFIG_OCTEON_USB=y | ||||
| # CONFIG_IOMMU_SUPPORT is not set | ||||
| CONFIG_RAS=y | ||||
| CONFIG_EXT4_FS=y | ||||
|  | ||||
| @ -794,6 +794,7 @@ static void __init arch_mem_init(char **cmdline_p) | ||||
| 
 | ||||
| 	/* call board setup routine */ | ||||
| 	plat_mem_setup(); | ||||
| 	memblock_set_bottom_up(true); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Make sure all kernel memory is in the maps.  The "UP" and | ||||
|  | ||||
| @ -2260,10 +2260,8 @@ void __init trap_init(void) | ||||
| 		unsigned long size = 0x200 + VECTORSPACING*64; | ||||
| 		phys_addr_t ebase_pa; | ||||
| 
 | ||||
| 		memblock_set_bottom_up(true); | ||||
| 		ebase = (unsigned long) | ||||
| 			memblock_alloc_from(size, 1 << fls(size), 0); | ||||
| 		memblock_set_bottom_up(false); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Try to ensure ebase resides in KSeg0 if possible. | ||||
| @ -2307,6 +2305,7 @@ void __init trap_init(void) | ||||
| 	if (board_ebase_setup) | ||||
| 		board_ebase_setup(); | ||||
| 	per_cpu_trap_init(true); | ||||
| 	memblock_set_bottom_up(false); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Copy the generic exception handlers to their final destination. | ||||
|  | ||||
| @ -231,6 +231,8 @@ static __init void prom_meminit(void) | ||||
| 			cpumask_clear(&__node_data[(node)]->cpumask); | ||||
| 		} | ||||
| 	} | ||||
| 	max_low_pfn = PHYS_PFN(memblock_end_of_DRAM()); | ||||
| 
 | ||||
| 	for (cpu = 0; cpu < loongson_sysconf.nr_cpus; cpu++) { | ||||
| 		node = cpu / loongson_sysconf.cores_per_node; | ||||
| 		if (node >= num_online_nodes()) | ||||
| @ -248,19 +250,9 @@ static __init void prom_meminit(void) | ||||
| 
 | ||||
| void __init paging_init(void) | ||||
| { | ||||
| 	unsigned node; | ||||
| 	unsigned long zones_size[MAX_NR_ZONES] = {0, }; | ||||
| 
 | ||||
| 	pagetable_init(); | ||||
| 
 | ||||
| 	for_each_online_node(node) { | ||||
| 		unsigned long  start_pfn, end_pfn; | ||||
| 
 | ||||
| 		get_pfn_range_for_nid(node, &start_pfn, &end_pfn); | ||||
| 
 | ||||
| 		if (end_pfn > max_low_pfn) | ||||
| 			max_low_pfn = end_pfn; | ||||
| 	} | ||||
| #ifdef CONFIG_ZONE_DMA32 | ||||
| 	zones_size[ZONE_DMA32] = MAX_DMA32_PFN; | ||||
| #endif | ||||
|  | ||||
| @ -435,6 +435,7 @@ void __init prom_meminit(void) | ||||
| 
 | ||||
| 	mlreset(); | ||||
| 	szmem(); | ||||
| 	max_low_pfn = PHYS_PFN(memblock_end_of_DRAM()); | ||||
| 
 | ||||
| 	for (node = 0; node < MAX_COMPACT_NODES; node++) { | ||||
| 		if (node_online(node)) { | ||||
| @ -455,18 +456,8 @@ extern void setup_zero_pages(void); | ||||
| void __init paging_init(void) | ||||
| { | ||||
| 	unsigned long zones_size[MAX_NR_ZONES] = {0, }; | ||||
| 	unsigned node; | ||||
| 
 | ||||
| 	pagetable_init(); | ||||
| 
 | ||||
| 	for_each_online_node(node) { | ||||
| 		unsigned long start_pfn, end_pfn; | ||||
| 
 | ||||
| 		get_pfn_range_for_nid(node, &start_pfn, &end_pfn); | ||||
| 
 | ||||
| 		if (end_pfn > max_low_pfn) | ||||
| 			max_low_pfn = end_pfn; | ||||
| 	} | ||||
| 	zones_size[ZONE_NORMAL] = max_low_pfn; | ||||
| 	free_area_init_nodes(zones_size); | ||||
| } | ||||
|  | ||||
| @ -71,6 +71,10 @@ KBUILD_CFLAGS += $(call cc-option,-mstrict-align) | ||||
| # arch specific predefines for sparse
 | ||||
| CHECKFLAGS += -D__riscv -D__riscv_xlen=$(BITS) | ||||
| 
 | ||||
| # Default target when executing plain make
 | ||||
| boot		:= arch/riscv/boot | ||||
| KBUILD_IMAGE	:= $(boot)/Image.gz | ||||
| 
 | ||||
| head-y := arch/riscv/kernel/head.o | ||||
| 
 | ||||
| core-y += arch/riscv/kernel/ arch/riscv/mm/ | ||||
| @ -81,4 +85,13 @@ PHONY += vdso_install | ||||
| vdso_install: | ||||
| 	$(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@ | ||||
| 
 | ||||
| all: vmlinux | ||||
| all: Image.gz | ||||
| 
 | ||||
| Image: vmlinux | ||||
| 	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ | ||||
| 
 | ||||
| Image.%: Image | ||||
| 	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ | ||||
| 
 | ||||
| zinstall install: | ||||
| 	$(Q)$(MAKE) $(build)=$(boot) $@ | ||||
|  | ||||
							
								
								
									
										2
									
								
								arch/riscv/boot/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								arch/riscv/boot/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| Image | ||||
| Image.gz | ||||
							
								
								
									
										33
									
								
								arch/riscv/boot/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								arch/riscv/boot/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| #
 | ||||
| # arch/riscv/boot/Makefile
 | ||||
| #
 | ||||
| # This file is included by the global makefile so that you can add your own
 | ||||
| # architecture-specific flags and dependencies.
 | ||||
| #
 | ||||
| # 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) 2018, Anup Patel.
 | ||||
| # Author: Anup Patel <anup@brainfault.org>
 | ||||
| #
 | ||||
| # Based on the ia64 and arm64 boot/Makefile.
 | ||||
| #
 | ||||
| 
 | ||||
| OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S | ||||
| 
 | ||||
| targets := Image | ||||
| 
 | ||||
| $(obj)/Image: vmlinux FORCE | ||||
| 	$(call if_changed,objcopy) | ||||
| 
 | ||||
| $(obj)/Image.gz: $(obj)/Image FORCE | ||||
| 	$(call if_changed,gzip) | ||||
| 
 | ||||
| install: | ||||
| 	$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
 | ||||
| 	$(obj)/Image System.map "$(INSTALL_PATH)" | ||||
| 
 | ||||
| zinstall: | ||||
| 	$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
 | ||||
| 	$(obj)/Image.gz System.map "$(INSTALL_PATH)" | ||||
							
								
								
									
										60
									
								
								arch/riscv/boot/install.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								arch/riscv/boot/install.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | ||||
| #!/bin/sh | ||||
| # | ||||
| # arch/riscv/boot/install.sh | ||||
| # | ||||
| # 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) 1995 by Linus Torvalds | ||||
| # | ||||
| # Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin | ||||
| # Adapted from code in arch/i386/boot/install.sh by Russell King | ||||
| # | ||||
| # "make install" script for the RISC-V Linux port | ||||
| # | ||||
| # Arguments: | ||||
| #   $1 - kernel version | ||||
| #   $2 - kernel image file | ||||
| #   $3 - kernel map file | ||||
| #   $4 - default install path (blank if root directory) | ||||
| # | ||||
| 
 | ||||
| verify () { | ||||
| 	if [ ! -f "$1" ]; then | ||||
| 		echo ""                                                   1>&2 | ||||
| 		echo " *** Missing file: $1"                              1>&2 | ||||
| 		echo ' *** You need to run "make" before "make install".' 1>&2 | ||||
| 		echo ""                                                   1>&2 | ||||
| 		exit 1 | ||||
| 	fi | ||||
| } | ||||
| 
 | ||||
| # Make sure the files actually exist | ||||
| verify "$2" | ||||
| verify "$3" | ||||
| 
 | ||||
| # User may have a custom install script | ||||
| if [ -x ~/bin/${INSTALLKERNEL} ]; then exec ~/bin/${INSTALLKERNEL} "$@"; fi | ||||
| if [ -x /sbin/${INSTALLKERNEL} ]; then exec /sbin/${INSTALLKERNEL} "$@"; fi | ||||
| 
 | ||||
| if [ "$(basename $2)" = "Image.gz" ]; then | ||||
| # Compressed install | ||||
|   echo "Installing compressed kernel" | ||||
|   base=vmlinuz | ||||
| else | ||||
| # Normal install | ||||
|   echo "Installing normal kernel" | ||||
|   base=vmlinux | ||||
| fi | ||||
| 
 | ||||
| if [ -f $4/$base-$1 ]; then | ||||
|   mv $4/$base-$1 $4/$base-$1.old | ||||
| fi | ||||
| cat $2 > $4/$base-$1 | ||||
| 
 | ||||
| # Install system map file | ||||
| if [ -f $4/System.map-$1 ]; then | ||||
|   mv $4/System.map-$1 $4/System.map-$1.old | ||||
| fi | ||||
| cp $3 $4/System.map-$1 | ||||
| @ -8,6 +8,7 @@ | ||||
| 
 | ||||
| #define MODULE_ARCH_VERMAGIC    "riscv" | ||||
| 
 | ||||
| struct module; | ||||
| u64 module_emit_got_entry(struct module *mod, u64 val); | ||||
| u64 module_emit_plt_entry(struct module *mod, u64 val); | ||||
| 
 | ||||
|  | ||||
| @ -400,13 +400,13 @@ extern unsigned long __must_check __asm_copy_from_user(void *to, | ||||
| static inline unsigned long | ||||
| raw_copy_from_user(void *to, const void __user *from, unsigned long n) | ||||
| { | ||||
| 	return __asm_copy_to_user(to, from, n); | ||||
| 	return __asm_copy_from_user(to, from, n); | ||||
| } | ||||
| 
 | ||||
| static inline unsigned long | ||||
| raw_copy_to_user(void __user *to, const void *from, unsigned long n) | ||||
| { | ||||
| 	return __asm_copy_from_user(to, from, n); | ||||
| 	return __asm_copy_to_user(to, from, n); | ||||
| } | ||||
| 
 | ||||
| extern long strncpy_from_user(char *dest, const char __user *src, long count); | ||||
|  | ||||
| @ -13,10 +13,9 @@ | ||||
| 
 | ||||
| /*
 | ||||
|  * There is explicitly no include guard here because this file is expected to | ||||
|  * be included multiple times.  See uapi/asm/syscalls.h for more info. | ||||
|  * be included multiple times. | ||||
|  */ | ||||
| 
 | ||||
| #define __ARCH_WANT_NEW_STAT | ||||
| #define __ARCH_WANT_SYS_CLONE | ||||
| 
 | ||||
| #include <uapi/asm/unistd.h> | ||||
| #include <uapi/asm/syscalls.h> | ||||
|  | ||||
| @ -1,13 +1,25 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0 */ | ||||
| /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ | ||||
| /*
 | ||||
|  * Copyright (C) 2017-2018 SiFive | ||||
|  * Copyright (C) 2018 David Abdurachmanov <david.abdurachmanov@gmail.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/>.
 | ||||
|  */ | ||||
| 
 | ||||
| /*
 | ||||
|  * There is explicitly no include guard here because this file is expected to | ||||
|  * be included multiple times in order to define the syscall macros via | ||||
|  * __SYSCALL. | ||||
|  */ | ||||
| #ifdef __LP64__ | ||||
| #define __ARCH_WANT_NEW_STAT | ||||
| #endif /* __LP64__ */ | ||||
| 
 | ||||
| #include <asm-generic/unistd.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * Allows the instruction cache to be flushed from userspace.  Despite RISC-V | ||||
| @ -64,7 +64,7 @@ int riscv_of_processor_hartid(struct device_node *node) | ||||
| 
 | ||||
| static void print_isa(struct seq_file *f, const char *orig_isa) | ||||
| { | ||||
| 	static const char *ext = "mafdc"; | ||||
| 	static const char *ext = "mafdcsu"; | ||||
| 	const char *isa = orig_isa; | ||||
| 	const char *e; | ||||
| 
 | ||||
| @ -88,11 +88,14 @@ static void print_isa(struct seq_file *f, const char *orig_isa) | ||||
| 	/*
 | ||||
| 	 * Check the rest of the ISA string for valid extensions, printing those | ||||
| 	 * we find.  RISC-V ISA strings define an order, so we only print the | ||||
| 	 * extension bits when they're in order. | ||||
| 	 * extension bits when they're in order. Hide the supervisor (S) | ||||
| 	 * extension from userspace as it's not accessible from there. | ||||
| 	 */ | ||||
| 	for (e = ext; *e != '\0'; ++e) { | ||||
| 		if (isa[0] == e[0]) { | ||||
| 			seq_write(f, isa, 1); | ||||
| 			if (isa[0] != 's') | ||||
| 				seq_write(f, isa, 1); | ||||
| 
 | ||||
| 			isa++; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -44,6 +44,16 @@ ENTRY(_start) | ||||
| 	amoadd.w a3, a2, (a3) | ||||
| 	bnez a3, .Lsecondary_start | ||||
| 
 | ||||
| 	/* Clear BSS for flat non-ELF images */ | ||||
| 	la a3, __bss_start | ||||
| 	la a4, __bss_stop | ||||
| 	ble a4, a3, clear_bss_done | ||||
| clear_bss: | ||||
| 	REG_S zero, (a3) | ||||
| 	add a3, a3, RISCV_SZPTR | ||||
| 	blt a3, a4, clear_bss | ||||
| clear_bss_done: | ||||
| 
 | ||||
| 	/* Save hart ID and DTB physical address */ | ||||
| 	mv s0, a0 | ||||
| 	mv s1, a1 | ||||
|  | ||||
| @ -74,7 +74,7 @@ SECTIONS | ||||
| 		*(.sbss*) | ||||
| 	} | ||||
| 
 | ||||
| 	BSS_SECTION(0, 0, 0) | ||||
| 	BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 0) | ||||
| 
 | ||||
| 	EXCEPTION_TABLE(0x10) | ||||
| 	NOTES | ||||
|  | ||||
| @ -30,6 +30,7 @@ static const struct acpi_device_id forbidden_id_list[] = { | ||||
| 	{"PNP0200",  0},	/* AT DMA Controller */ | ||||
| 	{"ACPI0009", 0},	/* IOxAPIC */ | ||||
| 	{"ACPI000A", 0},	/* IOAPIC */ | ||||
| 	{"SMB0001",  0},	/* ACPI SMBUS virtual device */ | ||||
| 	{"", 0}, | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -201,19 +201,28 @@ static const struct of_device_id ti_cpufreq_of_match[] = { | ||||
| 	{}, | ||||
| }; | ||||
| 
 | ||||
| static const struct of_device_id *ti_cpufreq_match_node(void) | ||||
| { | ||||
| 	struct device_node *np; | ||||
| 	const struct of_device_id *match; | ||||
| 
 | ||||
| 	np = of_find_node_by_path("/"); | ||||
| 	match = of_match_node(ti_cpufreq_of_match, np); | ||||
| 	of_node_put(np); | ||||
| 
 | ||||
| 	return match; | ||||
| } | ||||
| 
 | ||||
| static int ti_cpufreq_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	u32 version[VERSION_COUNT]; | ||||
| 	struct device_node *np; | ||||
| 	const struct of_device_id *match; | ||||
| 	struct opp_table *ti_opp_table; | ||||
| 	struct ti_cpufreq_data *opp_data; | ||||
| 	const char * const reg_names[] = {"vdd", "vbb"}; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	np = of_find_node_by_path("/"); | ||||
| 	match = of_match_node(ti_cpufreq_of_match, np); | ||||
| 	of_node_put(np); | ||||
| 	match = dev_get_platdata(&pdev->dev); | ||||
| 	if (!match) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| @ -290,7 +299,14 @@ fail_put_node: | ||||
| 
 | ||||
| static int ti_cpufreq_init(void) | ||||
| { | ||||
| 	platform_device_register_simple("ti-cpufreq", -1, NULL, 0); | ||||
| 	const struct of_device_id *match; | ||||
| 
 | ||||
| 	/* Check to ensure we are on a compatible platform */ | ||||
| 	match = ti_cpufreq_match_node(); | ||||
| 	if (match) | ||||
| 		platform_device_register_data(NULL, "ti-cpufreq", -1, match, | ||||
| 					      sizeof(*match)); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| module_init(ti_cpufreq_init); | ||||
|  | ||||
| @ -184,6 +184,7 @@ static long udmabuf_create(const struct udmabuf_create_list *head, | ||||
| 	exp_info.ops  = &udmabuf_ops; | ||||
| 	exp_info.size = ubuf->pagecount << PAGE_SHIFT; | ||||
| 	exp_info.priv = ubuf; | ||||
| 	exp_info.flags = O_RDWR; | ||||
| 
 | ||||
| 	buf = dma_buf_export(&exp_info); | ||||
| 	if (IS_ERR(buf)) { | ||||
|  | ||||
| @ -13,6 +13,7 @@ | ||||
| #include <linux/of.h> | ||||
| #include <linux/pm.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/serdev.h> | ||||
| #include <linux/slab.h> | ||||
| 
 | ||||
| @ -63,7 +64,7 @@ static int gnss_serial_write_raw(struct gnss_device *gdev, | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* write is only buffered synchronously */ | ||||
| 	ret = serdev_device_write(serdev, buf, count, 0); | ||||
| 	ret = serdev_device_write(serdev, buf, count, MAX_SCHEDULE_TIMEOUT); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 
 | ||||
|  | ||||
| @ -16,6 +16,7 @@ | ||||
| #include <linux/pm.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| #include <linux/regulator/consumer.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/serdev.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/wait.h> | ||||
| @ -83,7 +84,7 @@ static int sirf_write_raw(struct gnss_device *gdev, const unsigned char *buf, | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* write is only buffered synchronously */ | ||||
| 	ret = serdev_device_write(serdev, buf, count, 0); | ||||
| 	ret = serdev_device_write(serdev, buf, count, MAX_SCHEDULE_TIMEOUT); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 
 | ||||
|  | ||||
| @ -35,8 +35,8 @@ | ||||
| #define gpio_mockup_err(...)	pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__) | ||||
| 
 | ||||
| enum { | ||||
| 	GPIO_MOCKUP_DIR_OUT = 0, | ||||
| 	GPIO_MOCKUP_DIR_IN = 1, | ||||
| 	GPIO_MOCKUP_DIR_IN = 0, | ||||
| 	GPIO_MOCKUP_DIR_OUT = 1, | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
| @ -131,7 +131,7 @@ static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset) | ||||
| { | ||||
| 	struct gpio_mockup_chip *chip = gpiochip_get_data(gc); | ||||
| 
 | ||||
| 	return chip->lines[offset].dir; | ||||
| 	return !chip->lines[offset].dir; | ||||
| } | ||||
| 
 | ||||
| static int gpio_mockup_to_irq(struct gpio_chip *gc, unsigned int offset) | ||||
|  | ||||
| @ -268,8 +268,8 @@ static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||||
| 
 | ||||
| 	if (pxa_gpio_has_pinctrl()) { | ||||
| 		ret = pinctrl_gpio_direction_input(chip->base + offset); | ||||
| 		if (!ret) | ||||
| 			return 0; | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	spin_lock_irqsave(&gpio_lock, flags); | ||||
|  | ||||
| @ -1295,7 +1295,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, | ||||
| 	gdev->descs = kcalloc(chip->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL); | ||||
| 	if (!gdev->descs) { | ||||
| 		status = -ENOMEM; | ||||
| 		goto err_free_gdev; | ||||
| 		goto err_free_ida; | ||||
| 	} | ||||
| 
 | ||||
| 	if (chip->ngpio == 0) { | ||||
| @ -1427,8 +1427,9 @@ err_free_label: | ||||
| 	kfree_const(gdev->label); | ||||
| err_free_descs: | ||||
| 	kfree(gdev->descs); | ||||
| err_free_gdev: | ||||
| err_free_ida: | ||||
| 	ida_simple_remove(&gpio_ida, gdev->id); | ||||
| err_free_gdev: | ||||
| 	/* failures here can mean systems won't boot... */ | ||||
| 	pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__, | ||||
| 	       gdev->base, gdev->base + gdev->ngpio - 1, | ||||
|  | ||||
| @ -501,8 +501,11 @@ void amdgpu_amdkfd_set_compute_idle(struct kgd_dev *kgd, bool idle) | ||||
| { | ||||
| 	struct amdgpu_device *adev = (struct amdgpu_device *)kgd; | ||||
| 
 | ||||
| 	amdgpu_dpm_switch_power_profile(adev, | ||||
| 					PP_SMC_POWER_PROFILE_COMPUTE, !idle); | ||||
| 	if (adev->powerplay.pp_funcs && | ||||
| 	    adev->powerplay.pp_funcs->switch_power_profile) | ||||
| 		amdgpu_dpm_switch_power_profile(adev, | ||||
| 						PP_SMC_POWER_PROFILE_COMPUTE, | ||||
| 						!idle); | ||||
| } | ||||
| 
 | ||||
| bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid) | ||||
|  | ||||
| @ -626,6 +626,13 @@ int amdgpu_display_modeset_create_props(struct amdgpu_device *adev) | ||||
| 					 "dither", | ||||
| 					 amdgpu_dither_enum_list, sz); | ||||
| 
 | ||||
| 	if (amdgpu_device_has_dc_support(adev)) { | ||||
| 		adev->mode_info.max_bpc_property = | ||||
| 			drm_property_create_range(adev->ddev, 0, "max bpc", 8, 16); | ||||
| 		if (!adev->mode_info.max_bpc_property) | ||||
| 			return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -338,6 +338,8 @@ struct amdgpu_mode_info { | ||||
| 	struct drm_property *audio_property; | ||||
| 	/* FMT dithering */ | ||||
| 	struct drm_property *dither_property; | ||||
| 	/* maximum number of bits per channel for monitor color */ | ||||
| 	struct drm_property *max_bpc_property; | ||||
| 	/* hardcoded DFP edid from BIOS */ | ||||
| 	struct edid *bios_hardcoded_edid; | ||||
| 	int bios_hardcoded_edid_size; | ||||
|  | ||||
| @ -46,6 +46,7 @@ MODULE_FIRMWARE("amdgpu/tahiti_mc.bin"); | ||||
| MODULE_FIRMWARE("amdgpu/pitcairn_mc.bin"); | ||||
| MODULE_FIRMWARE("amdgpu/verde_mc.bin"); | ||||
| MODULE_FIRMWARE("amdgpu/oland_mc.bin"); | ||||
| MODULE_FIRMWARE("amdgpu/hainan_mc.bin"); | ||||
| MODULE_FIRMWARE("amdgpu/si58_mc.bin"); | ||||
| 
 | ||||
| #define MC_SEQ_MISC0__MT__MASK   0xf0000000 | ||||
|  | ||||
| @ -65,6 +65,13 @@ | ||||
| #define mmMP0_MISC_LIGHT_SLEEP_CTRL                                                             0x01ba | ||||
| #define mmMP0_MISC_LIGHT_SLEEP_CTRL_BASE_IDX                                                    0 | ||||
| 
 | ||||
| /* for Vega20 register name change */ | ||||
| #define mmHDP_MEM_POWER_CTRL	0x00d4 | ||||
| #define HDP_MEM_POWER_CTRL__IPH_MEM_POWER_CTRL_EN_MASK	0x00000001L | ||||
| #define HDP_MEM_POWER_CTRL__IPH_MEM_POWER_LS_EN_MASK	0x00000002L | ||||
| #define HDP_MEM_POWER_CTRL__RC_MEM_POWER_CTRL_EN_MASK	0x00010000L | ||||
| #define HDP_MEM_POWER_CTRL__RC_MEM_POWER_LS_EN_MASK		0x00020000L | ||||
| #define mmHDP_MEM_POWER_CTRL_BASE_IDX	0 | ||||
| /*
 | ||||
|  * Indirect registers accessor | ||||
|  */ | ||||
| @ -870,15 +877,33 @@ static void soc15_update_hdp_light_sleep(struct amdgpu_device *adev, bool enable | ||||
| { | ||||
| 	uint32_t def, data; | ||||
| 
 | ||||
| 	def = data = RREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS)); | ||||
| 	if (adev->asic_type == CHIP_VEGA20) { | ||||
| 		def = data = RREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_CTRL)); | ||||
| 
 | ||||
| 	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS)) | ||||
| 		data |= HDP_MEM_POWER_LS__LS_ENABLE_MASK; | ||||
| 	else | ||||
| 		data &= ~HDP_MEM_POWER_LS__LS_ENABLE_MASK; | ||||
| 		if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS)) | ||||
| 			data |= HDP_MEM_POWER_CTRL__IPH_MEM_POWER_CTRL_EN_MASK | | ||||
| 				HDP_MEM_POWER_CTRL__IPH_MEM_POWER_LS_EN_MASK | | ||||
| 				HDP_MEM_POWER_CTRL__RC_MEM_POWER_CTRL_EN_MASK | | ||||
| 				HDP_MEM_POWER_CTRL__RC_MEM_POWER_LS_EN_MASK; | ||||
| 		else | ||||
| 			data &= ~(HDP_MEM_POWER_CTRL__IPH_MEM_POWER_CTRL_EN_MASK | | ||||
| 				HDP_MEM_POWER_CTRL__IPH_MEM_POWER_LS_EN_MASK | | ||||
| 				HDP_MEM_POWER_CTRL__RC_MEM_POWER_CTRL_EN_MASK | | ||||
| 				HDP_MEM_POWER_CTRL__RC_MEM_POWER_LS_EN_MASK); | ||||
| 
 | ||||
| 	if (def != data) | ||||
| 		WREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS), data); | ||||
| 		if (def != data) | ||||
| 			WREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_CTRL), data); | ||||
| 	} else { | ||||
| 		def = data = RREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS)); | ||||
| 
 | ||||
| 		if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS)) | ||||
| 			data |= HDP_MEM_POWER_LS__LS_ENABLE_MASK; | ||||
| 		else | ||||
| 			data &= ~HDP_MEM_POWER_LS__LS_ENABLE_MASK; | ||||
| 
 | ||||
| 		if (def != data) | ||||
| 			WREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS), data); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void soc15_update_drm_clock_gating(struct amdgpu_device *adev, bool enable) | ||||
|  | ||||
| @ -2422,8 +2422,15 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, | ||||
| static enum dc_color_depth | ||||
| convert_color_depth_from_display_info(const struct drm_connector *connector) | ||||
| { | ||||
| 	struct dm_connector_state *dm_conn_state = | ||||
| 		to_dm_connector_state(connector->state); | ||||
| 	uint32_t bpc = connector->display_info.bpc; | ||||
| 
 | ||||
| 	/* TODO: Remove this when there's support for max_bpc in drm */ | ||||
| 	if (dm_conn_state && bpc > dm_conn_state->max_bpc) | ||||
| 		/* Round down to nearest even number. */ | ||||
| 		bpc = dm_conn_state->max_bpc - (dm_conn_state->max_bpc & 1); | ||||
| 
 | ||||
| 	switch (bpc) { | ||||
| 	case 0: | ||||
| 		/*
 | ||||
| @ -3007,6 +3014,9 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector, | ||||
| 	} else if (property == adev->mode_info.underscan_property) { | ||||
| 		dm_new_state->underscan_enable = val; | ||||
| 		ret = 0; | ||||
| 	} else if (property == adev->mode_info.max_bpc_property) { | ||||
| 		dm_new_state->max_bpc = val; | ||||
| 		ret = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| @ -3049,6 +3059,9 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector, | ||||
| 	} else if (property == adev->mode_info.underscan_property) { | ||||
| 		*val = dm_state->underscan_enable; | ||||
| 		ret = 0; | ||||
| 	} else if (property == adev->mode_info.max_bpc_property) { | ||||
| 		*val = dm_state->max_bpc; | ||||
| 		ret = 0; | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| @ -3859,6 +3872,9 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, | ||||
| 	drm_object_attach_property(&aconnector->base.base, | ||||
| 				adev->mode_info.underscan_vborder_property, | ||||
| 				0); | ||||
| 	drm_object_attach_property(&aconnector->base.base, | ||||
| 				adev->mode_info.max_bpc_property, | ||||
| 				0); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -252,6 +252,7 @@ struct dm_connector_state { | ||||
| 	enum amdgpu_rmx_type scaling; | ||||
| 	uint8_t underscan_vborder; | ||||
| 	uint8_t underscan_hborder; | ||||
| 	uint8_t max_bpc; | ||||
| 	bool underscan_enable; | ||||
| 	bool freesync_enable; | ||||
| 	bool freesync_capable; | ||||
|  | ||||
| @ -4525,12 +4525,12 @@ static int smu7_get_sclk_od(struct pp_hwmgr *hwmgr) | ||||
| 	struct smu7_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table); | ||||
| 	struct smu7_single_dpm_table *golden_sclk_table = | ||||
| 			&(data->golden_dpm_table.sclk_table); | ||||
| 	int value; | ||||
| 	int value = sclk_table->dpm_levels[sclk_table->count - 1].value; | ||||
| 	int golden_value = golden_sclk_table->dpm_levels | ||||
| 			[golden_sclk_table->count - 1].value; | ||||
| 
 | ||||
| 	value = (sclk_table->dpm_levels[sclk_table->count - 1].value - | ||||
| 			golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) * | ||||
| 			100 / | ||||
| 			golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value; | ||||
| 	value -= golden_value; | ||||
| 	value = DIV_ROUND_UP(value * 100, golden_value); | ||||
| 
 | ||||
| 	return value; | ||||
| } | ||||
| @ -4567,12 +4567,12 @@ static int smu7_get_mclk_od(struct pp_hwmgr *hwmgr) | ||||
| 	struct smu7_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table); | ||||
| 	struct smu7_single_dpm_table *golden_mclk_table = | ||||
| 			&(data->golden_dpm_table.mclk_table); | ||||
| 	int value; | ||||
|         int value = mclk_table->dpm_levels[mclk_table->count - 1].value; | ||||
| 	int golden_value = golden_mclk_table->dpm_levels | ||||
| 			[golden_mclk_table->count - 1].value; | ||||
| 
 | ||||
| 	value = (mclk_table->dpm_levels[mclk_table->count - 1].value - | ||||
| 			golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) * | ||||
| 			100 / | ||||
| 			golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value; | ||||
| 	value -= golden_value; | ||||
| 	value = DIV_ROUND_UP(value * 100, golden_value); | ||||
| 
 | ||||
| 	return value; | ||||
| } | ||||
|  | ||||
| @ -4522,15 +4522,13 @@ static int vega10_get_sclk_od(struct pp_hwmgr *hwmgr) | ||||
| 	struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table); | ||||
| 	struct vega10_single_dpm_table *golden_sclk_table = | ||||
| 			&(data->golden_dpm_table.gfx_table); | ||||
| 	int value; | ||||
| 
 | ||||
| 	value = (sclk_table->dpm_levels[sclk_table->count - 1].value - | ||||
| 			golden_sclk_table->dpm_levels | ||||
| 			[golden_sclk_table->count - 1].value) * | ||||
| 			100 / | ||||
| 			golden_sclk_table->dpm_levels | ||||
| 	int value = sclk_table->dpm_levels[sclk_table->count - 1].value; | ||||
| 	int golden_value = golden_sclk_table->dpm_levels | ||||
| 			[golden_sclk_table->count - 1].value; | ||||
| 
 | ||||
| 	value -= golden_value; | ||||
| 	value = DIV_ROUND_UP(value * 100, golden_value); | ||||
| 
 | ||||
| 	return value; | ||||
| } | ||||
| 
 | ||||
| @ -4575,16 +4573,13 @@ static int vega10_get_mclk_od(struct pp_hwmgr *hwmgr) | ||||
| 	struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table); | ||||
| 	struct vega10_single_dpm_table *golden_mclk_table = | ||||
| 			&(data->golden_dpm_table.mem_table); | ||||
| 	int value; | ||||
| 
 | ||||
| 	value = (mclk_table->dpm_levels | ||||
| 			[mclk_table->count - 1].value - | ||||
| 			golden_mclk_table->dpm_levels | ||||
| 			[golden_mclk_table->count - 1].value) * | ||||
| 			100 / | ||||
| 			golden_mclk_table->dpm_levels | ||||
| 	int value = mclk_table->dpm_levels[mclk_table->count - 1].value; | ||||
| 	int golden_value = golden_mclk_table->dpm_levels | ||||
| 			[golden_mclk_table->count - 1].value; | ||||
| 
 | ||||
| 	value -= golden_value; | ||||
| 	value = DIV_ROUND_UP(value * 100, golden_value); | ||||
| 
 | ||||
| 	return value; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -2243,12 +2243,12 @@ static int vega12_get_sclk_od(struct pp_hwmgr *hwmgr) | ||||
| 	struct vega12_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table); | ||||
| 	struct vega12_single_dpm_table *golden_sclk_table = | ||||
| 			&(data->golden_dpm_table.gfx_table); | ||||
| 	int value; | ||||
| 	int value = sclk_table->dpm_levels[sclk_table->count - 1].value; | ||||
| 	int golden_value = golden_sclk_table->dpm_levels | ||||
| 			[golden_sclk_table->count - 1].value; | ||||
| 
 | ||||
| 	value = (sclk_table->dpm_levels[sclk_table->count - 1].value - | ||||
| 			golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) * | ||||
| 			100 / | ||||
| 			golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value; | ||||
| 	value -= golden_value; | ||||
| 	value = DIV_ROUND_UP(value * 100, golden_value); | ||||
| 
 | ||||
| 	return value; | ||||
| } | ||||
| @ -2264,16 +2264,13 @@ static int vega12_get_mclk_od(struct pp_hwmgr *hwmgr) | ||||
| 	struct vega12_single_dpm_table *mclk_table = &(data->dpm_table.mem_table); | ||||
| 	struct vega12_single_dpm_table *golden_mclk_table = | ||||
| 			&(data->golden_dpm_table.mem_table); | ||||
| 	int value; | ||||
| 
 | ||||
| 	value = (mclk_table->dpm_levels | ||||
| 			[mclk_table->count - 1].value - | ||||
| 			golden_mclk_table->dpm_levels | ||||
| 			[golden_mclk_table->count - 1].value) * | ||||
| 			100 / | ||||
| 			golden_mclk_table->dpm_levels | ||||
| 	int value = mclk_table->dpm_levels[mclk_table->count - 1].value; | ||||
| 	int golden_value = golden_mclk_table->dpm_levels | ||||
| 			[golden_mclk_table->count - 1].value; | ||||
| 
 | ||||
| 	value -= golden_value; | ||||
| 	value = DIV_ROUND_UP(value * 100, golden_value); | ||||
| 
 | ||||
| 	return value; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -75,7 +75,17 @@ static void vega20_set_default_registry_data(struct pp_hwmgr *hwmgr) | ||||
| 	data->phy_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT; | ||||
| 	data->phy_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT; | ||||
| 
 | ||||
| 	data->registry_data.disallowed_features = 0x0; | ||||
| 	/*
 | ||||
| 	 * Disable the following features for now: | ||||
| 	 *   GFXCLK DS | ||||
| 	 *   SOCLK DS | ||||
| 	 *   LCLK DS | ||||
| 	 *   DCEFCLK DS | ||||
| 	 *   FCLK DS | ||||
| 	 *   MP1CLK DS | ||||
| 	 *   MP0CLK DS | ||||
| 	 */ | ||||
| 	data->registry_data.disallowed_features = 0xE0041C00; | ||||
| 	data->registry_data.od_state_in_dc_support = 0; | ||||
| 	data->registry_data.thermal_support = 1; | ||||
| 	data->registry_data.skip_baco_hardware = 0; | ||||
| @ -1313,12 +1323,13 @@ static int vega20_get_sclk_od( | ||||
| 			&(data->dpm_table.gfx_table); | ||||
| 	struct vega20_single_dpm_table *golden_sclk_table = | ||||
| 			&(data->golden_dpm_table.gfx_table); | ||||
| 	int value; | ||||
| 	int value = sclk_table->dpm_levels[sclk_table->count - 1].value; | ||||
| 	int golden_value = golden_sclk_table->dpm_levels | ||||
| 			[golden_sclk_table->count - 1].value; | ||||
| 
 | ||||
| 	/* od percentage */ | ||||
| 	value = DIV_ROUND_UP((sclk_table->dpm_levels[sclk_table->count - 1].value - | ||||
| 		golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) * 100, | ||||
| 		golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value); | ||||
| 	value -= golden_value; | ||||
| 	value = DIV_ROUND_UP(value * 100, golden_value); | ||||
| 
 | ||||
| 	return value; | ||||
| } | ||||
| @ -1358,12 +1369,13 @@ static int vega20_get_mclk_od( | ||||
| 			&(data->dpm_table.mem_table); | ||||
| 	struct vega20_single_dpm_table *golden_mclk_table = | ||||
| 			&(data->golden_dpm_table.mem_table); | ||||
| 	int value; | ||||
| 	int value = mclk_table->dpm_levels[mclk_table->count - 1].value; | ||||
| 	int golden_value = golden_mclk_table->dpm_levels | ||||
| 			[golden_mclk_table->count - 1].value; | ||||
| 
 | ||||
| 	/* od percentage */ | ||||
| 	value = DIV_ROUND_UP((mclk_table->dpm_levels[mclk_table->count - 1].value - | ||||
| 		golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) * 100, | ||||
| 		golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value); | ||||
| 	value -= golden_value; | ||||
| 	value = DIV_ROUND_UP(value * 100, golden_value); | ||||
| 
 | ||||
| 	return value; | ||||
| } | ||||
|  | ||||
| @ -60,8 +60,29 @@ static const struct pci_device_id pciidlist[] = { | ||||
| 
 | ||||
| MODULE_DEVICE_TABLE(pci, pciidlist); | ||||
| 
 | ||||
| static void ast_kick_out_firmware_fb(struct pci_dev *pdev) | ||||
| { | ||||
| 	struct apertures_struct *ap; | ||||
| 	bool primary = false; | ||||
| 
 | ||||
| 	ap = alloc_apertures(1); | ||||
| 	if (!ap) | ||||
| 		return; | ||||
| 
 | ||||
| 	ap->ranges[0].base = pci_resource_start(pdev, 0); | ||||
| 	ap->ranges[0].size = pci_resource_len(pdev, 0); | ||||
| 
 | ||||
| #ifdef CONFIG_X86 | ||||
| 	primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; | ||||
| #endif | ||||
| 	drm_fb_helper_remove_conflicting_framebuffers(ap, "astdrmfb", primary); | ||||
| 	kfree(ap); | ||||
| } | ||||
| 
 | ||||
| static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||||
| { | ||||
| 	ast_kick_out_firmware_fb(pdev); | ||||
| 
 | ||||
| 	return drm_get_pci_dev(pdev, ent, &driver); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -568,6 +568,7 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc, | ||||
| 	} | ||||
| 	ast_bo_unreserve(bo); | ||||
| 
 | ||||
| 	ast_set_offset_reg(crtc); | ||||
| 	ast_set_start_address_crt1(crtc, (u32)gpu_addr); | ||||
| 
 | ||||
| 	return 0; | ||||
| @ -1254,7 +1255,7 @@ static int ast_cursor_move(struct drm_crtc *crtc, | ||||
| 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc7, ((y >> 8) & 0x07)); | ||||
| 
 | ||||
| 	/* dummy write to fire HWC */ | ||||
| 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xCB, 0xFF, 0x00); | ||||
| 	ast_show_cursor(crtc); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @ -219,6 +219,9 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) | ||||
| 	mutex_lock(&fb_helper->lock); | ||||
| 	drm_connector_list_iter_begin(dev, &conn_iter); | ||||
| 	drm_for_each_connector_iter(connector, &conn_iter) { | ||||
| 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) | ||||
| 			continue; | ||||
| 
 | ||||
| 		ret = __drm_fb_helper_add_one_connector(fb_helper, connector); | ||||
| 		if (ret) | ||||
| 			goto fail; | ||||
|  | ||||
| @ -214,6 +214,12 @@ static int vc4_atomic_commit(struct drm_device *dev, | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* We know for sure we don't want an async update here. Set
 | ||||
| 	 * state->legacy_cursor_update to false to prevent | ||||
| 	 * drm_atomic_helper_setup_commit() from auto-completing | ||||
| 	 * commit->flip_done. | ||||
| 	 */ | ||||
| 	state->legacy_cursor_update = false; | ||||
| 	ret = drm_atomic_helper_setup_commit(state, nonblock); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
|  | ||||
| @ -854,7 +854,7 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) | ||||
| static void vc4_plane_atomic_async_update(struct drm_plane *plane, | ||||
| 					  struct drm_plane_state *state) | ||||
| { | ||||
| 	struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); | ||||
| 	struct vc4_plane_state *vc4_state, *new_vc4_state; | ||||
| 
 | ||||
| 	if (plane->state->fb != state->fb) { | ||||
| 		vc4_plane_async_set_fb(plane, state->fb); | ||||
| @ -875,7 +875,18 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane, | ||||
| 	plane->state->src_y = state->src_y; | ||||
| 
 | ||||
| 	/* Update the display list based on the new crtc_x/y. */ | ||||
| 	vc4_plane_atomic_check(plane, plane->state); | ||||
| 	vc4_plane_atomic_check(plane, state); | ||||
| 
 | ||||
| 	new_vc4_state = to_vc4_plane_state(state); | ||||
| 	vc4_state = to_vc4_plane_state(plane->state); | ||||
| 
 | ||||
| 	/* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */ | ||||
| 	vc4_state->dlist[vc4_state->pos0_offset] = | ||||
| 		new_vc4_state->dlist[vc4_state->pos0_offset]; | ||||
| 	vc4_state->dlist[vc4_state->pos2_offset] = | ||||
| 		new_vc4_state->dlist[vc4_state->pos2_offset]; | ||||
| 	vc4_state->dlist[vc4_state->ptr0_offset] = | ||||
| 		new_vc4_state->dlist[vc4_state->ptr0_offset]; | ||||
| 
 | ||||
| 	/* Note that we can't just call vc4_plane_write_dlist()
 | ||||
| 	 * because that would smash the context data that the HVS is | ||||
|  | ||||
| @ -275,6 +275,9 @@ | ||||
| 
 | ||||
| #define USB_VENDOR_ID_CIDC		0x1677 | ||||
| 
 | ||||
| #define I2C_VENDOR_ID_CIRQUE		0x0488 | ||||
| #define I2C_PRODUCT_ID_CIRQUE_121F	0x121F | ||||
| 
 | ||||
| #define USB_VENDOR_ID_CJTOUCH		0x24b8 | ||||
| #define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020	0x0020 | ||||
| #define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040	0x0040 | ||||
| @ -707,6 +710,7 @@ | ||||
| #define USB_VENDOR_ID_LG		0x1fd2 | ||||
| #define USB_DEVICE_ID_LG_MULTITOUCH	0x0064 | ||||
| #define USB_DEVICE_ID_LG_MELFAS_MT	0x6007 | ||||
| #define I2C_DEVICE_ID_LG_8001		0x8001 | ||||
| 
 | ||||
| #define USB_VENDOR_ID_LOGITECH		0x046d | ||||
| #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e | ||||
| @ -805,6 +809,7 @@ | ||||
| #define USB_DEVICE_ID_MS_TYPE_COVER_2    0x07a9 | ||||
| #define USB_DEVICE_ID_MS_POWER_COVER     0x07da | ||||
| #define USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER	0x02fd | ||||
| #define USB_DEVICE_ID_MS_PIXART_MOUSE    0x00cb | ||||
| 
 | ||||
| #define USB_VENDOR_ID_MOJO		0x8282 | ||||
| #define USB_DEVICE_ID_RETRO_ADAPTER	0x3201 | ||||
| @ -1043,6 +1048,7 @@ | ||||
| #define USB_VENDOR_ID_SYMBOL		0x05e0 | ||||
| #define USB_DEVICE_ID_SYMBOL_SCANNER_1	0x0800 | ||||
| #define USB_DEVICE_ID_SYMBOL_SCANNER_2	0x1300 | ||||
| #define USB_DEVICE_ID_SYMBOL_SCANNER_3	0x1200 | ||||
| 
 | ||||
| #define USB_VENDOR_ID_SYNAPTICS		0x06cb | ||||
| #define USB_DEVICE_ID_SYNAPTICS_TP	0x0001 | ||||
| @ -1204,6 +1210,8 @@ | ||||
| #define USB_DEVICE_ID_PRIMAX_MOUSE_4D22	0x4d22 | ||||
| #define USB_DEVICE_ID_PRIMAX_KEYBOARD	0x4e05 | ||||
| #define USB_DEVICE_ID_PRIMAX_REZEL	0x4e72 | ||||
| #define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F	0x4d0f | ||||
| #define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22	0x4e22 | ||||
| 
 | ||||
| 
 | ||||
| #define USB_VENDOR_ID_RISO_KAGAKU	0x1294	/* Riso Kagaku Corp. */ | ||||
|  | ||||
| @ -325,6 +325,9 @@ static const struct hid_device_id hid_battery_quirks[] = { | ||||
| 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, | ||||
| 		USB_DEVICE_ID_ELECOM_BM084), | ||||
| 	  HID_BATTERY_QUIRK_IGNORE }, | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_SYMBOL, | ||||
| 		USB_DEVICE_ID_SYMBOL_SCANNER_3), | ||||
| 	  HID_BATTERY_QUIRK_IGNORE }, | ||||
| 	{} | ||||
| }; | ||||
| 
 | ||||
| @ -1838,47 +1841,3 @@ void hidinput_disconnect(struct hid_device *hid) | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(hidinput_disconnect); | ||||
| 
 | ||||
| /**
 | ||||
|  * hid_scroll_counter_handle_scroll() - Send high- and low-resolution scroll | ||||
|  *                                      events given a high-resolution wheel | ||||
|  *                                      movement. | ||||
|  * @counter: a hid_scroll_counter struct describing the wheel. | ||||
|  * @hi_res_value: the movement of the wheel, in the mouse's high-resolution | ||||
|  *                units. | ||||
|  * | ||||
|  * Given a high-resolution movement, this function converts the movement into | ||||
|  * microns and emits high-resolution scroll events for the input device. It also | ||||
|  * uses the multiplier from &struct hid_scroll_counter to emit low-resolution | ||||
|  * scroll events when appropriate for backwards-compatibility with userspace | ||||
|  * input libraries. | ||||
|  */ | ||||
| void hid_scroll_counter_handle_scroll(struct hid_scroll_counter *counter, | ||||
| 				      int hi_res_value) | ||||
| { | ||||
| 	int low_res_value, remainder, multiplier; | ||||
| 
 | ||||
| 	input_report_rel(counter->dev, REL_WHEEL_HI_RES, | ||||
| 			 hi_res_value * counter->microns_per_hi_res_unit); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Update the low-res remainder with the high-res value, | ||||
| 	 * but reset if the direction has changed. | ||||
| 	 */ | ||||
| 	remainder = counter->remainder; | ||||
| 	if ((remainder ^ hi_res_value) < 0) | ||||
| 		remainder = 0; | ||||
| 	remainder += hi_res_value; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Then just use the resolution multiplier to see if | ||||
| 	 * we should send a low-res (aka regular wheel) event. | ||||
| 	 */ | ||||
| 	multiplier = counter->resolution_multiplier; | ||||
| 	low_res_value = remainder / multiplier; | ||||
| 	remainder -= low_res_value * multiplier; | ||||
| 	counter->remainder = remainder; | ||||
| 
 | ||||
| 	if (low_res_value) | ||||
| 		input_report_rel(counter->dev, REL_WHEEL, low_res_value); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(hid_scroll_counter_handle_scroll); | ||||
|  | ||||
| @ -64,14 +64,6 @@ MODULE_PARM_DESC(disable_tap_to_click, | ||||
| #define HIDPP_QUIRK_NO_HIDINPUT			BIT(23) | ||||
| #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS	BIT(24) | ||||
| #define HIDPP_QUIRK_UNIFYING			BIT(25) | ||||
| #define HIDPP_QUIRK_HI_RES_SCROLL_1P0		BIT(26) | ||||
| #define HIDPP_QUIRK_HI_RES_SCROLL_X2120		BIT(27) | ||||
| #define HIDPP_QUIRK_HI_RES_SCROLL_X2121		BIT(28) | ||||
| 
 | ||||
| /* Convenience constant to check for any high-res support. */ | ||||
| #define HIDPP_QUIRK_HI_RES_SCROLL	(HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \ | ||||
| 					 HIDPP_QUIRK_HI_RES_SCROLL_X2120 | \ | ||||
| 					 HIDPP_QUIRK_HI_RES_SCROLL_X2121) | ||||
| 
 | ||||
| #define HIDPP_QUIRK_DELAYED_INIT		HIDPP_QUIRK_NO_HIDINPUT | ||||
| 
 | ||||
| @ -157,7 +149,6 @@ struct hidpp_device { | ||||
| 	unsigned long capabilities; | ||||
| 
 | ||||
| 	struct hidpp_battery battery; | ||||
| 	struct hid_scroll_counter vertical_wheel_counter; | ||||
| }; | ||||
| 
 | ||||
| /* HID++ 1.0 error codes */ | ||||
| @ -409,53 +400,32 @@ static void hidpp_prefix_name(char **name, int name_length) | ||||
| #define HIDPP_SET_LONG_REGISTER				0x82 | ||||
| #define HIDPP_GET_LONG_REGISTER				0x83 | ||||
| 
 | ||||
| /**
 | ||||
|  * hidpp10_set_register_bit() - Sets a single bit in a HID++ 1.0 register. | ||||
|  * @hidpp_dev: the device to set the register on. | ||||
|  * @register_address: the address of the register to modify. | ||||
|  * @byte: the byte of the register to modify. Should be less than 3. | ||||
|  * Return: 0 if successful, otherwise a negative error code. | ||||
|  */ | ||||
| static int hidpp10_set_register_bit(struct hidpp_device *hidpp_dev, | ||||
| 	u8 register_address, u8 byte, u8 bit) | ||||
| #define HIDPP_REG_GENERAL				0x00 | ||||
| 
 | ||||
| static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev) | ||||
| { | ||||
| 	struct hidpp_report response; | ||||
| 	int ret; | ||||
| 	u8 params[3] = { 0 }; | ||||
| 
 | ||||
| 	ret = hidpp_send_rap_command_sync(hidpp_dev, | ||||
| 					  REPORT_ID_HIDPP_SHORT, | ||||
| 					  HIDPP_GET_REGISTER, | ||||
| 					  register_address, | ||||
| 					  NULL, 0, &response); | ||||
| 					REPORT_ID_HIDPP_SHORT, | ||||
| 					HIDPP_GET_REGISTER, | ||||
| 					HIDPP_REG_GENERAL, | ||||
| 					NULL, 0, &response); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	memcpy(params, response.rap.params, 3); | ||||
| 
 | ||||
| 	params[byte] |= BIT(bit); | ||||
| 	/* Set the battery bit */ | ||||
| 	params[0] |= BIT(4); | ||||
| 
 | ||||
| 	return hidpp_send_rap_command_sync(hidpp_dev, | ||||
| 					   REPORT_ID_HIDPP_SHORT, | ||||
| 					   HIDPP_SET_REGISTER, | ||||
| 					   register_address, | ||||
| 					   params, 3, &response); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #define HIDPP_REG_GENERAL				0x00 | ||||
| 
 | ||||
| static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev) | ||||
| { | ||||
| 	return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_GENERAL, 0, 4); | ||||
| } | ||||
| 
 | ||||
| #define HIDPP_REG_FEATURES				0x01 | ||||
| 
 | ||||
| /* On HID++ 1.0 devices, high-res scroll was called "scrolling acceleration". */ | ||||
| static int hidpp10_enable_scrolling_acceleration(struct hidpp_device *hidpp_dev) | ||||
| { | ||||
| 	return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_FEATURES, 0, 6); | ||||
| 					REPORT_ID_HIDPP_SHORT, | ||||
| 					HIDPP_SET_REGISTER, | ||||
| 					HIDPP_REG_GENERAL, | ||||
| 					params, 3, &response); | ||||
| } | ||||
| 
 | ||||
| #define HIDPP_REG_BATTERY_STATUS			0x07 | ||||
| @ -1166,100 +1136,6 @@ static int hidpp_battery_get_property(struct power_supply *psy, | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /* -------------------------------------------------------------------------- */ | ||||
| /* 0x2120: Hi-resolution scrolling                                            */ | ||||
| /* -------------------------------------------------------------------------- */ | ||||
| 
 | ||||
| #define HIDPP_PAGE_HI_RESOLUTION_SCROLLING			0x2120 | ||||
| 
 | ||||
| #define CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE	0x10 | ||||
| 
 | ||||
| static int hidpp_hrs_set_highres_scrolling_mode(struct hidpp_device *hidpp, | ||||
| 	bool enabled, u8 *multiplier) | ||||
| { | ||||
| 	u8 feature_index; | ||||
| 	u8 feature_type; | ||||
| 	int ret; | ||||
| 	u8 params[1]; | ||||
| 	struct hidpp_report response; | ||||
| 
 | ||||
| 	ret = hidpp_root_get_feature(hidpp, | ||||
| 				     HIDPP_PAGE_HI_RESOLUTION_SCROLLING, | ||||
| 				     &feature_index, | ||||
| 				     &feature_type); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	params[0] = enabled ? BIT(0) : 0; | ||||
| 	ret = hidpp_send_fap_command_sync(hidpp, feature_index, | ||||
| 					  CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE, | ||||
| 					  params, sizeof(params), &response); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 	*multiplier = response.fap.params[1]; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* -------------------------------------------------------------------------- */ | ||||
| /* 0x2121: HiRes Wheel                                                        */ | ||||
| /* -------------------------------------------------------------------------- */ | ||||
| 
 | ||||
| #define HIDPP_PAGE_HIRES_WHEEL		0x2121 | ||||
| 
 | ||||
| #define CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY	0x00 | ||||
| #define CMD_HIRES_WHEEL_SET_WHEEL_MODE		0x20 | ||||
| 
 | ||||
| static int hidpp_hrw_get_wheel_capability(struct hidpp_device *hidpp, | ||||
| 	u8 *multiplier) | ||||
| { | ||||
| 	u8 feature_index; | ||||
| 	u8 feature_type; | ||||
| 	int ret; | ||||
| 	struct hidpp_report response; | ||||
| 
 | ||||
| 	ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, | ||||
| 				     &feature_index, &feature_type); | ||||
| 	if (ret) | ||||
| 		goto return_default; | ||||
| 
 | ||||
| 	ret = hidpp_send_fap_command_sync(hidpp, feature_index, | ||||
| 					  CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY, | ||||
| 					  NULL, 0, &response); | ||||
| 	if (ret) | ||||
| 		goto return_default; | ||||
| 
 | ||||
| 	*multiplier = response.fap.params[0]; | ||||
| 	return 0; | ||||
| return_default: | ||||
| 	hid_warn(hidpp->hid_dev, | ||||
| 		 "Couldn't get wheel multiplier (error %d), assuming %d.\n", | ||||
| 		 ret, *multiplier); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int hidpp_hrw_set_wheel_mode(struct hidpp_device *hidpp, bool invert, | ||||
| 	bool high_resolution, bool use_hidpp) | ||||
| { | ||||
| 	u8 feature_index; | ||||
| 	u8 feature_type; | ||||
| 	int ret; | ||||
| 	u8 params[1]; | ||||
| 	struct hidpp_report response; | ||||
| 
 | ||||
| 	ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, | ||||
| 				     &feature_index, &feature_type); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	params[0] = (invert          ? BIT(2) : 0) | | ||||
| 		    (high_resolution ? BIT(1) : 0) | | ||||
| 		    (use_hidpp       ? BIT(0) : 0); | ||||
| 
 | ||||
| 	return hidpp_send_fap_command_sync(hidpp, feature_index, | ||||
| 					   CMD_HIRES_WHEEL_SET_WHEEL_MODE, | ||||
| 					   params, sizeof(params), &response); | ||||
| } | ||||
| 
 | ||||
| /* -------------------------------------------------------------------------- */ | ||||
| /* 0x4301: Solar Keyboard                                                     */ | ||||
| /* -------------------------------------------------------------------------- */ | ||||
| @ -2523,8 +2399,7 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size) | ||||
| 		input_report_rel(mydata->input, REL_Y, v); | ||||
| 
 | ||||
| 		v = hid_snto32(data[6], 8); | ||||
| 		hid_scroll_counter_handle_scroll( | ||||
| 				&hidpp->vertical_wheel_counter, v); | ||||
| 		input_report_rel(mydata->input, REL_WHEEL, v); | ||||
| 
 | ||||
| 		input_sync(mydata->input); | ||||
| 	} | ||||
| @ -2652,72 +2527,6 @@ static int g920_get_config(struct hidpp_device *hidpp) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* -------------------------------------------------------------------------- */ | ||||
| /* High-resolution scroll wheels                                              */ | ||||
| /* -------------------------------------------------------------------------- */ | ||||
| 
 | ||||
| /**
 | ||||
|  * struct hi_res_scroll_info - Stores info on a device's high-res scroll wheel. | ||||
|  * @product_id: the HID product ID of the device being described. | ||||
|  * @microns_per_hi_res_unit: the distance moved by the user's finger for each | ||||
|  *                         high-resolution unit reported by the device, in | ||||
|  *                         256ths of a millimetre. | ||||
|  */ | ||||
| struct hi_res_scroll_info { | ||||
| 	__u32 product_id; | ||||
| 	int microns_per_hi_res_unit; | ||||
| }; | ||||
| 
 | ||||
| static struct hi_res_scroll_info hi_res_scroll_devices[] = { | ||||
| 	{ /* Anywhere MX */ | ||||
| 	  .product_id = 0x1017, .microns_per_hi_res_unit = 445 }, | ||||
| 	{ /* Performance MX */ | ||||
| 	  .product_id = 0x101a, .microns_per_hi_res_unit = 406 }, | ||||
| 	{ /* M560 */ | ||||
| 	  .product_id = 0x402d, .microns_per_hi_res_unit = 435 }, | ||||
| 	{ /* MX Master 2S */ | ||||
| 	  .product_id = 0x4069, .microns_per_hi_res_unit = 406 }, | ||||
| }; | ||||
| 
 | ||||
| static int hi_res_scroll_look_up_microns(__u32 product_id) | ||||
| { | ||||
| 	int i; | ||||
| 	int num_devices = sizeof(hi_res_scroll_devices) | ||||
| 			  / sizeof(hi_res_scroll_devices[0]); | ||||
| 	for (i = 0; i < num_devices; i++) { | ||||
| 		if (hi_res_scroll_devices[i].product_id == product_id) | ||||
| 			return hi_res_scroll_devices[i].microns_per_hi_res_unit; | ||||
| 	} | ||||
| 	/* We don't have a value for this device, so use a sensible default. */ | ||||
| 	return 406; | ||||
| } | ||||
| 
 | ||||
| static int hi_res_scroll_enable(struct hidpp_device *hidpp) | ||||
| { | ||||
| 	int ret; | ||||
| 	u8 multiplier = 8; | ||||
| 
 | ||||
| 	if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) { | ||||
| 		ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false); | ||||
| 		hidpp_hrw_get_wheel_capability(hidpp, &multiplier); | ||||
| 	} else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) { | ||||
| 		ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true, | ||||
| 							   &multiplier); | ||||
| 	} else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */ | ||||
| 		ret = hidpp10_enable_scrolling_acceleration(hidpp); | ||||
| 
 | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	hidpp->vertical_wheel_counter.resolution_multiplier = multiplier; | ||||
| 	hidpp->vertical_wheel_counter.microns_per_hi_res_unit = | ||||
| 		hi_res_scroll_look_up_microns(hidpp->hid_dev->product); | ||||
| 	hid_info(hidpp->hid_dev, "multiplier = %d, microns = %d\n", | ||||
| 		 multiplier, | ||||
| 		 hidpp->vertical_wheel_counter.microns_per_hi_res_unit); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* -------------------------------------------------------------------------- */ | ||||
| /* Generic HID++ devices                                                      */ | ||||
| /* -------------------------------------------------------------------------- */ | ||||
| @ -2763,11 +2572,6 @@ static void hidpp_populate_input(struct hidpp_device *hidpp, | ||||
| 		wtp_populate_input(hidpp, input, origin_is_hid_core); | ||||
| 	else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) | ||||
| 		m560_populate_input(hidpp, input, origin_is_hid_core); | ||||
| 
 | ||||
| 	if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) { | ||||
| 		input_set_capability(input, EV_REL, REL_WHEEL_HI_RES); | ||||
| 		hidpp->vertical_wheel_counter.dev = input; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int hidpp_input_configured(struct hid_device *hdev, | ||||
| @ -2886,27 +2690,6 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int hidpp_event(struct hid_device *hdev, struct hid_field *field, | ||||
| 	struct hid_usage *usage, __s32 value) | ||||
| { | ||||
| 	/* This function will only be called for scroll events, due to the
 | ||||
| 	 * restriction imposed in hidpp_usages. | ||||
| 	 */ | ||||
| 	struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||||
| 	struct hid_scroll_counter *counter = &hidpp->vertical_wheel_counter; | ||||
| 	/* A scroll event may occur before the multiplier has been retrieved or
 | ||||
| 	 * the input device set, or high-res scroll enabling may fail. In such | ||||
| 	 * cases we must return early (falling back to default behaviour) to | ||||
| 	 * avoid a crash in hid_scroll_counter_handle_scroll. | ||||
| 	 */ | ||||
| 	if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0 | ||||
| 	    || counter->dev == NULL || counter->resolution_multiplier == 0) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	hid_scroll_counter_handle_scroll(counter, value); | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static int hidpp_initialize_battery(struct hidpp_device *hidpp) | ||||
| { | ||||
| 	static atomic_t battery_no = ATOMIC_INIT(0); | ||||
| @ -3118,9 +2901,6 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) | ||||
| 	if (hidpp->battery.ps) | ||||
| 		power_supply_changed(hidpp->battery.ps); | ||||
| 
 | ||||
| 	if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) | ||||
| 		hi_res_scroll_enable(hidpp); | ||||
| 
 | ||||
| 	if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input) | ||||
| 		/* if the input nodes are already created, we can stop now */ | ||||
| 		return; | ||||
| @ -3306,63 +3086,35 @@ static void hidpp_remove(struct hid_device *hdev) | ||||
| 	mutex_destroy(&hidpp->send_mutex); | ||||
| } | ||||
| 
 | ||||
| #define LDJ_DEVICE(product) \ | ||||
| 	HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \ | ||||
| 		   USB_VENDOR_ID_LOGITECH, (product)) | ||||
| 
 | ||||
| static const struct hid_device_id hidpp_devices[] = { | ||||
| 	{ /* wireless touchpad */ | ||||
| 	  LDJ_DEVICE(0x4011), | ||||
| 	  HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | ||||
| 		USB_VENDOR_ID_LOGITECH, 0x4011), | ||||
| 	  .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT | | ||||
| 			 HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS }, | ||||
| 	{ /* wireless touchpad T650 */ | ||||
| 	  LDJ_DEVICE(0x4101), | ||||
| 	  HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | ||||
| 		USB_VENDOR_ID_LOGITECH, 0x4101), | ||||
| 	  .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT }, | ||||
| 	{ /* wireless touchpad T651 */ | ||||
| 	  HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, | ||||
| 		USB_DEVICE_ID_LOGITECH_T651), | ||||
| 	  .driver_data = HIDPP_QUIRK_CLASS_WTP }, | ||||
| 	{ /* Mouse Logitech Anywhere MX */ | ||||
| 	  LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, | ||||
| 	{ /* Mouse Logitech Cube */ | ||||
| 	  LDJ_DEVICE(0x4010), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, | ||||
| 	{ /* Mouse Logitech M335 */ | ||||
| 	  LDJ_DEVICE(0x4050), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||||
| 	{ /* Mouse Logitech M515 */ | ||||
| 	  LDJ_DEVICE(0x4007), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, | ||||
| 	{ /* Mouse logitech M560 */ | ||||
| 	  LDJ_DEVICE(0x402d), | ||||
| 	  .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 | ||||
| 		| HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, | ||||
| 	{ /* Mouse Logitech M705 (firmware RQM17) */ | ||||
| 	  LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, | ||||
| 	{ /* Mouse Logitech M705 (firmware RQM67) */ | ||||
| 	  LDJ_DEVICE(0x406d), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||||
| 	{ /* Mouse Logitech M720 */ | ||||
| 	  LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||||
| 	{ /* Mouse Logitech MX Anywhere 2 */ | ||||
| 	  LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||||
| 	{ LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||||
| 	{ LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||||
| 	{ LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||||
| 	{ /* Mouse Logitech MX Anywhere 2S */ | ||||
| 	  LDJ_DEVICE(0x406a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||||
| 	{ /* Mouse Logitech MX Master */ | ||||
| 	  LDJ_DEVICE(0x4041), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||||
| 	{ LDJ_DEVICE(0x4060), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||||
| 	{ LDJ_DEVICE(0x4071), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||||
| 	{ /* Mouse Logitech MX Master 2S */ | ||||
| 	  LDJ_DEVICE(0x4069), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||||
| 	{ /* Mouse Logitech Performance MX */ | ||||
| 	  LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, | ||||
| 	  HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | ||||
| 		USB_VENDOR_ID_LOGITECH, 0x402d), | ||||
| 	  .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 }, | ||||
| 	{ /* Keyboard logitech K400 */ | ||||
| 	  LDJ_DEVICE(0x4024), | ||||
| 	  HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | ||||
| 		USB_VENDOR_ID_LOGITECH, 0x4024), | ||||
| 	  .driver_data = HIDPP_QUIRK_CLASS_K400 }, | ||||
| 	{ /* Solar Keyboard Logitech K750 */ | ||||
| 	  LDJ_DEVICE(0x4002), | ||||
| 	  HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | ||||
| 		USB_VENDOR_ID_LOGITECH, 0x4002), | ||||
| 	  .driver_data = HIDPP_QUIRK_CLASS_K750 }, | ||||
| 
 | ||||
| 	{ LDJ_DEVICE(HID_ANY_ID) }, | ||||
| 	{ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | ||||
| 		USB_VENDOR_ID_LOGITECH, HID_ANY_ID)}, | ||||
| 
 | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL), | ||||
| 		.driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS}, | ||||
| @ -3371,19 +3123,12 @@ static const struct hid_device_id hidpp_devices[] = { | ||||
| 
 | ||||
| MODULE_DEVICE_TABLE(hid, hidpp_devices); | ||||
| 
 | ||||
| static const struct hid_usage_id hidpp_usages[] = { | ||||
| 	{ HID_GD_WHEEL, EV_REL, REL_WHEEL }, | ||||
| 	{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} | ||||
| }; | ||||
| 
 | ||||
| static struct hid_driver hidpp_driver = { | ||||
| 	.name = "logitech-hidpp-device", | ||||
| 	.id_table = hidpp_devices, | ||||
| 	.probe = hidpp_probe, | ||||
| 	.remove = hidpp_remove, | ||||
| 	.raw_event = hidpp_raw_event, | ||||
| 	.usage_table = hidpp_usages, | ||||
| 	.event = hidpp_event, | ||||
| 	.input_configured = hidpp_input_configured, | ||||
| 	.input_mapping = hidpp_input_mapping, | ||||
| 	.input_mapped = hidpp_input_mapped, | ||||
|  | ||||
| @ -1814,6 +1814,12 @@ static const struct hid_device_id mt_devices[] = { | ||||
| 		MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, | ||||
| 			USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, | ||||
| 
 | ||||
| 	/* Cirque devices */ | ||||
| 	{ .driver_data = MT_CLS_WIN_8_DUAL, | ||||
| 		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, | ||||
| 			I2C_VENDOR_ID_CIRQUE, | ||||
| 			I2C_PRODUCT_ID_CIRQUE_121F) }, | ||||
| 
 | ||||
| 	/* CJTouch panels */ | ||||
| 	{ .driver_data = MT_CLS_NSMU, | ||||
| 		MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, | ||||
|  | ||||
| @ -107,6 +107,7 @@ static const struct hid_device_id hid_quirks[] = { | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A), HID_QUIRK_ALWAYS_POLL }, | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A), HID_QUIRK_ALWAYS_POLL }, | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_GAMEPADBLOCK), HID_QUIRK_MULTI_INPUT }, | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PIXART_MOUSE), HID_QUIRK_ALWAYS_POLL }, | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), HID_QUIRK_NO_INIT_REPORTS }, | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2), HID_QUIRK_NO_INIT_REPORTS }, | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), HID_QUIRK_NO_INIT_REPORTS }, | ||||
| @ -129,6 +130,8 @@ static const struct hid_device_id hid_quirks[] = { | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN), HID_QUIRK_NO_INIT_REPORTS }, | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL }, | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22), HID_QUIRK_ALWAYS_POLL }, | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F), HID_QUIRK_ALWAYS_POLL }, | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22), HID_QUIRK_ALWAYS_POLL }, | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS), HID_QUIRK_NOGET }, | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001), HID_QUIRK_NOGET }, | ||||
| 	{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3003), HID_QUIRK_NOGET }, | ||||
|  | ||||
| @ -23,8 +23,9 @@ | ||||
|  * In order to avoid breaking them this driver creates a layered hidraw device, | ||||
|  * so it can detect when the client is running and then: | ||||
|  *  - it will not send any command to the controller. | ||||
|  *  - this input device will be disabled, to avoid double input of the same | ||||
|  *  - this input device will be removed, to avoid double input of the same | ||||
|  *    user action. | ||||
|  * When the client is closed, this input device will be created again. | ||||
|  * | ||||
|  * For additional functions, such as changing the right-pad margin or switching | ||||
|  * the led, you can use the user-space tool at: | ||||
| @ -113,7 +114,7 @@ struct steam_device { | ||||
| 	spinlock_t lock; | ||||
| 	struct hid_device *hdev, *client_hdev; | ||||
| 	struct mutex mutex; | ||||
| 	bool client_opened, input_opened; | ||||
| 	bool client_opened; | ||||
| 	struct input_dev __rcu *input; | ||||
| 	unsigned long quirks; | ||||
| 	struct work_struct work_connect; | ||||
| @ -279,18 +280,6 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void steam_update_lizard_mode(struct steam_device *steam) | ||||
| { | ||||
| 	mutex_lock(&steam->mutex); | ||||
| 	if (!steam->client_opened) { | ||||
| 		if (steam->input_opened) | ||||
| 			steam_set_lizard_mode(steam, false); | ||||
| 		else | ||||
| 			steam_set_lizard_mode(steam, lizard_mode); | ||||
| 	} | ||||
| 	mutex_unlock(&steam->mutex); | ||||
| } | ||||
| 
 | ||||
| static int steam_input_open(struct input_dev *dev) | ||||
| { | ||||
| 	struct steam_device *steam = input_get_drvdata(dev); | ||||
| @ -301,7 +290,6 @@ static int steam_input_open(struct input_dev *dev) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	mutex_lock(&steam->mutex); | ||||
| 	steam->input_opened = true; | ||||
| 	if (!steam->client_opened && lizard_mode) | ||||
| 		steam_set_lizard_mode(steam, false); | ||||
| 	mutex_unlock(&steam->mutex); | ||||
| @ -313,7 +301,6 @@ static void steam_input_close(struct input_dev *dev) | ||||
| 	struct steam_device *steam = input_get_drvdata(dev); | ||||
| 
 | ||||
| 	mutex_lock(&steam->mutex); | ||||
| 	steam->input_opened = false; | ||||
| 	if (!steam->client_opened && lizard_mode) | ||||
| 		steam_set_lizard_mode(steam, true); | ||||
| 	mutex_unlock(&steam->mutex); | ||||
| @ -400,7 +387,7 @@ static int steam_battery_register(struct steam_device *steam) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int steam_register(struct steam_device *steam) | ||||
| static int steam_input_register(struct steam_device *steam) | ||||
| { | ||||
| 	struct hid_device *hdev = steam->hdev; | ||||
| 	struct input_dev *input; | ||||
| @ -414,17 +401,6 @@ static int steam_register(struct steam_device *steam) | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Unlikely, but getting the serial could fail, and it is not so | ||||
| 	 * important, so make up a serial number and go on. | ||||
| 	 */ | ||||
| 	if (steam_get_serial(steam) < 0) | ||||
| 		strlcpy(steam->serial_no, "XXXXXXXXXX", | ||||
| 				sizeof(steam->serial_no)); | ||||
| 
 | ||||
| 	hid_info(hdev, "Steam Controller '%s' connected", | ||||
| 			steam->serial_no); | ||||
| 
 | ||||
| 	input = input_allocate_device(); | ||||
| 	if (!input) | ||||
| 		return -ENOMEM; | ||||
| @ -492,11 +468,6 @@ static int steam_register(struct steam_device *steam) | ||||
| 		goto input_register_fail; | ||||
| 
 | ||||
| 	rcu_assign_pointer(steam->input, input); | ||||
| 
 | ||||
| 	/* ignore battery errors, we can live without it */ | ||||
| 	if (steam->quirks & STEAM_QUIRK_WIRELESS) | ||||
| 		steam_battery_register(steam); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| input_register_fail: | ||||
| @ -504,27 +475,88 @@ input_register_fail: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void steam_unregister(struct steam_device *steam) | ||||
| static void steam_input_unregister(struct steam_device *steam) | ||||
| { | ||||
| 	struct input_dev *input; | ||||
| 	rcu_read_lock(); | ||||
| 	input = rcu_dereference(steam->input); | ||||
| 	rcu_read_unlock(); | ||||
| 	if (!input) | ||||
| 		return; | ||||
| 	RCU_INIT_POINTER(steam->input, NULL); | ||||
| 	synchronize_rcu(); | ||||
| 	input_unregister_device(input); | ||||
| } | ||||
| 
 | ||||
| static void steam_battery_unregister(struct steam_device *steam) | ||||
| { | ||||
| 	struct power_supply *battery; | ||||
| 
 | ||||
| 	rcu_read_lock(); | ||||
| 	input = rcu_dereference(steam->input); | ||||
| 	battery = rcu_dereference(steam->battery); | ||||
| 	rcu_read_unlock(); | ||||
| 
 | ||||
| 	if (battery) { | ||||
| 		RCU_INIT_POINTER(steam->battery, NULL); | ||||
| 		synchronize_rcu(); | ||||
| 		power_supply_unregister(battery); | ||||
| 	if (!battery) | ||||
| 		return; | ||||
| 	RCU_INIT_POINTER(steam->battery, NULL); | ||||
| 	synchronize_rcu(); | ||||
| 	power_supply_unregister(battery); | ||||
| } | ||||
| 
 | ||||
| static int steam_register(struct steam_device *steam) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * This function can be called several times in a row with the | ||||
| 	 * wireless adaptor, without steam_unregister() between them, because | ||||
| 	 * another client send a get_connection_status command, for example. | ||||
| 	 * The battery and serial number are set just once per device. | ||||
| 	 */ | ||||
| 	if (!steam->serial_no[0]) { | ||||
| 		/*
 | ||||
| 		 * Unlikely, but getting the serial could fail, and it is not so | ||||
| 		 * important, so make up a serial number and go on. | ||||
| 		 */ | ||||
| 		if (steam_get_serial(steam) < 0) | ||||
| 			strlcpy(steam->serial_no, "XXXXXXXXXX", | ||||
| 					sizeof(steam->serial_no)); | ||||
| 
 | ||||
| 		hid_info(steam->hdev, "Steam Controller '%s' connected", | ||||
| 				steam->serial_no); | ||||
| 
 | ||||
| 		/* ignore battery errors, we can live without it */ | ||||
| 		if (steam->quirks & STEAM_QUIRK_WIRELESS) | ||||
| 			steam_battery_register(steam); | ||||
| 
 | ||||
| 		mutex_lock(&steam_devices_lock); | ||||
| 		list_add(&steam->list, &steam_devices); | ||||
| 		mutex_unlock(&steam_devices_lock); | ||||
| 	} | ||||
| 	if (input) { | ||||
| 		RCU_INIT_POINTER(steam->input, NULL); | ||||
| 		synchronize_rcu(); | ||||
| 
 | ||||
| 	mutex_lock(&steam->mutex); | ||||
| 	if (!steam->client_opened) { | ||||
| 		steam_set_lizard_mode(steam, lizard_mode); | ||||
| 		ret = steam_input_register(steam); | ||||
| 	} else { | ||||
| 		ret = 0; | ||||
| 	} | ||||
| 	mutex_unlock(&steam->mutex); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void steam_unregister(struct steam_device *steam) | ||||
| { | ||||
| 	steam_battery_unregister(steam); | ||||
| 	steam_input_unregister(steam); | ||||
| 	if (steam->serial_no[0]) { | ||||
| 		hid_info(steam->hdev, "Steam Controller '%s' disconnected", | ||||
| 				steam->serial_no); | ||||
| 		input_unregister_device(input); | ||||
| 		mutex_lock(&steam_devices_lock); | ||||
| 		list_del(&steam->list); | ||||
| 		mutex_unlock(&steam_devices_lock); | ||||
| 		steam->serial_no[0] = 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -600,6 +632,9 @@ static int steam_client_ll_open(struct hid_device *hdev) | ||||
| 	mutex_lock(&steam->mutex); | ||||
| 	steam->client_opened = true; | ||||
| 	mutex_unlock(&steam->mutex); | ||||
| 
 | ||||
| 	steam_input_unregister(steam); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| @ -609,13 +644,13 @@ static void steam_client_ll_close(struct hid_device *hdev) | ||||
| 
 | ||||
| 	mutex_lock(&steam->mutex); | ||||
| 	steam->client_opened = false; | ||||
| 	if (steam->input_opened) | ||||
| 		steam_set_lizard_mode(steam, false); | ||||
| 	else | ||||
| 		steam_set_lizard_mode(steam, lizard_mode); | ||||
| 	mutex_unlock(&steam->mutex); | ||||
| 
 | ||||
| 	hid_hw_close(steam->hdev); | ||||
| 	if (steam->connected) { | ||||
| 		steam_set_lizard_mode(steam, lizard_mode); | ||||
| 		steam_input_register(steam); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int steam_client_ll_raw_request(struct hid_device *hdev, | ||||
| @ -744,11 +779,6 @@ static int steam_probe(struct hid_device *hdev, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	mutex_lock(&steam_devices_lock); | ||||
| 	steam_update_lizard_mode(steam); | ||||
| 	list_add(&steam->list, &steam_devices); | ||||
| 	mutex_unlock(&steam_devices_lock); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| hid_hw_open_fail: | ||||
| @ -774,10 +804,6 @@ static void steam_remove(struct hid_device *hdev) | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	mutex_lock(&steam_devices_lock); | ||||
| 	list_del(&steam->list); | ||||
| 	mutex_unlock(&steam_devices_lock); | ||||
| 
 | ||||
| 	hid_destroy_device(steam->client_hdev); | ||||
| 	steam->client_opened = false; | ||||
| 	cancel_work_sync(&steam->work_connect); | ||||
| @ -792,12 +818,14 @@ static void steam_remove(struct hid_device *hdev) | ||||
| static void steam_do_connect_event(struct steam_device *steam, bool connected) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	bool changed; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&steam->lock, flags); | ||||
| 	changed = steam->connected != connected; | ||||
| 	steam->connected = connected; | ||||
| 	spin_unlock_irqrestore(&steam->lock, flags); | ||||
| 
 | ||||
| 	if (schedule_work(&steam->work_connect) == 0) | ||||
| 	if (changed && schedule_work(&steam->work_connect) == 0) | ||||
| 		dbg_hid("%s: connected=%d event already queued\n", | ||||
| 				__func__, connected); | ||||
| } | ||||
| @ -1019,13 +1047,8 @@ static int steam_raw_event(struct hid_device *hdev, | ||||
| 			return 0; | ||||
| 		rcu_read_lock(); | ||||
| 		input = rcu_dereference(steam->input); | ||||
| 		if (likely(input)) { | ||||
| 		if (likely(input)) | ||||
| 			steam_do_input_event(steam, input, data); | ||||
| 		} else { | ||||
| 			dbg_hid("%s: input data without connect event\n", | ||||
| 					__func__); | ||||
| 			steam_do_connect_event(steam, true); | ||||
| 		} | ||||
| 		rcu_read_unlock(); | ||||
| 		break; | ||||
| 	case STEAM_EV_CONNECT: | ||||
| @ -1074,7 +1097,10 @@ static int steam_param_set_lizard_mode(const char *val, | ||||
| 
 | ||||
| 	mutex_lock(&steam_devices_lock); | ||||
| 	list_for_each_entry(steam, &steam_devices, list) { | ||||
| 		steam_update_lizard_mode(steam); | ||||
| 		mutex_lock(&steam->mutex); | ||||
| 		if (!steam->client_opened) | ||||
| 			steam_set_lizard_mode(steam, lizard_mode); | ||||
| 		mutex_unlock(&steam->mutex); | ||||
| 	} | ||||
| 	mutex_unlock(&steam_devices_lock); | ||||
| 	return 0; | ||||
|  | ||||
| @ -177,6 +177,8 @@ static const struct i2c_hid_quirks { | ||||
| 		I2C_HID_QUIRK_NO_RUNTIME_PM }, | ||||
| 	{ I2C_VENDOR_ID_RAYDIUM, I2C_PRODUCT_ID_RAYDIUM_4B33, | ||||
| 		I2C_HID_QUIRK_DELAY_AFTER_SLEEP }, | ||||
| 	{ USB_VENDOR_ID_LG, I2C_DEVICE_ID_LG_8001, | ||||
| 		I2C_HID_QUIRK_NO_RUNTIME_PM }, | ||||
| 	{ 0, 0 } | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -12,6 +12,7 @@ | ||||
| 
 | ||||
| #include <linux/atomic.h> | ||||
| #include <linux/compat.h> | ||||
| #include <linux/cred.h> | ||||
| #include <linux/device.h> | ||||
| #include <linux/fs.h> | ||||
| #include <linux/hid.h> | ||||
| @ -496,12 +497,13 @@ static int uhid_dev_create2(struct uhid_device *uhid, | ||||
| 		goto err_free; | ||||
| 	} | ||||
| 
 | ||||
| 	len = min(sizeof(hid->name), sizeof(ev->u.create2.name)); | ||||
| 	strlcpy(hid->name, ev->u.create2.name, len); | ||||
| 	len = min(sizeof(hid->phys), sizeof(ev->u.create2.phys)); | ||||
| 	strlcpy(hid->phys, ev->u.create2.phys, len); | ||||
| 	len = min(sizeof(hid->uniq), sizeof(ev->u.create2.uniq)); | ||||
| 	strlcpy(hid->uniq, ev->u.create2.uniq, len); | ||||
| 	/* @hid is zero-initialized, strncpy() is correct, strlcpy() not */ | ||||
| 	len = min(sizeof(hid->name), sizeof(ev->u.create2.name)) - 1; | ||||
| 	strncpy(hid->name, ev->u.create2.name, len); | ||||
| 	len = min(sizeof(hid->phys), sizeof(ev->u.create2.phys)) - 1; | ||||
| 	strncpy(hid->phys, ev->u.create2.phys, len); | ||||
| 	len = min(sizeof(hid->uniq), sizeof(ev->u.create2.uniq)) - 1; | ||||
| 	strncpy(hid->uniq, ev->u.create2.uniq, len); | ||||
| 
 | ||||
| 	hid->ll_driver = &uhid_hid_driver; | ||||
| 	hid->bus = ev->u.create2.bus; | ||||
| @ -722,6 +724,17 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer, | ||||
| 
 | ||||
| 	switch (uhid->input_buf.type) { | ||||
| 	case UHID_CREATE: | ||||
| 		/*
 | ||||
| 		 * 'struct uhid_create_req' contains a __user pointer which is | ||||
| 		 * copied from, so it's unsafe to allow this with elevated | ||||
| 		 * privileges (e.g. from a setuid binary) or via kernel_write(). | ||||
| 		 */ | ||||
| 		if (file->f_cred != current_cred() || uaccess_kernel()) { | ||||
| 			pr_err_once("UHID_CREATE from different security context by process %d (%s), this is not allowed.\n", | ||||
| 				    task_tgid_vnr(current), current->comm); | ||||
| 			ret = -EACCES; | ||||
| 			goto unlock; | ||||
| 		} | ||||
| 		ret = uhid_dev_create(uhid, &uhid->input_buf); | ||||
| 		break; | ||||
| 	case UHID_CREATE2: | ||||
|  | ||||
| @ -353,6 +353,9 @@ static void process_ib_ipinfo(void *in_msg, void *out_msg, int op) | ||||
| 
 | ||||
| 		out->body.kvp_ip_val.dhcp_enabled = in->kvp_ip_val.dhcp_enabled; | ||||
| 
 | ||||
| 		/* fallthrough */ | ||||
| 
 | ||||
| 	case KVP_OP_GET_IP_INFO: | ||||
| 		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.adapter_id, | ||||
| 				MAX_ADAPTER_ID_SIZE, | ||||
| 				UTF16_LITTLE_ENDIAN, | ||||
| @ -405,7 +408,11 @@ kvp_send_key(struct work_struct *dummy) | ||||
| 		process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO); | ||||
| 		break; | ||||
| 	case KVP_OP_GET_IP_INFO: | ||||
| 		/* We only need to pass on message->kvp_hdr.operation.  */ | ||||
| 		/*
 | ||||
| 		 * We only need to pass on the info of operation, adapter_id | ||||
| 		 * and addr_family to the userland kvp daemon. | ||||
| 		 */ | ||||
| 		process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO); | ||||
| 		break; | ||||
| 	case KVP_OP_SET: | ||||
| 		switch (in_msg->body.kvp_set.data.value_type) { | ||||
| @ -446,9 +453,9 @@ kvp_send_key(struct work_struct *dummy) | ||||
| 
 | ||||
| 		} | ||||
| 
 | ||||
| 		break; | ||||
| 
 | ||||
| 	case KVP_OP_GET: | ||||
| 		/*
 | ||||
| 		 * The key is always a string - utf16 encoding. | ||||
| 		 */ | ||||
| 		message->body.kvp_set.data.key_size = | ||||
| 			utf16s_to_utf8s( | ||||
| 			(wchar_t *)in_msg->body.kvp_set.data.key, | ||||
| @ -456,6 +463,17 @@ kvp_send_key(struct work_struct *dummy) | ||||
| 			UTF16_LITTLE_ENDIAN, | ||||
| 			message->body.kvp_set.data.key, | ||||
| 			HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1; | ||||
| 
 | ||||
| 		break; | ||||
| 
 | ||||
| 	case KVP_OP_GET: | ||||
| 		message->body.kvp_get.data.key_size = | ||||
| 			utf16s_to_utf8s( | ||||
| 			(wchar_t *)in_msg->body.kvp_get.data.key, | ||||
| 			in_msg->body.kvp_get.data.key_size, | ||||
| 			UTF16_LITTLE_ENDIAN, | ||||
| 			message->body.kvp_get.data.key, | ||||
| 			HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1; | ||||
| 		break; | ||||
| 
 | ||||
| 	case KVP_OP_DELETE: | ||||
|  | ||||
| @ -797,7 +797,8 @@ static int iommu_init_ga_log(struct amd_iommu *iommu) | ||||
| 	entry = iommu_virt_to_phys(iommu->ga_log) | GA_LOG_SIZE_512; | ||||
| 	memcpy_toio(iommu->mmio_base + MMIO_GA_LOG_BASE_OFFSET, | ||||
| 		    &entry, sizeof(entry)); | ||||
| 	entry = (iommu_virt_to_phys(iommu->ga_log) & 0xFFFFFFFFFFFFFULL) & ~7ULL; | ||||
| 	entry = (iommu_virt_to_phys(iommu->ga_log_tail) & | ||||
| 		 (BIT_ULL(52)-1)) & ~7ULL; | ||||
| 	memcpy_toio(iommu->mmio_base + MMIO_GA_LOG_TAIL_OFFSET, | ||||
| 		    &entry, sizeof(entry)); | ||||
| 	writel(0x00, iommu->mmio_base + MMIO_GA_HEAD_OFFSET); | ||||
|  | ||||
| @ -3075,7 +3075,7 @@ static int copy_context_table(struct intel_iommu *iommu, | ||||
| 			} | ||||
| 
 | ||||
| 			if (old_ce) | ||||
| 				iounmap(old_ce); | ||||
| 				memunmap(old_ce); | ||||
| 
 | ||||
| 			ret = 0; | ||||
| 			if (devfn < 0x80) | ||||
|  | ||||
| @ -595,7 +595,7 @@ static irqreturn_t prq_event_thread(int irq, void *d) | ||||
| 			pr_err("%s: Page request without PASID: %08llx %08llx\n", | ||||
| 			       iommu->name, ((unsigned long long *)req)[0], | ||||
| 			       ((unsigned long long *)req)[1]); | ||||
| 			goto bad_req; | ||||
| 			goto no_pasid; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!svm || svm->pasid != req->pasid) { | ||||
|  | ||||
| @ -498,6 +498,9 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) | ||||
| 
 | ||||
| static void ipmmu_domain_destroy_context(struct ipmmu_vmsa_domain *domain) | ||||
| { | ||||
| 	if (!domain->mmu) | ||||
| 		return; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Disable the context. Flush the TLB as required when modifying the | ||||
| 	 * context registers. | ||||
|  | ||||
| @ -807,7 +807,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, | ||||
| 	} | ||||
| 
 | ||||
| 	if (adap->transmit_queue_sz >= CEC_MAX_MSG_TX_QUEUE_SZ) { | ||||
| 		dprintk(1, "%s: transmit queue full\n", __func__); | ||||
| 		dprintk(2, "%s: transmit queue full\n", __func__); | ||||
| 		return -EBUSY; | ||||
| 	} | ||||
| 
 | ||||
| @ -1180,6 +1180,8 @@ static int cec_config_log_addr(struct cec_adapter *adap, | ||||
| { | ||||
| 	struct cec_log_addrs *las = &adap->log_addrs; | ||||
| 	struct cec_msg msg = { }; | ||||
| 	const unsigned int max_retries = 2; | ||||
| 	unsigned int i; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (cec_has_log_addr(adap, log_addr)) | ||||
| @ -1188,19 +1190,44 @@ static int cec_config_log_addr(struct cec_adapter *adap, | ||||
| 	/* Send poll message */ | ||||
| 	msg.len = 1; | ||||
| 	msg.msg[0] = (log_addr << 4) | log_addr; | ||||
| 	err = cec_transmit_msg_fh(adap, &msg, NULL, true); | ||||
| 
 | ||||
| 	for (i = 0; i < max_retries; i++) { | ||||
| 		err = cec_transmit_msg_fh(adap, &msg, NULL, true); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * While trying to poll the physical address was reset | ||||
| 		 * and the adapter was unconfigured, so bail out. | ||||
| 		 */ | ||||
| 		if (!adap->is_configuring) | ||||
| 			return -EINTR; | ||||
| 
 | ||||
| 		if (err) | ||||
| 			return err; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * The message was aborted due to a disconnect or | ||||
| 		 * unconfigure, just bail out. | ||||
| 		 */ | ||||
| 		if (msg.tx_status & CEC_TX_STATUS_ABORTED) | ||||
| 			return -EINTR; | ||||
| 		if (msg.tx_status & CEC_TX_STATUS_OK) | ||||
| 			return 0; | ||||
| 		if (msg.tx_status & CEC_TX_STATUS_NACK) | ||||
| 			break; | ||||
| 		/*
 | ||||
| 		 * Retry up to max_retries times if the message was neither | ||||
| 		 * OKed or NACKed. This can happen due to e.g. a Lost | ||||
| 		 * Arbitration condition. | ||||
| 		 */ | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * While trying to poll the physical address was reset | ||||
| 	 * and the adapter was unconfigured, so bail out. | ||||
| 	 * If we are unable to get an OK or a NACK after max_retries attempts | ||||
| 	 * (and note that each attempt already consists of four polls), then | ||||
| 	 * then we assume that something is really weird and that it is not a | ||||
| 	 * good idea to try and claim this logical address. | ||||
| 	 */ | ||||
| 	if (!adap->is_configuring) | ||||
| 		return -EINTR; | ||||
| 
 | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	if (msg.tx_status & CEC_TX_STATUS_OK) | ||||
| 	if (i == max_retries) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/*
 | ||||
|  | ||||
| @ -1918,7 +1918,6 @@ static int tc358743_probe_of(struct tc358743_state *state) | ||||
| 	ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep), &endpoint); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "failed to parse endpoint\n"); | ||||
| 		ret = ret; | ||||
| 		goto put_node; | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -1844,14 +1844,12 @@ fail_mutex_destroy: | ||||
| static void cio2_pci_remove(struct pci_dev *pci_dev) | ||||
| { | ||||
| 	struct cio2_device *cio2 = pci_get_drvdata(pci_dev); | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| 	cio2_notifier_exit(cio2); | ||||
| 	cio2_fbpt_exit_dummy(cio2); | ||||
| 	for (i = 0; i < CIO2_QUEUES; i++) | ||||
| 		cio2_queue_exit(cio2, &cio2->queue[i]); | ||||
| 	v4l2_device_unregister(&cio2->v4l2_dev); | ||||
| 	media_device_unregister(&cio2->media_dev); | ||||
| 	cio2_notifier_exit(cio2); | ||||
| 	cio2_queues_exit(cio2); | ||||
| 	cio2_fbpt_exit_dummy(cio2); | ||||
| 	v4l2_device_unregister(&cio2->v4l2_dev); | ||||
| 	media_device_cleanup(&cio2->media_dev); | ||||
| 	mutex_destroy(&cio2->lock); | ||||
| } | ||||
|  | ||||
| @ -1587,6 +1587,8 @@ static void isp_pm_complete(struct device *dev) | ||||
| 
 | ||||
| static void isp_unregister_entities(struct isp_device *isp) | ||||
| { | ||||
| 	media_device_unregister(&isp->media_dev); | ||||
| 
 | ||||
| 	omap3isp_csi2_unregister_entities(&isp->isp_csi2a); | ||||
| 	omap3isp_ccp2_unregister_entities(&isp->isp_ccp2); | ||||
| 	omap3isp_ccdc_unregister_entities(&isp->isp_ccdc); | ||||
| @ -1597,7 +1599,6 @@ static void isp_unregister_entities(struct isp_device *isp) | ||||
| 	omap3isp_stat_unregister_entities(&isp->isp_hist); | ||||
| 
 | ||||
| 	v4l2_device_unregister(&isp->v4l2_dev); | ||||
| 	media_device_unregister(&isp->media_dev); | ||||
| 	media_device_cleanup(&isp->media_dev); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -42,7 +42,7 @@ MODULE_PARM_DESC(debug, " activates debug info"); | ||||
| #define MAX_WIDTH		4096U | ||||
| #define MIN_WIDTH		640U | ||||
| #define MAX_HEIGHT		2160U | ||||
| #define MIN_HEIGHT		480U | ||||
| #define MIN_HEIGHT		360U | ||||
| 
 | ||||
| #define dprintk(dev, fmt, arg...) \ | ||||
| 	v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) | ||||
|  | ||||
| @ -1009,7 +1009,7 @@ static const struct v4l2_m2m_ops m2m_ops = { | ||||
| 
 | ||||
| static const struct media_device_ops m2m_media_ops = { | ||||
| 	.req_validate = vb2_request_validate, | ||||
| 	.req_queue = vb2_m2m_request_queue, | ||||
| 	.req_queue = v4l2_m2m_request_queue, | ||||
| }; | ||||
| 
 | ||||
| static int vim2m_probe(struct platform_device *pdev) | ||||
|  | ||||
| @ -1664,6 +1664,11 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, | ||||
| 		    p_mpeg2_slice_params->forward_ref_index >= VIDEO_MAX_FRAME) | ||||
| 			return -EINVAL; | ||||
| 
 | ||||
| 		if (p_mpeg2_slice_params->pad || | ||||
| 		    p_mpeg2_slice_params->picture.pad || | ||||
| 		    p_mpeg2_slice_params->sequence.pad) | ||||
| 			return -EINVAL; | ||||
| 
 | ||||
| 		return 0; | ||||
| 
 | ||||
| 	case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION: | ||||
|  | ||||
| @ -193,6 +193,22 @@ int v4l2_event_pending(struct v4l2_fh *fh) | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(v4l2_event_pending); | ||||
| 
 | ||||
| static void __v4l2_event_unsubscribe(struct v4l2_subscribed_event *sev) | ||||
| { | ||||
| 	struct v4l2_fh *fh = sev->fh; | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| 	lockdep_assert_held(&fh->subscribe_lock); | ||||
| 	assert_spin_locked(&fh->vdev->fh_lock); | ||||
| 
 | ||||
| 	/* Remove any pending events for this subscription */ | ||||
| 	for (i = 0; i < sev->in_use; i++) { | ||||
| 		list_del(&sev->events[sev_pos(sev, i)].list); | ||||
| 		fh->navailable--; | ||||
| 	} | ||||
| 	list_del(&sev->list); | ||||
| } | ||||
| 
 | ||||
| int v4l2_event_subscribe(struct v4l2_fh *fh, | ||||
| 			 const struct v4l2_event_subscription *sub, unsigned elems, | ||||
| 			 const struct v4l2_subscribed_event_ops *ops) | ||||
| @ -224,27 +240,23 @@ int v4l2_event_subscribe(struct v4l2_fh *fh, | ||||
| 
 | ||||
| 	spin_lock_irqsave(&fh->vdev->fh_lock, flags); | ||||
| 	found_ev = v4l2_event_subscribed(fh, sub->type, sub->id); | ||||
| 	if (!found_ev) | ||||
| 		list_add(&sev->list, &fh->subscribed); | ||||
| 	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); | ||||
| 
 | ||||
| 	if (found_ev) { | ||||
| 		/* Already listening */ | ||||
| 		kvfree(sev); | ||||
| 		goto out_unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	if (sev->ops && sev->ops->add) { | ||||
| 	} else if (sev->ops && sev->ops->add) { | ||||
| 		ret = sev->ops->add(sev, elems); | ||||
| 		if (ret) { | ||||
| 			spin_lock_irqsave(&fh->vdev->fh_lock, flags); | ||||
| 			__v4l2_event_unsubscribe(sev); | ||||
| 			spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); | ||||
| 			kvfree(sev); | ||||
| 			goto out_unlock; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	spin_lock_irqsave(&fh->vdev->fh_lock, flags); | ||||
| 	list_add(&sev->list, &fh->subscribed); | ||||
| 	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); | ||||
| 
 | ||||
| out_unlock: | ||||
| 	mutex_unlock(&fh->subscribe_lock); | ||||
| 
 | ||||
| 	return ret; | ||||
| @ -279,7 +291,6 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh, | ||||
| { | ||||
| 	struct v4l2_subscribed_event *sev; | ||||
| 	unsigned long flags; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (sub->type == V4L2_EVENT_ALL) { | ||||
| 		v4l2_event_unsubscribe_all(fh); | ||||
| @ -291,14 +302,8 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh, | ||||
| 	spin_lock_irqsave(&fh->vdev->fh_lock, flags); | ||||
| 
 | ||||
| 	sev = v4l2_event_subscribed(fh, sub->type, sub->id); | ||||
| 	if (sev != NULL) { | ||||
| 		/* Remove any pending events for this subscription */ | ||||
| 		for (i = 0; i < sev->in_use; i++) { | ||||
| 			list_del(&sev->events[sev_pos(sev, i)].list); | ||||
| 			fh->navailable--; | ||||
| 		} | ||||
| 		list_del(&sev->list); | ||||
| 	} | ||||
| 	if (sev != NULL) | ||||
| 		__v4l2_event_unsubscribe(sev); | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); | ||||
| 
 | ||||
|  | ||||
| @ -953,7 +953,7 @@ void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue); | ||||
| 
 | ||||
| void vb2_m2m_request_queue(struct media_request *req) | ||||
| void v4l2_m2m_request_queue(struct media_request *req) | ||||
| { | ||||
| 	struct media_request_object *obj, *obj_safe; | ||||
| 	struct v4l2_m2m_ctx *m2m_ctx = NULL; | ||||
| @ -997,7 +997,7 @@ void vb2_m2m_request_queue(struct media_request *req) | ||||
| 	if (m2m_ctx) | ||||
| 		v4l2_m2m_try_schedule(m2m_ctx); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(vb2_m2m_request_queue); | ||||
| EXPORT_SYMBOL_GPL(v4l2_m2m_request_queue); | ||||
| 
 | ||||
| /* Videobuf2 ioctl helpers */ | ||||
| 
 | ||||
|  | ||||
| @ -132,7 +132,7 @@ static const struct of_device_id atmel_ssc_dt_ids[] = { | ||||
| MODULE_DEVICE_TABLE(of, atmel_ssc_dt_ids); | ||||
| #endif | ||||
| 
 | ||||
| static inline const struct atmel_ssc_platform_data * __init | ||||
| static inline const struct atmel_ssc_platform_data * | ||||
| 	atmel_ssc_get_driver_data(struct platform_device *pdev) | ||||
| { | ||||
| 	if (pdev->dev.of_node) { | ||||
|  | ||||
| @ -27,6 +27,9 @@ | ||||
| #include <linux/delay.h> | ||||
| #include <linux/bitops.h> | ||||
| #include <asm/uv/uv_hub.h> | ||||
| 
 | ||||
| #include <linux/nospec.h> | ||||
| 
 | ||||
| #include "gru.h" | ||||
| #include "grutables.h" | ||||
| #include "gruhandles.h" | ||||
| @ -196,6 +199,7 @@ int gru_dump_chiplet_request(unsigned long arg) | ||||
| 	/* Currently, only dump by gid is implemented */ | ||||
| 	if (req.gid >= gru_max_gids) | ||||
| 		return -EINVAL; | ||||
| 	req.gid = array_index_nospec(req.gid, gru_max_gids); | ||||
| 
 | ||||
| 	gru = GID_TO_GRU(req.gid); | ||||
| 	ubuf = req.buf; | ||||
|  | ||||
| @ -12,6 +12,7 @@ | ||||
|  *     - JMicron (hardware and technical support) | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/bitfield.h> | ||||
| #include <linux/string.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/highmem.h> | ||||
| @ -462,6 +463,9 @@ struct intel_host { | ||||
| 	u32	dsm_fns; | ||||
| 	int	drv_strength; | ||||
| 	bool	d3_retune; | ||||
| 	bool	rpm_retune_ok; | ||||
| 	u32	glk_rx_ctrl1; | ||||
| 	u32	glk_tun_val; | ||||
| }; | ||||
| 
 | ||||
| static const guid_t intel_dsm_guid = | ||||
| @ -791,6 +795,77 @@ cleanup: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_PM | ||||
| #define GLK_RX_CTRL1	0x834 | ||||
| #define GLK_TUN_VAL	0x840 | ||||
| #define GLK_PATH_PLL	GENMASK(13, 8) | ||||
| #define GLK_DLY		GENMASK(6, 0) | ||||
| /* Workaround firmware failing to restore the tuning value */ | ||||
| static void glk_rpm_retune_wa(struct sdhci_pci_chip *chip, bool susp) | ||||
| { | ||||
| 	struct sdhci_pci_slot *slot = chip->slots[0]; | ||||
| 	struct intel_host *intel_host = sdhci_pci_priv(slot); | ||||
| 	struct sdhci_host *host = slot->host; | ||||
| 	u32 glk_rx_ctrl1; | ||||
| 	u32 glk_tun_val; | ||||
| 	u32 dly; | ||||
| 
 | ||||
| 	if (intel_host->rpm_retune_ok || !mmc_can_retune(host->mmc)) | ||||
| 		return; | ||||
| 
 | ||||
| 	glk_rx_ctrl1 = sdhci_readl(host, GLK_RX_CTRL1); | ||||
| 	glk_tun_val = sdhci_readl(host, GLK_TUN_VAL); | ||||
| 
 | ||||
| 	if (susp) { | ||||
| 		intel_host->glk_rx_ctrl1 = glk_rx_ctrl1; | ||||
| 		intel_host->glk_tun_val = glk_tun_val; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!intel_host->glk_tun_val) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (glk_rx_ctrl1 != intel_host->glk_rx_ctrl1) { | ||||
| 		intel_host->rpm_retune_ok = true; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	dly = FIELD_PREP(GLK_DLY, FIELD_GET(GLK_PATH_PLL, glk_rx_ctrl1) + | ||||
| 				  (intel_host->glk_tun_val << 1)); | ||||
| 	if (dly == FIELD_GET(GLK_DLY, glk_rx_ctrl1)) | ||||
| 		return; | ||||
| 
 | ||||
| 	glk_rx_ctrl1 = (glk_rx_ctrl1 & ~GLK_DLY) | dly; | ||||
| 	sdhci_writel(host, glk_rx_ctrl1, GLK_RX_CTRL1); | ||||
| 
 | ||||
| 	intel_host->rpm_retune_ok = true; | ||||
| 	chip->rpm_retune = true; | ||||
| 	mmc_retune_needed(host->mmc); | ||||
| 	pr_info("%s: Requiring re-tune after rpm resume", mmc_hostname(host->mmc)); | ||||
| } | ||||
| 
 | ||||
| static void glk_rpm_retune_chk(struct sdhci_pci_chip *chip, bool susp) | ||||
| { | ||||
| 	if (chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC && | ||||
| 	    !chip->rpm_retune) | ||||
| 		glk_rpm_retune_wa(chip, susp); | ||||
| } | ||||
| 
 | ||||
| static int glk_runtime_suspend(struct sdhci_pci_chip *chip) | ||||
| { | ||||
| 	glk_rpm_retune_chk(chip, true); | ||||
| 
 | ||||
| 	return sdhci_cqhci_runtime_suspend(chip); | ||||
| } | ||||
| 
 | ||||
| static int glk_runtime_resume(struct sdhci_pci_chip *chip) | ||||
| { | ||||
| 	glk_rpm_retune_chk(chip, false); | ||||
| 
 | ||||
| 	return sdhci_cqhci_runtime_resume(chip); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_ACPI | ||||
| static int ni_set_max_freq(struct sdhci_pci_slot *slot) | ||||
| { | ||||
| @ -879,8 +954,8 @@ static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = { | ||||
| 	.resume			= sdhci_cqhci_resume, | ||||
| #endif | ||||
| #ifdef CONFIG_PM | ||||
| 	.runtime_suspend	= sdhci_cqhci_runtime_suspend, | ||||
| 	.runtime_resume		= sdhci_cqhci_runtime_resume, | ||||
| 	.runtime_suspend	= glk_runtime_suspend, | ||||
| 	.runtime_resume		= glk_runtime_resume, | ||||
| #endif | ||||
| 	.quirks			= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, | ||||
| 	.quirks2		= SDHCI_QUIRK2_PRESET_VALUE_BROKEN | | ||||
| @ -1762,8 +1837,13 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( | ||||
| 		device_init_wakeup(&pdev->dev, true); | ||||
| 
 | ||||
| 	if (slot->cd_idx >= 0) { | ||||
| 		ret = mmc_gpiod_request_cd(host->mmc, NULL, slot->cd_idx, | ||||
| 		ret = mmc_gpiod_request_cd(host->mmc, "cd", slot->cd_idx, | ||||
| 					   slot->cd_override_level, 0, NULL); | ||||
| 		if (ret && ret != -EPROBE_DEFER) | ||||
| 			ret = mmc_gpiod_request_cd(host->mmc, NULL, | ||||
| 						   slot->cd_idx, | ||||
| 						   slot->cd_override_level, | ||||
| 						   0, NULL); | ||||
| 		if (ret == -EPROBE_DEFER) | ||||
| 			goto remove; | ||||
| 
 | ||||
|  | ||||
| @ -2032,8 +2032,7 @@ atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc) | ||||
| 	int ret; | ||||
| 
 | ||||
| 	nand_np = dev->of_node; | ||||
| 	nfc_np = of_find_compatible_node(dev->of_node, NULL, | ||||
| 					 "atmel,sama5d3-nfc"); | ||||
| 	nfc_np = of_get_compatible_child(dev->of_node, "atmel,sama5d3-nfc"); | ||||
| 	if (!nfc_np) { | ||||
| 		dev_err(dev, "Could not find device node for sama5d3-nfc\n"); | ||||
| 		return -ENODEV; | ||||
| @ -2447,15 +2446,19 @@ static int atmel_nand_controller_probe(struct platform_device *pdev) | ||||
| 	} | ||||
| 
 | ||||
| 	if (caps->legacy_of_bindings) { | ||||
| 		struct device_node *nfc_node; | ||||
| 		u32 ale_offs = 21; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * If we are parsing legacy DT props and the DT contains a | ||||
| 		 * valid NFC node, forward the request to the sama5 logic. | ||||
| 		 */ | ||||
| 		if (of_find_compatible_node(pdev->dev.of_node, NULL, | ||||
| 					    "atmel,sama5d3-nfc")) | ||||
| 		nfc_node = of_get_compatible_child(pdev->dev.of_node, | ||||
| 						   "atmel,sama5d3-nfc"); | ||||
| 		if (nfc_node) { | ||||
| 			caps = &atmel_sama5_nand_caps; | ||||
| 			of_node_put(nfc_node); | ||||
| 		} | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Even if the compatible says we are dealing with an | ||||
|  | ||||
| @ -150,15 +150,15 @@ | ||||
| #define	NAND_VERSION_MINOR_SHIFT	16 | ||||
| 
 | ||||
| /* NAND OP_CMDs */ | ||||
| #define	PAGE_READ			0x2 | ||||
| #define	PAGE_READ_WITH_ECC		0x3 | ||||
| #define	PAGE_READ_WITH_ECC_SPARE	0x4 | ||||
| #define	PROGRAM_PAGE			0x6 | ||||
| #define	PAGE_PROGRAM_WITH_ECC		0x7 | ||||
| #define	PROGRAM_PAGE_SPARE		0x9 | ||||
| #define	BLOCK_ERASE			0xa | ||||
| #define	FETCH_ID			0xb | ||||
| #define	RESET_DEVICE			0xd | ||||
| #define	OP_PAGE_READ			0x2 | ||||
| #define	OP_PAGE_READ_WITH_ECC		0x3 | ||||
| #define	OP_PAGE_READ_WITH_ECC_SPARE	0x4 | ||||
| #define	OP_PROGRAM_PAGE			0x6 | ||||
| #define	OP_PAGE_PROGRAM_WITH_ECC	0x7 | ||||
| #define	OP_PROGRAM_PAGE_SPARE		0x9 | ||||
| #define	OP_BLOCK_ERASE			0xa | ||||
| #define	OP_FETCH_ID			0xb | ||||
| #define	OP_RESET_DEVICE			0xd | ||||
| 
 | ||||
| /* Default Value for NAND_DEV_CMD_VLD */ | ||||
| #define NAND_DEV_CMD_VLD_VAL		(READ_START_VLD | WRITE_START_VLD | \ | ||||
| @ -692,11 +692,11 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read) | ||||
| 
 | ||||
| 	if (read) { | ||||
| 		if (host->use_ecc) | ||||
| 			cmd = PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE; | ||||
| 			cmd = OP_PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE; | ||||
| 		else | ||||
| 			cmd = PAGE_READ | PAGE_ACC | LAST_PAGE; | ||||
| 			cmd = OP_PAGE_READ | PAGE_ACC | LAST_PAGE; | ||||
| 	} else { | ||||
| 			cmd = PROGRAM_PAGE | PAGE_ACC | LAST_PAGE; | ||||
| 		cmd = OP_PROGRAM_PAGE | PAGE_ACC | LAST_PAGE; | ||||
| 	} | ||||
| 
 | ||||
| 	if (host->use_ecc) { | ||||
| @ -1170,7 +1170,7 @@ static int nandc_param(struct qcom_nand_host *host) | ||||
| 	 * in use. we configure the controller to perform a raw read of 512 | ||||
| 	 * bytes to read onfi params | ||||
| 	 */ | ||||
| 	nandc_set_reg(nandc, NAND_FLASH_CMD, PAGE_READ | PAGE_ACC | LAST_PAGE); | ||||
| 	nandc_set_reg(nandc, NAND_FLASH_CMD, OP_PAGE_READ | PAGE_ACC | LAST_PAGE); | ||||
| 	nandc_set_reg(nandc, NAND_ADDR0, 0); | ||||
| 	nandc_set_reg(nandc, NAND_ADDR1, 0); | ||||
| 	nandc_set_reg(nandc, NAND_DEV0_CFG0, 0 << CW_PER_PAGE | ||||
| @ -1224,7 +1224,7 @@ static int erase_block(struct qcom_nand_host *host, int page_addr) | ||||
| 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); | ||||
| 
 | ||||
| 	nandc_set_reg(nandc, NAND_FLASH_CMD, | ||||
| 		      BLOCK_ERASE | PAGE_ACC | LAST_PAGE); | ||||
| 		      OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE); | ||||
| 	nandc_set_reg(nandc, NAND_ADDR0, page_addr); | ||||
| 	nandc_set_reg(nandc, NAND_ADDR1, 0); | ||||
| 	nandc_set_reg(nandc, NAND_DEV0_CFG0, | ||||
| @ -1255,7 +1255,7 @@ static int read_id(struct qcom_nand_host *host, int column) | ||||
| 	if (column == -1) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	nandc_set_reg(nandc, NAND_FLASH_CMD, FETCH_ID); | ||||
| 	nandc_set_reg(nandc, NAND_FLASH_CMD, OP_FETCH_ID); | ||||
| 	nandc_set_reg(nandc, NAND_ADDR0, column); | ||||
| 	nandc_set_reg(nandc, NAND_ADDR1, 0); | ||||
| 	nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT, | ||||
| @ -1276,7 +1276,7 @@ static int reset(struct qcom_nand_host *host) | ||||
| 	struct nand_chip *chip = &host->chip; | ||||
| 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); | ||||
| 
 | ||||
| 	nandc_set_reg(nandc, NAND_FLASH_CMD, RESET_DEVICE); | ||||
| 	nandc_set_reg(nandc, NAND_FLASH_CMD, OP_RESET_DEVICE); | ||||
| 	nandc_set_reg(nandc, NAND_EXEC_CMD, 1); | ||||
| 
 | ||||
| 	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); | ||||
|  | ||||
| @ -644,9 +644,23 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor, loff_t to_addr, | ||||
| 		ndelay(cqspi->wr_delay); | ||||
| 
 | ||||
| 	while (remaining > 0) { | ||||
| 		size_t write_words, mod_bytes; | ||||
| 
 | ||||
| 		write_bytes = remaining > page_size ? page_size : remaining; | ||||
| 		iowrite32_rep(cqspi->ahb_base, txbuf, | ||||
| 			      DIV_ROUND_UP(write_bytes, 4)); | ||||
| 		write_words = write_bytes / 4; | ||||
| 		mod_bytes = write_bytes % 4; | ||||
| 		/* Write 4 bytes at a time then single bytes. */ | ||||
| 		if (write_words) { | ||||
| 			iowrite32_rep(cqspi->ahb_base, txbuf, write_words); | ||||
| 			txbuf += (write_words * 4); | ||||
| 		} | ||||
| 		if (mod_bytes) { | ||||
| 			unsigned int temp = 0xFFFFFFFF; | ||||
| 
 | ||||
| 			memcpy(&temp, txbuf, mod_bytes); | ||||
| 			iowrite32(temp, cqspi->ahb_base); | ||||
| 			txbuf += mod_bytes; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!wait_for_completion_timeout(&cqspi->transfer_complete, | ||||
| 					msecs_to_jiffies(CQSPI_TIMEOUT_MS))) { | ||||
| @ -655,7 +669,6 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor, loff_t to_addr, | ||||
| 			goto failwr; | ||||
| 		} | ||||
| 
 | ||||
| 		txbuf += write_bytes; | ||||
| 		remaining -= write_bytes; | ||||
| 
 | ||||
| 		if (remaining > 0) | ||||
|  | ||||
| @ -2156,7 +2156,7 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, | ||||
|  * @nor:	pointer to a 'struct spi_nor' | ||||
|  * @addr:	offset in the serial flash memory | ||||
|  * @len:	number of bytes to read | ||||
|  * @buf:	buffer where the data is copied into | ||||
|  * @buf:	buffer where the data is copied into (dma-safe memory) | ||||
|  * | ||||
|  * Return: 0 on success, -errno otherwise. | ||||
|  */ | ||||
| @ -2521,6 +2521,34 @@ static int spi_nor_map_cmp_erase_type(const void *l, const void *r) | ||||
| 	return left->size - right->size; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * spi_nor_sort_erase_mask() - sort erase mask | ||||
|  * @map:	the erase map of the SPI NOR | ||||
|  * @erase_mask:	the erase type mask to be sorted | ||||
|  * | ||||
|  * Replicate the sort done for the map's erase types in BFPT: sort the erase | ||||
|  * mask in ascending order with the smallest erase type size starting from | ||||
|  * BIT(0) in the sorted erase mask. | ||||
|  * | ||||
|  * Return: sorted erase mask. | ||||
|  */ | ||||
| static u8 spi_nor_sort_erase_mask(struct spi_nor_erase_map *map, u8 erase_mask) | ||||
| { | ||||
| 	struct spi_nor_erase_type *erase_type = map->erase_type; | ||||
| 	int i; | ||||
| 	u8 sorted_erase_mask = 0; | ||||
| 
 | ||||
| 	if (!erase_mask) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/* Replicate the sort done for the map's erase types. */ | ||||
| 	for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) | ||||
| 		if (erase_type[i].size && erase_mask & BIT(erase_type[i].idx)) | ||||
| 			sorted_erase_mask |= BIT(i); | ||||
| 
 | ||||
| 	return sorted_erase_mask; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * spi_nor_regions_sort_erase_types() - sort erase types in each region | ||||
|  * @map:	the erase map of the SPI NOR | ||||
| @ -2536,19 +2564,13 @@ static int spi_nor_map_cmp_erase_type(const void *l, const void *r) | ||||
| static void spi_nor_regions_sort_erase_types(struct spi_nor_erase_map *map) | ||||
| { | ||||
| 	struct spi_nor_erase_region *region = map->regions; | ||||
| 	struct spi_nor_erase_type *erase_type = map->erase_type; | ||||
| 	int i; | ||||
| 	u8 region_erase_mask, sorted_erase_mask; | ||||
| 
 | ||||
| 	while (region) { | ||||
| 		region_erase_mask = region->offset & SNOR_ERASE_TYPE_MASK; | ||||
| 
 | ||||
| 		/* Replicate the sort done for the map's erase types. */ | ||||
| 		sorted_erase_mask = 0; | ||||
| 		for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) | ||||
| 			if (erase_type[i].size && | ||||
| 			    region_erase_mask & BIT(erase_type[i].idx)) | ||||
| 				sorted_erase_mask |= BIT(i); | ||||
| 		sorted_erase_mask = spi_nor_sort_erase_mask(map, | ||||
| 							    region_erase_mask); | ||||
| 
 | ||||
| 		/* Overwrite erase mask. */ | ||||
| 		region->offset = (region->offset & ~SNOR_ERASE_TYPE_MASK) | | ||||
| @ -2855,52 +2877,84 @@ static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings) | ||||
|  * spi_nor_get_map_in_use() - get the configuration map in use | ||||
|  * @nor:	pointer to a 'struct spi_nor' | ||||
|  * @smpt:	pointer to the sector map parameter table | ||||
|  * @smpt_len:	sector map parameter table length | ||||
|  * | ||||
|  * Return: pointer to the map in use, ERR_PTR(-errno) otherwise. | ||||
|  */ | ||||
| static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt) | ||||
| static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt, | ||||
| 					 u8 smpt_len) | ||||
| { | ||||
| 	const u32 *ret = NULL; | ||||
| 	u32 i, addr; | ||||
| 	const u32 *ret; | ||||
| 	u8 *buf; | ||||
| 	u32 addr; | ||||
| 	int err; | ||||
| 	u8 i; | ||||
| 	u8 addr_width, read_opcode, read_dummy; | ||||
| 	u8 read_data_mask, data_byte, map_id; | ||||
| 	u8 read_data_mask, map_id; | ||||
| 
 | ||||
| 	/* Use a kmalloc'ed bounce buffer to guarantee it is DMA-able. */ | ||||
| 	buf = kmalloc(sizeof(*buf), GFP_KERNEL); | ||||
| 	if (!buf) | ||||
| 		return ERR_PTR(-ENOMEM); | ||||
| 
 | ||||
| 	addr_width = nor->addr_width; | ||||
| 	read_dummy = nor->read_dummy; | ||||
| 	read_opcode = nor->read_opcode; | ||||
| 
 | ||||
| 	map_id = 0; | ||||
| 	i = 0; | ||||
| 	/* Determine if there are any optional Detection Command Descriptors */ | ||||
| 	while (!(smpt[i] & SMPT_DESC_TYPE_MAP)) { | ||||
| 	for (i = 0; i < smpt_len; i += 2) { | ||||
| 		if (smpt[i] & SMPT_DESC_TYPE_MAP) | ||||
| 			break; | ||||
| 
 | ||||
| 		read_data_mask = SMPT_CMD_READ_DATA(smpt[i]); | ||||
| 		nor->addr_width = spi_nor_smpt_addr_width(nor, smpt[i]); | ||||
| 		nor->read_dummy = spi_nor_smpt_read_dummy(nor, smpt[i]); | ||||
| 		nor->read_opcode = SMPT_CMD_OPCODE(smpt[i]); | ||||
| 		addr = smpt[i + 1]; | ||||
| 
 | ||||
| 		err = spi_nor_read_raw(nor, addr, 1, &data_byte); | ||||
| 		if (err) | ||||
| 		err = spi_nor_read_raw(nor, addr, 1, buf); | ||||
| 		if (err) { | ||||
| 			ret = ERR_PTR(err); | ||||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Build an index value that is used to select the Sector Map | ||||
| 		 * Configuration that is currently in use. | ||||
| 		 */ | ||||
| 		map_id = map_id << 1 | !!(data_byte & read_data_mask); | ||||
| 		i = i + 2; | ||||
| 		map_id = map_id << 1 | !!(*buf & read_data_mask); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Find the matching configuration map */ | ||||
| 	while (SMPT_MAP_ID(smpt[i]) != map_id) { | ||||
| 	/*
 | ||||
| 	 * If command descriptors are provided, they always precede map | ||||
| 	 * descriptors in the table. There is no need to start the iteration | ||||
| 	 * over smpt array all over again. | ||||
| 	 * | ||||
| 	 * Find the matching configuration map. | ||||
| 	 */ | ||||
| 	ret = ERR_PTR(-EINVAL); | ||||
| 	while (i < smpt_len) { | ||||
| 		if (SMPT_MAP_ID(smpt[i]) == map_id) { | ||||
| 			ret = smpt + i; | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * If there are no more configuration map descriptors and no | ||||
| 		 * configuration ID matched the configuration identifier, the | ||||
| 		 * sector address map is unknown. | ||||
| 		 */ | ||||
| 		if (smpt[i] & SMPT_DESC_END) | ||||
| 			goto out; | ||||
| 			break; | ||||
| 
 | ||||
| 		/* increment the table index to the next map */ | ||||
| 		i += SMPT_MAP_REGION_COUNT(smpt[i]) + 1; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = smpt + i; | ||||
| 	/* fall through */ | ||||
| out: | ||||
| 	kfree(buf); | ||||
| 	nor->addr_width = addr_width; | ||||
| 	nor->read_dummy = read_dummy; | ||||
| 	nor->read_opcode = read_opcode; | ||||
| @ -2946,7 +3000,7 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, | ||||
| 	u64 offset; | ||||
| 	u32 region_count; | ||||
| 	int i, j; | ||||
| 	u8 erase_type; | ||||
| 	u8 erase_type, uniform_erase_type; | ||||
| 
 | ||||
| 	region_count = SMPT_MAP_REGION_COUNT(*smpt); | ||||
| 	/*
 | ||||
| @ -2959,7 +3013,7 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, | ||||
| 		return -ENOMEM; | ||||
| 	map->regions = region; | ||||
| 
 | ||||
| 	map->uniform_erase_type = 0xff; | ||||
| 	uniform_erase_type = 0xff; | ||||
| 	offset = 0; | ||||
| 	/* Populate regions. */ | ||||
| 	for (i = 0; i < region_count; i++) { | ||||
| @ -2974,12 +3028,15 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, | ||||
| 		 * Save the erase types that are supported in all regions and | ||||
| 		 * can erase the entire flash memory. | ||||
| 		 */ | ||||
| 		map->uniform_erase_type &= erase_type; | ||||
| 		uniform_erase_type &= erase_type; | ||||
| 
 | ||||
| 		offset = (region[i].offset & ~SNOR_ERASE_FLAGS_MASK) + | ||||
| 			 region[i].size; | ||||
| 	} | ||||
| 
 | ||||
| 	map->uniform_erase_type = spi_nor_sort_erase_mask(map, | ||||
| 							  uniform_erase_type); | ||||
| 
 | ||||
| 	spi_nor_region_mark_end(®ion[i - 1]); | ||||
| 
 | ||||
| 	return 0; | ||||
| @ -3020,9 +3077,9 @@ static int spi_nor_parse_smpt(struct spi_nor *nor, | ||||
| 	for (i = 0; i < smpt_header->length; i++) | ||||
| 		smpt[i] = le32_to_cpu(smpt[i]); | ||||
| 
 | ||||
| 	sector_map = spi_nor_get_map_in_use(nor, smpt); | ||||
| 	if (!sector_map) { | ||||
| 		ret = -EINVAL; | ||||
| 	sector_map = spi_nor_get_map_in_use(nor, smpt, smpt_header->length); | ||||
| 	if (IS_ERR(sector_map)) { | ||||
| 		ret = PTR_ERR(sector_map); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| @ -3125,7 +3182,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor, | ||||
| 	if (err) | ||||
| 		goto exit; | ||||
| 
 | ||||
| 	/* Parse other parameter headers. */ | ||||
| 	/* Parse optional parameter tables. */ | ||||
| 	for (i = 0; i < header.nph; i++) { | ||||
| 		param_header = ¶m_headers[i]; | ||||
| 
 | ||||
| @ -3138,8 +3195,17 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor, | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		if (err) | ||||
| 			goto exit; | ||||
| 		if (err) { | ||||
| 			dev_warn(dev, "Failed to parse optional parameter table: %04x\n", | ||||
| 				 SFDP_PARAM_HEADER_ID(param_header)); | ||||
| 			/*
 | ||||
| 			 * Let's not drop all information we extracted so far | ||||
| 			 * if optional table parsers fail. In case of failing, | ||||
| 			 * each optional parser is responsible to roll back to | ||||
| 			 * the previously known spi_nor data. | ||||
| 			 */ | ||||
| 			err = 0; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| exit: | ||||
|  | ||||
| @ -477,6 +477,34 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(can_put_echo_skb); | ||||
| 
 | ||||
| struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr) | ||||
| { | ||||
| 	struct can_priv *priv = netdev_priv(dev); | ||||
| 	struct sk_buff *skb = priv->echo_skb[idx]; | ||||
| 	struct canfd_frame *cf; | ||||
| 
 | ||||
| 	if (idx >= priv->echo_skb_max) { | ||||
| 		netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n", | ||||
| 			   __func__, idx, priv->echo_skb_max); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!skb) { | ||||
| 		netdev_err(dev, "%s: BUG! Trying to echo non existing skb: can_priv::echo_skb[%u]\n", | ||||
| 			   __func__, idx); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Using "struct canfd_frame::len" for the frame
 | ||||
| 	 * length is supported on both CAN and CANFD frames. | ||||
| 	 */ | ||||
| 	cf = (struct canfd_frame *)skb->data; | ||||
| 	*len_ptr = cf->len; | ||||
| 	priv->echo_skb[idx] = NULL; | ||||
| 
 | ||||
| 	return skb; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Get the skb from the stack and loop it back locally | ||||
|  * | ||||
| @ -486,22 +514,16 @@ EXPORT_SYMBOL_GPL(can_put_echo_skb); | ||||
|  */ | ||||
| unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx) | ||||
| { | ||||
| 	struct can_priv *priv = netdev_priv(dev); | ||||
| 	struct sk_buff *skb; | ||||
| 	u8 len; | ||||
| 
 | ||||
| 	BUG_ON(idx >= priv->echo_skb_max); | ||||
| 	skb = __can_get_echo_skb(dev, idx, &len); | ||||
| 	if (!skb) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (priv->echo_skb[idx]) { | ||||
| 		struct sk_buff *skb = priv->echo_skb[idx]; | ||||
| 		struct can_frame *cf = (struct can_frame *)skb->data; | ||||
| 		u8 dlc = cf->can_dlc; | ||||
| 	netif_rx(skb); | ||||
| 
 | ||||
| 		netif_rx(priv->echo_skb[idx]); | ||||
| 		priv->echo_skb[idx] = NULL; | ||||
| 
 | ||||
| 		return dlc; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 	return len; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(can_get_echo_skb); | ||||
| 
 | ||||
|  | ||||
| @ -135,13 +135,12 @@ | ||||
| 
 | ||||
| /* FLEXCAN interrupt flag register (IFLAG) bits */ | ||||
| /* Errata ERR005829 step7: Reserve first valid MB */ | ||||
| #define FLEXCAN_TX_MB_RESERVED_OFF_FIFO	8 | ||||
| #define FLEXCAN_TX_MB_OFF_FIFO		9 | ||||
| #define FLEXCAN_TX_MB_RESERVED_OFF_FIFO		8 | ||||
| #define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP	0 | ||||
| #define FLEXCAN_TX_MB_OFF_TIMESTAMP		1 | ||||
| #define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST	(FLEXCAN_TX_MB_OFF_TIMESTAMP + 1) | ||||
| #define FLEXCAN_RX_MB_OFF_TIMESTAMP_LAST	63 | ||||
| #define FLEXCAN_IFLAG_MB(x)		BIT(x) | ||||
| #define FLEXCAN_TX_MB				63 | ||||
| #define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST	(FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1) | ||||
| #define FLEXCAN_RX_MB_OFF_TIMESTAMP_LAST	(FLEXCAN_TX_MB - 1) | ||||
| #define FLEXCAN_IFLAG_MB(x)		BIT(x & 0x1f) | ||||
| #define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW	BIT(7) | ||||
| #define FLEXCAN_IFLAG_RX_FIFO_WARN	BIT(6) | ||||
| #define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE	BIT(5) | ||||
| @ -259,9 +258,7 @@ struct flexcan_priv { | ||||
| 	struct can_rx_offload offload; | ||||
| 
 | ||||
| 	struct flexcan_regs __iomem *regs; | ||||
| 	struct flexcan_mb __iomem *tx_mb; | ||||
| 	struct flexcan_mb __iomem *tx_mb_reserved; | ||||
| 	u8 tx_mb_idx; | ||||
| 	u32 reg_ctrl_default; | ||||
| 	u32 reg_imask1_default; | ||||
| 	u32 reg_imask2_default; | ||||
| @ -515,6 +512,7 @@ static int flexcan_get_berr_counter(const struct net_device *dev, | ||||
| static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||||
| { | ||||
| 	const struct flexcan_priv *priv = netdev_priv(dev); | ||||
| 	struct flexcan_regs __iomem *regs = priv->regs; | ||||
| 	struct can_frame *cf = (struct can_frame *)skb->data; | ||||
| 	u32 can_id; | ||||
| 	u32 data; | ||||
| @ -537,17 +535,17 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de | ||||
| 
 | ||||
| 	if (cf->can_dlc > 0) { | ||||
| 		data = be32_to_cpup((__be32 *)&cf->data[0]); | ||||
| 		priv->write(data, &priv->tx_mb->data[0]); | ||||
| 		priv->write(data, ®s->mb[FLEXCAN_TX_MB].data[0]); | ||||
| 	} | ||||
| 	if (cf->can_dlc > 4) { | ||||
| 		data = be32_to_cpup((__be32 *)&cf->data[4]); | ||||
| 		priv->write(data, &priv->tx_mb->data[1]); | ||||
| 		priv->write(data, ®s->mb[FLEXCAN_TX_MB].data[1]); | ||||
| 	} | ||||
| 
 | ||||
| 	can_put_echo_skb(skb, dev, 0); | ||||
| 
 | ||||
| 	priv->write(can_id, &priv->tx_mb->can_id); | ||||
| 	priv->write(ctrl, &priv->tx_mb->can_ctrl); | ||||
| 	priv->write(can_id, ®s->mb[FLEXCAN_TX_MB].can_id); | ||||
| 	priv->write(ctrl, ®s->mb[FLEXCAN_TX_MB].can_ctrl); | ||||
| 
 | ||||
| 	/* Errata ERR005829 step8:
 | ||||
| 	 * Write twice INACTIVE(0x8) code to first MB. | ||||
| @ -563,9 +561,13 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de | ||||
| static void flexcan_irq_bus_err(struct net_device *dev, u32 reg_esr) | ||||
| { | ||||
| 	struct flexcan_priv *priv = netdev_priv(dev); | ||||
| 	struct flexcan_regs __iomem *regs = priv->regs; | ||||
| 	struct sk_buff *skb; | ||||
| 	struct can_frame *cf; | ||||
| 	bool rx_errors = false, tx_errors = false; | ||||
| 	u32 timestamp; | ||||
| 
 | ||||
| 	timestamp = priv->read(®s->timer) << 16; | ||||
| 
 | ||||
| 	skb = alloc_can_err_skb(dev, &cf); | ||||
| 	if (unlikely(!skb)) | ||||
| @ -612,17 +614,21 @@ static void flexcan_irq_bus_err(struct net_device *dev, u32 reg_esr) | ||||
| 	if (tx_errors) | ||||
| 		dev->stats.tx_errors++; | ||||
| 
 | ||||
| 	can_rx_offload_irq_queue_err_skb(&priv->offload, skb); | ||||
| 	can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); | ||||
| } | ||||
| 
 | ||||
| static void flexcan_irq_state(struct net_device *dev, u32 reg_esr) | ||||
| { | ||||
| 	struct flexcan_priv *priv = netdev_priv(dev); | ||||
| 	struct flexcan_regs __iomem *regs = priv->regs; | ||||
| 	struct sk_buff *skb; | ||||
| 	struct can_frame *cf; | ||||
| 	enum can_state new_state, rx_state, tx_state; | ||||
| 	int flt; | ||||
| 	struct can_berr_counter bec; | ||||
| 	u32 timestamp; | ||||
| 
 | ||||
| 	timestamp = priv->read(®s->timer) << 16; | ||||
| 
 | ||||
| 	flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK; | ||||
| 	if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) { | ||||
| @ -652,7 +658,7 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr) | ||||
| 	if (unlikely(new_state == CAN_STATE_BUS_OFF)) | ||||
| 		can_bus_off(dev); | ||||
| 
 | ||||
| 	can_rx_offload_irq_queue_err_skb(&priv->offload, skb); | ||||
| 	can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); | ||||
| } | ||||
| 
 | ||||
| static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload) | ||||
| @ -720,9 +726,14 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload, | ||||
| 			priv->write(BIT(n - 32), ®s->iflag2); | ||||
| 	} else { | ||||
| 		priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, ®s->iflag1); | ||||
| 		priv->read(®s->timer); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Read the Free Running Timer. It is optional but recommended
 | ||||
| 	 * to unlock Mailbox as soon as possible and make it available | ||||
| 	 * for reception. | ||||
| 	 */ | ||||
| 	priv->read(®s->timer); | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| @ -732,9 +743,9 @@ static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv) | ||||
| 	struct flexcan_regs __iomem *regs = priv->regs; | ||||
| 	u32 iflag1, iflag2; | ||||
| 
 | ||||
| 	iflag2 = priv->read(®s->iflag2) & priv->reg_imask2_default; | ||||
| 	iflag1 = priv->read(®s->iflag1) & priv->reg_imask1_default & | ||||
| 		~FLEXCAN_IFLAG_MB(priv->tx_mb_idx); | ||||
| 	iflag2 = priv->read(®s->iflag2) & priv->reg_imask2_default & | ||||
| 		~FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB); | ||||
| 	iflag1 = priv->read(®s->iflag1) & priv->reg_imask1_default; | ||||
| 
 | ||||
| 	return (u64)iflag2 << 32 | iflag1; | ||||
| } | ||||
| @ -746,11 +757,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) | ||||
| 	struct flexcan_priv *priv = netdev_priv(dev); | ||||
| 	struct flexcan_regs __iomem *regs = priv->regs; | ||||
| 	irqreturn_t handled = IRQ_NONE; | ||||
| 	u32 reg_iflag1, reg_esr; | ||||
| 	u32 reg_iflag2, reg_esr; | ||||
| 	enum can_state last_state = priv->can.state; | ||||
| 
 | ||||
| 	reg_iflag1 = priv->read(®s->iflag1); | ||||
| 
 | ||||
| 	/* reception interrupt */ | ||||
| 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { | ||||
| 		u64 reg_iflag; | ||||
| @ -764,6 +773,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) | ||||
| 				break; | ||||
| 		} | ||||
| 	} else { | ||||
| 		u32 reg_iflag1; | ||||
| 
 | ||||
| 		reg_iflag1 = priv->read(®s->iflag1); | ||||
| 		if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) { | ||||
| 			handled = IRQ_HANDLED; | ||||
| 			can_rx_offload_irq_offload_fifo(&priv->offload); | ||||
| @ -779,17 +791,22 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	reg_iflag2 = priv->read(®s->iflag2); | ||||
| 
 | ||||
| 	/* transmission complete interrupt */ | ||||
| 	if (reg_iflag1 & FLEXCAN_IFLAG_MB(priv->tx_mb_idx)) { | ||||
| 	if (reg_iflag2 & FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB)) { | ||||
| 		u32 reg_ctrl = priv->read(®s->mb[FLEXCAN_TX_MB].can_ctrl); | ||||
| 
 | ||||
| 		handled = IRQ_HANDLED; | ||||
| 		stats->tx_bytes += can_get_echo_skb(dev, 0); | ||||
| 		stats->tx_bytes += can_rx_offload_get_echo_skb(&priv->offload, | ||||
| 							       0, reg_ctrl << 16); | ||||
| 		stats->tx_packets++; | ||||
| 		can_led_event(dev, CAN_LED_EVENT_TX); | ||||
| 
 | ||||
| 		/* after sending a RTR frame MB is in RX mode */ | ||||
| 		priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, | ||||
| 			    &priv->tx_mb->can_ctrl); | ||||
| 		priv->write(FLEXCAN_IFLAG_MB(priv->tx_mb_idx), ®s->iflag1); | ||||
| 			    ®s->mb[FLEXCAN_TX_MB].can_ctrl); | ||||
| 		priv->write(FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB), ®s->iflag2); | ||||
| 		netif_wake_queue(dev); | ||||
| 	} | ||||
| 
 | ||||
| @ -931,15 +948,13 @@ static int flexcan_chip_start(struct net_device *dev) | ||||
| 	reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff); | ||||
| 	reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT | FLEXCAN_MCR_SUPV | | ||||
| 		FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_SRX_DIS | FLEXCAN_MCR_IRMQ | | ||||
| 		FLEXCAN_MCR_IDAM_C; | ||||
| 		FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_MAXMB(FLEXCAN_TX_MB); | ||||
| 
 | ||||
| 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { | ||||
| 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) | ||||
| 		reg_mcr &= ~FLEXCAN_MCR_FEN; | ||||
| 		reg_mcr |= FLEXCAN_MCR_MAXMB(priv->offload.mb_last); | ||||
| 	} else { | ||||
| 		reg_mcr |= FLEXCAN_MCR_FEN | | ||||
| 			FLEXCAN_MCR_MAXMB(priv->tx_mb_idx); | ||||
| 	} | ||||
| 	else | ||||
| 		reg_mcr |= FLEXCAN_MCR_FEN; | ||||
| 
 | ||||
| 	netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr); | ||||
| 	priv->write(reg_mcr, ®s->mcr); | ||||
| 
 | ||||
| @ -982,16 +997,17 @@ static int flexcan_chip_start(struct net_device *dev) | ||||
| 		priv->write(reg_ctrl2, ®s->ctrl2); | ||||
| 	} | ||||
| 
 | ||||
| 	/* clear and invalidate all mailboxes first */ | ||||
| 	for (i = priv->tx_mb_idx; i < ARRAY_SIZE(regs->mb); i++) { | ||||
| 		priv->write(FLEXCAN_MB_CODE_RX_INACTIVE, | ||||
| 			    ®s->mb[i].can_ctrl); | ||||
| 	} | ||||
| 
 | ||||
| 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { | ||||
| 		for (i = priv->offload.mb_first; i <= priv->offload.mb_last; i++) | ||||
| 		for (i = priv->offload.mb_first; i <= priv->offload.mb_last; i++) { | ||||
| 			priv->write(FLEXCAN_MB_CODE_RX_EMPTY, | ||||
| 				    ®s->mb[i].can_ctrl); | ||||
| 		} | ||||
| 	} else { | ||||
| 		/* clear and invalidate unused mailboxes first */ | ||||
| 		for (i = FLEXCAN_TX_MB_RESERVED_OFF_FIFO; i <= ARRAY_SIZE(regs->mb); i++) { | ||||
| 			priv->write(FLEXCAN_MB_CODE_RX_INACTIVE, | ||||
| 				    ®s->mb[i].can_ctrl); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Errata ERR005829: mark first TX mailbox as INACTIVE */ | ||||
| @ -1000,7 +1016,7 @@ static int flexcan_chip_start(struct net_device *dev) | ||||
| 
 | ||||
| 	/* mark TX mailbox as INACTIVE */ | ||||
| 	priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, | ||||
| 		    &priv->tx_mb->can_ctrl); | ||||
| 		    ®s->mb[FLEXCAN_TX_MB].can_ctrl); | ||||
| 
 | ||||
| 	/* acceptance mask/acceptance code (accept everything) */ | ||||
| 	priv->write(0x0, ®s->rxgmask); | ||||
| @ -1355,17 +1371,13 @@ static int flexcan_probe(struct platform_device *pdev) | ||||
| 	priv->devtype_data = devtype_data; | ||||
| 	priv->reg_xceiver = reg_xceiver; | ||||
| 
 | ||||
| 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { | ||||
| 		priv->tx_mb_idx = FLEXCAN_TX_MB_OFF_TIMESTAMP; | ||||
| 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) | ||||
| 		priv->tx_mb_reserved = ®s->mb[FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP]; | ||||
| 	} else { | ||||
| 		priv->tx_mb_idx = FLEXCAN_TX_MB_OFF_FIFO; | ||||
| 	else | ||||
| 		priv->tx_mb_reserved = ®s->mb[FLEXCAN_TX_MB_RESERVED_OFF_FIFO]; | ||||
| 	} | ||||
| 	priv->tx_mb = ®s->mb[priv->tx_mb_idx]; | ||||
| 
 | ||||
| 	priv->reg_imask1_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx); | ||||
| 	priv->reg_imask2_default = 0; | ||||
| 	priv->reg_imask1_default = 0; | ||||
| 	priv->reg_imask2_default = FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB); | ||||
| 
 | ||||
| 	priv->offload.mailbox_read = flexcan_mailbox_read; | ||||
| 
 | ||||
|  | ||||
| @ -24,6 +24,9 @@ | ||||
| 
 | ||||
| #define RCAR_CAN_DRV_NAME	"rcar_can" | ||||
| 
 | ||||
| #define RCAR_SUPPORTED_CLOCKS	(BIT(CLKR_CLKP1) | BIT(CLKR_CLKP2) | \ | ||||
| 				 BIT(CLKR_CLKEXT)) | ||||
| 
 | ||||
| /* Mailbox configuration:
 | ||||
|  * mailbox 60 - 63 - Rx FIFO mailboxes | ||||
|  * mailbox 56 - 59 - Tx FIFO mailboxes | ||||
| @ -789,7 +792,7 @@ static int rcar_can_probe(struct platform_device *pdev) | ||||
| 		goto fail_clk; | ||||
| 	} | ||||
| 
 | ||||
| 	if (clock_select >= ARRAY_SIZE(clock_names)) { | ||||
| 	if (!(BIT(clock_select) & RCAR_SUPPORTED_CLOCKS)) { | ||||
| 		err = -EINVAL; | ||||
| 		dev_err(&pdev->dev, "invalid CAN clock selected\n"); | ||||
| 		goto fail_clk; | ||||
|  | ||||
| @ -211,7 +211,54 @@ int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload) | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_fifo); | ||||
| 
 | ||||
| int can_rx_offload_irq_queue_err_skb(struct can_rx_offload *offload, struct sk_buff *skb) | ||||
| int can_rx_offload_queue_sorted(struct can_rx_offload *offload, | ||||
| 				struct sk_buff *skb, u32 timestamp) | ||||
| { | ||||
| 	struct can_rx_offload_cb *cb; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	if (skb_queue_len(&offload->skb_queue) > | ||||
| 	    offload->skb_queue_len_max) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	cb = can_rx_offload_get_cb(skb); | ||||
| 	cb->timestamp = timestamp; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&offload->skb_queue.lock, flags); | ||||
| 	__skb_queue_add_sort(&offload->skb_queue, skb, can_rx_offload_compare); | ||||
| 	spin_unlock_irqrestore(&offload->skb_queue.lock, flags); | ||||
| 
 | ||||
| 	can_rx_offload_schedule(offload); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(can_rx_offload_queue_sorted); | ||||
| 
 | ||||
| unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload, | ||||
| 					 unsigned int idx, u32 timestamp) | ||||
| { | ||||
| 	struct net_device *dev = offload->dev; | ||||
| 	struct net_device_stats *stats = &dev->stats; | ||||
| 	struct sk_buff *skb; | ||||
| 	u8 len; | ||||
| 	int err; | ||||
| 
 | ||||
| 	skb = __can_get_echo_skb(dev, idx, &len); | ||||
| 	if (!skb) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	err = can_rx_offload_queue_sorted(offload, skb, timestamp); | ||||
| 	if (err) { | ||||
| 		stats->rx_errors++; | ||||
| 		stats->tx_fifo_errors++; | ||||
| 	} | ||||
| 
 | ||||
| 	return len; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(can_rx_offload_get_echo_skb); | ||||
| 
 | ||||
| int can_rx_offload_queue_tail(struct can_rx_offload *offload, | ||||
| 			      struct sk_buff *skb) | ||||
| { | ||||
| 	if (skb_queue_len(&offload->skb_queue) > | ||||
| 	    offload->skb_queue_len_max) | ||||
| @ -222,7 +269,7 @@ int can_rx_offload_irq_queue_err_skb(struct can_rx_offload *offload, struct sk_b | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(can_rx_offload_irq_queue_err_skb); | ||||
| EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail); | ||||
| 
 | ||||
| static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offload *offload, unsigned int weight) | ||||
| { | ||||
|  | ||||
| @ -760,7 +760,7 @@ static int hi3110_open(struct net_device *net) | ||||
| { | ||||
| 	struct hi3110_priv *priv = netdev_priv(net); | ||||
| 	struct spi_device *spi = priv->spi; | ||||
| 	unsigned long flags = IRQF_ONESHOT | IRQF_TRIGGER_RISING; | ||||
| 	unsigned long flags = IRQF_ONESHOT | IRQF_TRIGGER_HIGH; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = open_candev(net); | ||||
|  | ||||
| @ -528,7 +528,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, | ||||
| 			context = &priv->tx_contexts[i]; | ||||
| 
 | ||||
| 			context->echo_index = i; | ||||
| 			can_put_echo_skb(skb, netdev, context->echo_index); | ||||
| 			++priv->active_tx_contexts; | ||||
| 			if (priv->active_tx_contexts >= (int)dev->max_tx_urbs) | ||||
| 				netif_stop_queue(netdev); | ||||
| @ -553,7 +552,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, | ||||
| 		dev_kfree_skb(skb); | ||||
| 		spin_lock_irqsave(&priv->tx_contexts_lock, flags); | ||||
| 
 | ||||
| 		can_free_echo_skb(netdev, context->echo_index); | ||||
| 		context->echo_index = dev->max_tx_urbs; | ||||
| 		--priv->active_tx_contexts; | ||||
| 		netif_wake_queue(netdev); | ||||
| @ -564,6 +562,8 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, | ||||
| 
 | ||||
| 	context->priv = priv; | ||||
| 
 | ||||
| 	can_put_echo_skb(skb, netdev, context->echo_index); | ||||
| 
 | ||||
| 	usb_fill_bulk_urb(urb, dev->udev, | ||||
| 			  usb_sndbulkpipe(dev->udev, | ||||
| 					  dev->bulk_out->bEndpointAddress), | ||||
|  | ||||
| @ -1019,6 +1019,11 @@ kvaser_usb_hydra_error_frame(struct kvaser_usb_net_priv *priv, | ||||
| 					new_state : CAN_STATE_ERROR_ACTIVE; | ||||
| 
 | ||||
| 			can_change_state(netdev, cf, tx_state, rx_state); | ||||
| 
 | ||||
| 			if (priv->can.restart_ms && | ||||
| 			    old_state >= CAN_STATE_BUS_OFF && | ||||
| 			    new_state < CAN_STATE_BUS_OFF) | ||||
| 				cf->can_id |= CAN_ERR_RESTARTED; | ||||
| 		} | ||||
| 
 | ||||
| 		if (new_state == CAN_STATE_BUS_OFF) { | ||||
| @ -1028,11 +1033,6 @@ kvaser_usb_hydra_error_frame(struct kvaser_usb_net_priv *priv, | ||||
| 
 | ||||
| 			can_bus_off(netdev); | ||||
| 		} | ||||
| 
 | ||||
| 		if (priv->can.restart_ms && | ||||
| 		    old_state >= CAN_STATE_BUS_OFF && | ||||
| 		    new_state < CAN_STATE_BUS_OFF) | ||||
| 			cf->can_id |= CAN_ERR_RESTARTED; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!skb) { | ||||
|  | ||||
| @ -35,10 +35,6 @@ | ||||
| #include <linux/slab.h> | ||||
| #include <linux/usb.h> | ||||
| 
 | ||||
| #include <linux/can.h> | ||||
| #include <linux/can/dev.h> | ||||
| #include <linux/can/error.h> | ||||
| 
 | ||||
| #define UCAN_DRIVER_NAME "ucan" | ||||
| #define UCAN_MAX_RX_URBS 8 | ||||
| /* the CAN controller needs a while to enable/disable the bus */ | ||||
| @ -1575,11 +1571,8 @@ err_firmware_needs_update: | ||||
| /* disconnect the device */ | ||||
| static void ucan_disconnect(struct usb_interface *intf) | ||||
| { | ||||
| 	struct usb_device *udev; | ||||
| 	struct ucan_priv *up = usb_get_intfdata(intf); | ||||
| 
 | ||||
| 	udev = interface_to_usbdev(intf); | ||||
| 
 | ||||
| 	usb_set_intfdata(intf, NULL); | ||||
| 
 | ||||
| 	if (up) { | ||||
|  | ||||
| @ -1848,6 +1848,8 @@ static void ena_down(struct ena_adapter *adapter) | ||||
| 		rc = ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason); | ||||
| 		if (rc) | ||||
| 			dev_err(&adapter->pdev->dev, "Device reset failed\n"); | ||||
| 		/* stop submitting admin commands on a device that was reset */ | ||||
| 		ena_com_set_admin_running_state(adapter->ena_dev, false); | ||||
| 	} | ||||
| 
 | ||||
| 	ena_destroy_all_io_queues(adapter); | ||||
| @ -1914,6 +1916,9 @@ static int ena_close(struct net_device *netdev) | ||||
| 
 | ||||
| 	netif_dbg(adapter, ifdown, netdev, "%s\n", __func__); | ||||
| 
 | ||||
| 	if (!test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags)) | ||||
| 		ena_down(adapter); | ||||
| 
 | ||||
| @ -2613,9 +2618,7 @@ static void ena_destroy_device(struct ena_adapter *adapter, bool graceful) | ||||
| 		ena_down(adapter); | ||||
| 
 | ||||
| 	/* Stop the device from sending AENQ events (in case reset flag is set
 | ||||
| 	 *  and device is up, ena_close already reset the device | ||||
| 	 * In case the reset flag is set and the device is up, ena_down() | ||||
| 	 * already perform the reset, so it can be skipped. | ||||
| 	 *  and device is up, ena_down() already reset the device. | ||||
| 	 */ | ||||
| 	if (!(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags) && dev_up)) | ||||
| 		ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason); | ||||
| @ -2694,8 +2697,8 @@ err_device_destroy: | ||||
| 	ena_com_abort_admin_commands(ena_dev); | ||||
| 	ena_com_wait_for_abort_completion(ena_dev); | ||||
| 	ena_com_admin_destroy(ena_dev); | ||||
| 	ena_com_mmio_reg_read_request_destroy(ena_dev); | ||||
| 	ena_com_dev_reset(ena_dev, ENA_REGS_RESET_DRIVER_INVALID_STATE); | ||||
| 	ena_com_mmio_reg_read_request_destroy(ena_dev); | ||||
| err: | ||||
| 	clear_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags); | ||||
| 	clear_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags); | ||||
| @ -3452,6 +3455,8 @@ err_rss: | ||||
| 	ena_com_rss_destroy(ena_dev); | ||||
| err_free_msix: | ||||
| 	ena_com_dev_reset(ena_dev, ENA_REGS_RESET_INIT_ERR); | ||||
| 	/* stop submitting admin commands on a device that was reset */ | ||||
| 	ena_com_set_admin_running_state(ena_dev, false); | ||||
| 	ena_free_mgmnt_irq(adapter); | ||||
| 	ena_disable_msix(adapter); | ||||
| err_worker_destroy: | ||||
| @ -3498,18 +3503,12 @@ static void ena_remove(struct pci_dev *pdev) | ||||
| 
 | ||||
| 	cancel_work_sync(&adapter->reset_task); | ||||
| 
 | ||||
| 	unregister_netdev(netdev); | ||||
| 
 | ||||
| 	/* If the device is running then we want to make sure the device will be
 | ||||
| 	 * reset to make sure no more events will be issued by the device. | ||||
| 	 */ | ||||
| 	if (test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags)) | ||||
| 		set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); | ||||
| 
 | ||||
| 	rtnl_lock(); | ||||
| 	ena_destroy_device(adapter, true); | ||||
| 	rtnl_unlock(); | ||||
| 
 | ||||
| 	unregister_netdev(netdev); | ||||
| 
 | ||||
| 	free_netdev(netdev); | ||||
| 
 | ||||
| 	ena_com_rss_destroy(ena_dev); | ||||
|  | ||||
| @ -45,7 +45,7 @@ | ||||
| 
 | ||||
| #define DRV_MODULE_VER_MAJOR	2 | ||||
| #define DRV_MODULE_VER_MINOR	0 | ||||
| #define DRV_MODULE_VER_SUBMINOR 1 | ||||
| #define DRV_MODULE_VER_SUBMINOR 2 | ||||
| 
 | ||||
| #define DRV_MODULE_NAME		"ena" | ||||
| #ifndef DRV_MODULE_VERSION | ||||
|  | ||||
| @ -1419,7 +1419,7 @@ static int sparc_lance_probe_one(struct platform_device *op, | ||||
| 
 | ||||
| 			prop = of_get_property(nd, "tpe-link-test?", NULL); | ||||
| 			if (!prop) | ||||
| 				goto no_link_test; | ||||
| 				goto node_put; | ||||
| 
 | ||||
| 			if (strcmp(prop, "true")) { | ||||
| 				printk(KERN_NOTICE "SunLance: warning: overriding option " | ||||
| @ -1428,6 +1428,8 @@ static int sparc_lance_probe_one(struct platform_device *op, | ||||
| 				       "to ecd@skynet.be\n"); | ||||
| 				auxio_set_lte(AUXIO_LTE_ON); | ||||
| 			} | ||||
| node_put: | ||||
| 			of_node_put(nd); | ||||
| no_link_test: | ||||
| 			lp->auto_select = 1; | ||||
| 			lp->tpe = 0; | ||||
|  | ||||
| @ -2191,6 +2191,13 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id, | ||||
| #define PMF_DMAE_C(bp)			(BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \ | ||||
| 					 E1HVN_MAX) | ||||
| 
 | ||||
| /* Following is the DMAE channel number allocation for the clients.
 | ||||
|  *   MFW: OCBB/OCSD implementations use DMAE channels 14/15 respectively. | ||||
|  *   Driver: 0-3 and 8-11 (for PF dmae operations) | ||||
|  *           4 and 12 (for stats requests) | ||||
|  */ | ||||
| #define BNX2X_FW_DMAE_C                 13 /* Channel for FW DMAE operations */ | ||||
| 
 | ||||
| /* PCIE link and speed */ | ||||
| #define PCICFG_LINK_WIDTH		0x1f00000 | ||||
| #define PCICFG_LINK_WIDTH_SHIFT		20 | ||||
|  | ||||
| @ -6149,6 +6149,7 @@ static inline int bnx2x_func_send_start(struct bnx2x *bp, | ||||
| 	rdata->sd_vlan_tag	= cpu_to_le16(start_params->sd_vlan_tag); | ||||
| 	rdata->path_id		= BP_PATH(bp); | ||||
| 	rdata->network_cos_mode	= start_params->network_cos_mode; | ||||
| 	rdata->dmae_cmd_id	= BNX2X_FW_DMAE_C; | ||||
| 
 | ||||
| 	rdata->vxlan_dst_port	= cpu_to_le16(start_params->vxlan_dst_port); | ||||
| 	rdata->geneve_dst_port	= cpu_to_le16(start_params->geneve_dst_port); | ||||
|  | ||||
| @ -1675,7 +1675,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, | ||||
| 	} else { | ||||
| 		if (rxcmp1->rx_cmp_cfa_code_errors_v2 & RX_CMP_L4_CS_ERR_BITS) { | ||||
| 			if (dev->features & NETIF_F_RXCSUM) | ||||
| 				cpr->rx_l4_csum_errors++; | ||||
| 				bnapi->cp_ring.rx_l4_csum_errors++; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -8714,6 +8714,26 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features) | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| static int bnxt_dbg_hwrm_ring_info_get(struct bnxt *bp, u8 ring_type, | ||||
| 				       u32 ring_id, u32 *prod, u32 *cons) | ||||
| { | ||||
| 	struct hwrm_dbg_ring_info_get_output *resp = bp->hwrm_cmd_resp_addr; | ||||
| 	struct hwrm_dbg_ring_info_get_input req = {0}; | ||||
| 	int rc; | ||||
| 
 | ||||
| 	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_DBG_RING_INFO_GET, -1, -1); | ||||
| 	req.ring_type = ring_type; | ||||
| 	req.fw_ring_id = cpu_to_le32(ring_id); | ||||
| 	mutex_lock(&bp->hwrm_cmd_lock); | ||||
| 	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); | ||||
| 	if (!rc) { | ||||
| 		*prod = le32_to_cpu(resp->producer_index); | ||||
| 		*cons = le32_to_cpu(resp->consumer_index); | ||||
| 	} | ||||
| 	mutex_unlock(&bp->hwrm_cmd_lock); | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| static void bnxt_dump_tx_sw_state(struct bnxt_napi *bnapi) | ||||
| { | ||||
| 	struct bnxt_tx_ring_info *txr = bnapi->tx_ring; | ||||
| @ -8821,6 +8841,11 @@ static void bnxt_timer(struct timer_list *t) | ||||
| 			bnxt_queue_sp_work(bp); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if ((bp->flags & BNXT_FLAG_CHIP_P5) && netif_carrier_ok(dev)) { | ||||
| 		set_bit(BNXT_RING_COAL_NOW_SP_EVENT, &bp->sp_event); | ||||
| 		bnxt_queue_sp_work(bp); | ||||
| 	} | ||||
| bnxt_restart_timer: | ||||
| 	mod_timer(&bp->timer, jiffies + bp->current_interval); | ||||
| } | ||||
| @ -8851,6 +8876,44 @@ static void bnxt_reset(struct bnxt *bp, bool silent) | ||||
| 	bnxt_rtnl_unlock_sp(bp); | ||||
| } | ||||
| 
 | ||||
| static void bnxt_chk_missed_irq(struct bnxt *bp) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (!(bp->flags & BNXT_FLAG_CHIP_P5)) | ||||
| 		return; | ||||
| 
 | ||||
| 	for (i = 0; i < bp->cp_nr_rings; i++) { | ||||
| 		struct bnxt_napi *bnapi = bp->bnapi[i]; | ||||
| 		struct bnxt_cp_ring_info *cpr; | ||||
| 		u32 fw_ring_id; | ||||
| 		int j; | ||||
| 
 | ||||
| 		if (!bnapi) | ||||
| 			continue; | ||||
| 
 | ||||
| 		cpr = &bnapi->cp_ring; | ||||
| 		for (j = 0; j < 2; j++) { | ||||
| 			struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j]; | ||||
| 			u32 val[2]; | ||||
| 
 | ||||
| 			if (!cpr2 || cpr2->has_more_work || | ||||
| 			    !bnxt_has_work(bp, cpr2)) | ||||
| 				continue; | ||||
| 
 | ||||
| 			if (cpr2->cp_raw_cons != cpr2->last_cp_raw_cons) { | ||||
| 				cpr2->last_cp_raw_cons = cpr2->cp_raw_cons; | ||||
| 				continue; | ||||
| 			} | ||||
| 			fw_ring_id = cpr2->cp_ring_struct.fw_ring_id; | ||||
| 			bnxt_dbg_hwrm_ring_info_get(bp, | ||||
| 				DBG_RING_INFO_GET_REQ_RING_TYPE_L2_CMPL, | ||||
| 				fw_ring_id, &val[0], &val[1]); | ||||
| 			cpr->missed_irqs++; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void bnxt_cfg_ntp_filters(struct bnxt *); | ||||
| 
 | ||||
| static void bnxt_sp_task(struct work_struct *work) | ||||
| @ -8930,6 +8993,9 @@ static void bnxt_sp_task(struct work_struct *work) | ||||
| 	if (test_and_clear_bit(BNXT_FLOW_STATS_SP_EVENT, &bp->sp_event)) | ||||
| 		bnxt_tc_flow_stats_work(bp); | ||||
| 
 | ||||
| 	if (test_and_clear_bit(BNXT_RING_COAL_NOW_SP_EVENT, &bp->sp_event)) | ||||
| 		bnxt_chk_missed_irq(bp); | ||||
| 
 | ||||
| 	/* These functions below will clear BNXT_STATE_IN_SP_TASK.  They
 | ||||
| 	 * must be the last functions to be called before exiting. | ||||
| 	 */ | ||||
| @ -10087,6 +10153,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | ||||
| 	} | ||||
| 
 | ||||
| 	bnxt_hwrm_func_qcfg(bp); | ||||
| 	bnxt_hwrm_vnic_qcaps(bp); | ||||
| 	bnxt_hwrm_port_led_qcaps(bp); | ||||
| 	bnxt_ethtool_init(bp); | ||||
| 	bnxt_dcb_init(bp); | ||||
| @ -10120,7 +10187,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | ||||
| 				    VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; | ||||
| 	} | ||||
| 
 | ||||
| 	bnxt_hwrm_vnic_qcaps(bp); | ||||
| 	if (bnxt_rfs_supported(bp)) { | ||||
| 		dev->hw_features |= NETIF_F_NTUPLE; | ||||
| 		if (bnxt_rfs_capable(bp)) { | ||||
|  | ||||
| @ -798,6 +798,8 @@ struct bnxt_cp_ring_info { | ||||
| 	u8			had_work_done:1; | ||||
| 	u8			has_more_work:1; | ||||
| 
 | ||||
| 	u32			last_cp_raw_cons; | ||||
| 
 | ||||
| 	struct bnxt_coal	rx_ring_coal; | ||||
| 	u64			rx_packets; | ||||
| 	u64			rx_bytes; | ||||
| @ -816,6 +818,7 @@ struct bnxt_cp_ring_info { | ||||
| 	dma_addr_t		hw_stats_map; | ||||
| 	u32			hw_stats_ctx_id; | ||||
| 	u64			rx_l4_csum_errors; | ||||
| 	u64			missed_irqs; | ||||
| 
 | ||||
| 	struct bnxt_ring_struct	cp_ring_struct; | ||||
| 
 | ||||
| @ -1527,6 +1530,7 @@ struct bnxt { | ||||
| #define BNXT_LINK_SPEED_CHNG_SP_EVENT	14 | ||||
| #define BNXT_FLOW_STATS_SP_EVENT	15 | ||||
| #define BNXT_UPDATE_PHY_SP_EVENT	16 | ||||
| #define BNXT_RING_COAL_NOW_SP_EVENT	17 | ||||
| 
 | ||||
| 	struct bnxt_hw_resc	hw_resc; | ||||
| 	struct bnxt_pf_info	pf; | ||||
|  | ||||
| @ -137,7 +137,7 @@ reset_coalesce: | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| #define BNXT_NUM_STATS	21 | ||||
| #define BNXT_NUM_STATS	22 | ||||
| 
 | ||||
| #define BNXT_RX_STATS_ENTRY(counter)	\ | ||||
| 	{ BNXT_RX_STATS_OFFSET(counter), __stringify(counter) } | ||||
| @ -384,6 +384,7 @@ static void bnxt_get_ethtool_stats(struct net_device *dev, | ||||
| 		for (k = 0; k < stat_fields; j++, k++) | ||||
| 			buf[j] = le64_to_cpu(hw_stats[k]); | ||||
| 		buf[j++] = cpr->rx_l4_csum_errors; | ||||
| 		buf[j++] = cpr->missed_irqs; | ||||
| 
 | ||||
| 		bnxt_sw_func_stats[RX_TOTAL_DISCARDS].counter += | ||||
| 			le64_to_cpu(cpr->hw_stats->rx_discard_pkts); | ||||
| @ -468,6 +469,8 @@ static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf) | ||||
| 			buf += ETH_GSTRING_LEN; | ||||
| 			sprintf(buf, "[%d]: rx_l4_csum_errors", i); | ||||
| 			buf += ETH_GSTRING_LEN; | ||||
| 			sprintf(buf, "[%d]: missed_irqs", i); | ||||
| 			buf += ETH_GSTRING_LEN; | ||||
| 		} | ||||
| 		for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++) { | ||||
| 			strcpy(buf, bnxt_sw_func_stats[i].string); | ||||
| @ -2942,8 +2945,8 @@ bnxt_fill_coredump_record(struct bnxt *bp, struct bnxt_coredump_record *record, | ||||
| 	record->asic_state = 0; | ||||
| 	strlcpy(record->system_name, utsname()->nodename, | ||||
| 		sizeof(record->system_name)); | ||||
| 	record->year = cpu_to_le16(tm.tm_year); | ||||
| 	record->month = cpu_to_le16(tm.tm_mon); | ||||
| 	record->year = cpu_to_le16(tm.tm_year + 1900); | ||||
| 	record->month = cpu_to_le16(tm.tm_mon + 1); | ||||
| 	record->day = cpu_to_le16(tm.tm_mday); | ||||
| 	record->hour = cpu_to_le16(tm.tm_hour); | ||||
| 	record->minute = cpu_to_le16(tm.tm_min); | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user