Cross-merge networking fixes after downstream PR. No conflicts or adjacent changes.
Unified · Split
| @@ -2161,6 +2161,19 @@ N: Mike Kravetz · 2160 unmodified lines | ||
| 2161 | 2161 | E: mike.kravetz@oracle.com |
| 2162 | 2162 | D: Maintenance and development of the hugetlb subsystem |
| 2163 | 2163 | |
| 2164 | +N: Seth Jennings | |
| 2165 | +E: sjenning@redhat.com | |
| 2166 | +D: Creation and maintenance of zswap | |
| 2167 | + | |
| 2168 | +N: Dan Streetman | |
| 2169 | +E: ddstreet@ieee.org | |
| 2170 | +D: Maintenance and development of zswap | |
| 2171 | +D: Creation and maintenance of the zpool API | |
| 2172 | + | |
| 2173 | +N: Vitaly Wool | |
| 2174 | +E: vitaly.wool@konsulko.com | |
| 2175 | +D: Maintenance and development of zswap | |
| 2176 | + | |
| 2164 | 2177 | N: Andreas S. Krebs |
| 2165 | 2178 | E: akrebs@altavista.net |
| 2166 | 2179 | D: CYPRESS CY82C693 chipset IDE, Digital's PC-Alpha 164SX boards |
| @@ -1,4 +1,4 @@ | ||
| 1 | −What: /sys/class/<iface>/queues/rx-<queue>/rps_cpus | |
| 1 | +What: /sys/class/net/<iface>/queues/rx-<queue>/rps_cpus | |
| 2 | 2 | Date: March 2010 |
| 3 | 3 | KernelVersion: 2.6.35 |
| 4 | 4 | Contact: netdev@vger.kernel.org |
| @@ -8,7 +8,7 @@ Description: · 3 unmodified lines | ||
| 8 | 8 | network device queue. Possible values depend on the number |
| 9 | 9 | of available CPU(s) in the system. |
| 10 | 10 | |
| 11 | −What: /sys/class/<iface>/queues/rx-<queue>/rps_flow_cnt | |
| 11 | +What: /sys/class/net/<iface>/queues/rx-<queue>/rps_flow_cnt | |
| 12 | 12 | Date: April 2010 |
| 13 | 13 | KernelVersion: 2.6.35 |
| 14 | 14 | Contact: netdev@vger.kernel.org |
| @@ -16,7 +16,7 @@ Description: · 1 unmodified line | ||
| 16 | 16 | Number of Receive Packet Steering flows being currently |
| 17 | 17 | processed by this particular network device receive queue. |
| 18 | 18 | |
| 19 | −What: /sys/class/<iface>/queues/tx-<queue>/tx_timeout | |
| 19 | +What: /sys/class/net/<iface>/queues/tx-<queue>/tx_timeout | |
| 20 | 20 | Date: November 2011 |
| 21 | 21 | KernelVersion: 3.3 |
| 22 | 22 | Contact: netdev@vger.kernel.org |
| @@ -24,7 +24,7 @@ Description: · 1 unmodified line | ||
| 24 | 24 | Indicates the number of transmit timeout events seen by this |
| 25 | 25 | network interface transmit queue. |
| 26 | 26 | |
| 27 | −What: /sys/class/<iface>/queues/tx-<queue>/tx_maxrate | |
| 27 | +What: /sys/class/net/<iface>/queues/tx-<queue>/tx_maxrate | |
| 28 | 28 | Date: March 2015 |
| 29 | 29 | KernelVersion: 4.1 |
| 30 | 30 | Contact: netdev@vger.kernel.org |
| @@ -32,7 +32,7 @@ Description: · 1 unmodified line | ||
| 32 | 32 | A Mbps max-rate set for the queue, a value of zero means disabled, |
| 33 | 33 | default is disabled. |
| 34 | 34 | |
| 35 | −What: /sys/class/<iface>/queues/tx-<queue>/xps_cpus | |
| 35 | +What: /sys/class/net/<iface>/queues/tx-<queue>/xps_cpus | |
| 36 | 36 | Date: November 2010 |
| 37 | 37 | KernelVersion: 2.6.38 |
| 38 | 38 | Contact: netdev@vger.kernel.org |
| @@ -42,7 +42,7 @@ Description: · 3 unmodified lines | ||
| 42 | 42 | network device transmit queue. Possible values depend on the |
| 43 | 43 | number of available CPU(s) in the system. |
| 44 | 44 | |
| 45 | −What: /sys/class/<iface>/queues/tx-<queue>/xps_rxqs | |
| 45 | +What: /sys/class/net/<iface>/queues/tx-<queue>/xps_rxqs | |
| 46 | 46 | Date: June 2018 |
| 47 | 47 | KernelVersion: 4.18.0 |
| 48 | 48 | Contact: netdev@vger.kernel.org |
| @@ -53,7 +53,7 @@ Description: · 4 unmodified lines | ||
| 53 | 53 | number of available receive queue(s) in the network device. |
| 54 | 54 | Default is disabled. |
| 55 | 55 | |
| 56 | −What: /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/hold_time | |
| 56 | +What: /sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/hold_time | |
| 57 | 57 | Date: November 2011 |
| 58 | 58 | KernelVersion: 3.3 |
| 59 | 59 | Contact: netdev@vger.kernel.org |
| @@ -62,7 +62,7 @@ Description: · 2 unmodified lines | ||
| 62 | 62 | of this particular network device transmit queue. |
| 63 | 63 | Default value is 1000. |
| 64 | 64 | |
| 65 | −What: /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/inflight | |
| 65 | +What: /sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/inflight | |
| 66 | 66 | Date: November 2011 |
| 67 | 67 | KernelVersion: 3.3 |
| 68 | 68 | Contact: netdev@vger.kernel.org |
| @@ -70,7 +70,7 @@ Description: · 1 unmodified line | ||
| 70 | 70 | Indicates the number of bytes (objects) in flight on this |
| 71 | 71 | network device transmit queue. |
| 72 | 72 | |
| 73 | −What: /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/limit | |
| 73 | +What: /sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/limit | |
| 74 | 74 | Date: November 2011 |
| 75 | 75 | KernelVersion: 3.3 |
| 76 | 76 | Contact: netdev@vger.kernel.org |
| @@ -79,7 +79,7 @@ Description: · 2 unmodified lines | ||
| 79 | 79 | on this network device transmit queue. This value is clamped |
| 80 | 80 | to be within the bounds defined by limit_max and limit_min. |
| 81 | 81 | |
| 82 | −What: /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/limit_max | |
| 82 | +What: /sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/limit_max | |
| 83 | 83 | Date: November 2011 |
| 84 | 84 | KernelVersion: 3.3 |
| 85 | 85 | Contact: netdev@vger.kernel.org |
| @@ -88,7 +88,7 @@ Description: · 2 unmodified lines | ||
| 88 | 88 | queued on this network device transmit queue. See |
| 89 | 89 | include/linux/dynamic_queue_limits.h for the default value. |
| 90 | 90 | |
| 91 | −What: /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/limit_min | |
| 91 | +What: /sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/limit_min | |
| 92 | 92 | Date: November 2011 |
| 93 | 93 | KernelVersion: 3.3 |
| 94 | 94 | Contact: netdev@vger.kernel.org |
| @@ -10,6 +10,7 @@ What: /sys/devices/platform/silicom-platform/power_cycle · 9 unmodified lines | ||
| 10 | 10 | Date: November 2023 |
| 11 | 11 | KernelVersion: 6.7 |
| 12 | 12 | Contact: Henry Shi <henrys@silicom-usa.com> |
| 13 | +Description: | |
| 13 | 14 | This file allow user to power cycle the platform. |
| 14 | 15 | Default value is 0; when set to 1, it powers down |
| 15 | 16 | the platform, waits 5 seconds, then powers on the |
| @@ -101,8 +101,8 @@ External References · 100 unmodified lines | ||
| 101 | 101 | email threads |
| 102 | 102 | ------------- |
| 103 | 103 | |
| 104 | −* `Initial discussion on the New subsystem for acceleration devices <https://lkml.org/lkml/2022/7/31/83>`_ - Oded Gabbay (2022) | |
| 105 | −* `patch-set to add the new subsystem <https://lkml.org/lkml/2022/10/22/544>`_ - Oded Gabbay (2022) | |
| 104 | +* `Initial discussion on the New subsystem for acceleration devices <https://lore.kernel.org/lkml/CAFCwf11=9qpNAepL7NL+YAV_QO=Wv6pnWPhKHKAepK3fNn+2Dg@mail.gmail.com/>`_ - Oded Gabbay (2022) | |
| 105 | +* `patch-set to add the new subsystem <https://lore.kernel.org/lkml/20221022214622.18042-1-ogabbay@kernel.org/>`_ - Oded Gabbay (2022) | |
| 106 | 106 | |
| 107 | 107 | Conference talks |
| 108 | 108 | ---------------- |
| @@ -218,8 +218,3 @@ bytes respectively. Such letter suffixes can also be entirely omitted: · 217 unmodified lines | ||
| 218 | 218 | |
| 219 | 219 | .. include:: kernel-parameters.txt |
| 220 | 220 | :literal: |
| 221 | − | |
| 222 | −Todo | |
| 223 | −---- | |
| 224 | − | |
| 225 | − Add more DRM drivers. | |
| @@ -243,13 +243,9 @@ To reduce its OS jitter, do any of the following: · 242 unmodified lines | ||
| 243 | 243 | 3. Do any of the following needed to avoid jitter that your |
| 244 | 244 | application cannot tolerate: |
| 245 | 245 | |
| 246 | − a. Build your kernel with CONFIG_SLUB=y rather than | |
| 247 | − CONFIG_SLAB=y, thus avoiding the slab allocator's periodic | |
| 248 | − use of each CPU's workqueues to run its cache_reap() | |
| 249 | − function. | |
| 250 | − b. Avoid using oprofile, thus avoiding OS jitter from | |
| 246 | + a. Avoid using oprofile, thus avoiding OS jitter from | |
| 251 | 247 | wq_sync_buffer(). |
| 252 | − c. Limit your CPU frequency so that a CPU-frequency | |
| 248 | + b. Limit your CPU frequency so that a CPU-frequency | |
| 253 | 249 | governor is not required, possibly enlisting the aid of |
| 254 | 250 | special heatsinks or other cooling technologies. If done |
| 255 | 251 | correctly, and if you CPU architecture permits, you should |
| @@ -259,7 +255,7 @@ To reduce its OS jitter, do any of the following: · 3 unmodified lines | ||
| 259 | 255 | |
| 260 | 256 | WARNING: Please check your CPU specifications to |
| 261 | 257 | make sure that this is safe on your particular system. |
| 262 | − d. As of v3.18, Christoph Lameter's on-demand vmstat workers | |
| 258 | + c. As of v3.18, Christoph Lameter's on-demand vmstat workers | |
| 263 | 259 | commit prevents OS jitter due to vmstat_update() on |
| 264 | 260 | CONFIG_SMP=y systems. Before v3.18, is not possible |
| 265 | 261 | to entirely get rid of the OS jitter, but you can |
| @@ -274,7 +270,7 @@ To reduce its OS jitter, do any of the following: · 8 unmodified lines | ||
| 274 | 270 | (based on an earlier one from Gilad Ben-Yossef) that |
| 275 | 271 | reduces or even eliminates vmstat overhead for some |
| 276 | 272 | workloads at https://lore.kernel.org/r/00000140e9dfd6bd-40db3d4f-c1be-434f-8132-7820f81bb586-000000@email.amazonses.com. |
| 277 | − e. If running on high-end powerpc servers, build with | |
| 273 | + d. If running on high-end powerpc servers, build with | |
| 278 | 274 | CONFIG_PPC_RTAS_DAEMON=n. This prevents the RTAS |
| 279 | 275 | daemon from running on each CPU every second or so. |
| 280 | 276 | (This will require editing Kconfig files and will defeat |
| @@ -282,12 +278,12 @@ To reduce its OS jitter, do any of the following: · 1 unmodified line | ||
| 282 | 278 | due to the rtas_event_scan() function. |
| 283 | 279 | WARNING: Please check your CPU specifications to |
| 284 | 280 | make sure that this is safe on your particular system. |
| 285 | − f. If running on Cell Processor, build your kernel with | |
| 281 | + e. If running on Cell Processor, build your kernel with | |
| 286 | 282 | CBE_CPUFREQ_SPU_GOVERNOR=n to avoid OS jitter from |
| 287 | 283 | spu_gov_work(). |
| 288 | 284 | WARNING: Please check your CPU specifications to |
| 289 | 285 | make sure that this is safe on your particular system. |
| 290 | − g. If running on PowerMAC, build your kernel with | |
| 286 | + f. If running on PowerMAC, build your kernel with | |
| 291 | 287 | CONFIG_PMAC_RACKMETER=n to disable the CPU-meter, |
| 292 | 288 | avoiding OS jitter from rackmeter_do_timer(). |
| 293 | 289 | |
| @@ -671,8 +671,23 @@ Testing Static Functions · 670 unmodified lines | ||
| 671 | 671 | ------------------------ |
| 672 | 672 | |
| 673 | 673 | If we do not want to expose functions or variables for testing, one option is to |
| 674 | −conditionally ``#include`` the test file at the end of your .c file. For | |
| 675 | −example: | |
| 674 | +conditionally export the used symbol. For example: | |
| 675 | + | |
| 676 | +.. code-block:: c | |
| 677 | + | |
| 678 | + /* In my_file.c */ | |
| 679 | + | |
| 680 | + VISIBLE_IF_KUNIT int do_interesting_thing(); | |
| 681 | + EXPORT_SYMBOL_IF_KUNIT(do_interesting_thing); | |
| 682 | + | |
| 683 | + /* In my_file.h */ | |
| 684 | + | |
| 685 | + #if IS_ENABLED(CONFIG_KUNIT) | |
| 686 | + int do_interesting_thing(void); | |
| 687 | + #endif | |
| 688 | + | |
| 689 | +Alternatively, you could conditionally ``#include`` the test file at the end of | |
| 690 | +your .c file. For example: | |
| 676 | 691 | |
| 677 | 692 | .. code-block:: c |
| 678 | 693 | |
| @@ -85,7 +85,7 @@ allOf: · 84 unmodified lines | ||
| 85 | 85 | clocks: |
| 86 | 86 | minItems: 6 |
| 87 | 87 | maxItems: 6 |
| 88 | − regs: | |
| 88 | + reg: | |
| 89 | 89 | minItems: 2 |
| 90 | 90 | maxItems: 2 |
| 91 | 91 | |
| @@ -99,7 +99,7 @@ allOf: · 7 unmodified lines | ||
| 99 | 99 | clocks: |
| 100 | 100 | minItems: 4 |
| 101 | 101 | maxItems: 4 |
| 102 | − regs: | |
| 102 | + reg: | |
| 103 | 103 | minItems: 2 |
| 104 | 104 | maxItems: 2 |
| 105 | 105 | |
| @@ -116,7 +116,7 @@ allOf: · 10 unmodified lines | ||
| 116 | 116 | clocks: |
| 117 | 117 | minItems: 3 |
| 118 | 118 | maxItems: 3 |
| 119 | − regs: | |
| 119 | + reg: | |
| 120 | 120 | minItems: 1 |
| 121 | 121 | maxItems: 1 |
| 122 | 122 | |
| @@ -17,7 +17,7 @@ properties: · 16 unmodified lines | ||
| 17 | 17 | compatible: |
| 18 | 18 | items: |
| 19 | 19 | - enum: |
| 20 | − - ti,k3-j721s2-wave521c | |
| 20 | + - ti,j721s2-wave521c | |
| 21 | 21 | - const: cnm,wave521c |
| 22 | 22 | |
| 23 | 23 | reg: |
| @@ -53,7 +53,7 @@ additionalProperties: false · 29 unmodified lines | ||
| 53 | 53 | examples: |
| 54 | 54 | - | |
| 55 | 55 | vpu: video-codec@12345678 { |
| 56 | − compatible = "ti,k3-j721s2-wave521c", "cnm,wave521c"; | |
| 56 | + compatible = "ti,j721s2-wave521c", "cnm,wave521c"; | |
| 57 | 57 | reg = <0x12345678 0x1000>; |
| 58 | 58 | clocks = <&clks 42>; |
| 59 | 59 | interrupts = <42>; |
| @@ -942,6 +942,10 @@ attribute-sets: · 941 unmodified lines | ||
| 942 | 942 | - |
| 943 | 943 | name: gro-ipv4-max-size |
| 944 | 944 | type: u32 |
| 945 | + - | |
| 946 | + name: dpll-pin | |
| 947 | + type: nest | |
| 948 | + nested-attributes: link-dpll-pin-attrs | |
| 945 | 949 | - |
| 946 | 950 | name: af-spec-attrs |
| 947 | 951 | attributes: |
| @@ -1627,6 +1631,12 @@ attribute-sets: · 679 unmodified lines | ||
| 1627 | 1631 | - |
| 1628 | 1632 | name: used |
| 1629 | 1633 | type: u8 |
| 1634 | + - | |
| 1635 | + name: link-dpll-pin-attrs | |
| 1636 | + attributes: | |
| 1637 | + - | |
| 1638 | + name: id | |
| 1639 | + type: u32 | |
| 1630 | 1640 | |
| 1631 | 1641 | sub-messages: |
| 1632 | 1642 | - |
| @@ -12,5 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | <script type="text/javascript"> <!-- |
| 13 | 13 | var sbar = document.getElementsByClassName("sphinxsidebar")[0]; |
| 14 | 14 | let currents = document.getElementsByClassName("current") |
| 15 | − sbar.scrollTop = currents[currents.length - 1].offsetTop; | |
| 15 | + if (currents.length) { | |
| 16 | + sbar.scrollTop = currents[currents.length - 1].offsetTop; | |
| 17 | + } | |
| 16 | 18 | --> </script> |
| @@ -3168,10 +3168,10 @@ F: drivers/hwmon/asus-ec-sensors.c · 3167 unmodified lines | ||
| 3168 | 3168 | |
| 3169 | 3169 | ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS |
| 3170 | 3170 | M: Corentin Chary <corentin.chary@gmail.com> |
| 3171 | −L: acpi4asus-user@lists.sourceforge.net | |
| 3171 | +M: Luke D. Jones <luke@ljones.dev> | |
| 3172 | 3172 | L: platform-driver-x86@vger.kernel.org |
| 3173 | 3173 | S: Maintained |
| 3174 | −W: http://acpi4asus.sf.net | |
| 3174 | +W: https://asus-linux.org/ | |
| 3175 | 3175 | F: drivers/platform/x86/asus*.c |
| 3176 | 3176 | F: drivers/platform/x86/eeepc*.c |
| 3177 | 3177 | |
| @@ -5961,7 +5961,6 @@ S: Maintained · 2783 unmodified lines | ||
| 5961 | 5961 | F: drivers/platform/x86/dell/dell-wmi-descriptor.c |
| 5962 | 5962 | |
| 5963 | 5963 | DELL WMI HARDWARE PRIVACY SUPPORT |
| 5964 | −M: Perry Yuan <Perry.Yuan@dell.com> | |
| 5965 | 5964 | L: Dell.Client.Kernel@dell.com |
| 5966 | 5965 | L: platform-driver-x86@vger.kernel.org |
| 5967 | 5966 | S: Maintained |
| @@ -10287,7 +10286,7 @@ F: drivers/scsi/ibmvscsi/ibmvscsi* · 4319 unmodified lines | ||
| 10287 | 10286 | F: include/scsi/viosrp.h |
| 10288 | 10287 | |
| 10289 | 10288 | IBM Power Virtual SCSI Device Target Driver |
| 10290 | −M: Michael Cyr <mikecyr@linux.ibm.com> | |
| 10289 | +M: Tyrel Datwyler <tyreld@linux.ibm.com> | |
| 10291 | 10290 | L: linux-scsi@vger.kernel.org |
| 10292 | 10291 | L: target-devel@vger.kernel.org |
| 10293 | 10292 | S: Supported |
| @@ -11729,6 +11728,7 @@ F: fs/smb/server/ · 1435 unmodified lines | ||
| 11729 | 11728 | KERNEL UNIT TESTING FRAMEWORK (KUnit) |
| 11730 | 11729 | M: Brendan Higgins <brendanhiggins@google.com> |
| 11731 | 11730 | M: David Gow <davidgow@google.com> |
| 11731 | +R: Rae Moar <rmoar@google.com> | |
| 11732 | 11732 | L: linux-kselftest@vger.kernel.org |
| 11733 | 11733 | L: kunit-dev@googlegroups.com |
| 11734 | 11734 | S: Maintained |
| @@ -12907,6 +12907,8 @@ M: Alejandro Colomar <alx@kernel.org> · 1172 unmodified lines | ||
| 12907 | 12907 | L: linux-man@vger.kernel.org |
| 12908 | 12908 | S: Maintained |
| 12909 | 12909 | W: http://www.kernel.org/doc/man-pages |
| 12910 | +T: git git://git.kernel.org/pub/scm/docs/man-pages/man-pages.git | |
| 12911 | +T: git git://www.alejandro-colomar.es/src/alx/linux/man-pages/man-pages.git | |
| 12910 | 12912 | |
| 12911 | 12913 | MANAGEMENT COMPONENT TRANSPORT PROTOCOL (MCTP) |
| 12912 | 12914 | M: Jeremy Kerr <jk@codeconstruct.com.au> |
| @@ -15182,6 +15184,7 @@ F: Documentation/networking/net_cachelines/net_device.rst · 2269 unmodified lines | ||
| 15182 | 15184 | F: drivers/connector/ |
| 15183 | 15185 | F: drivers/net/ |
| 15184 | 15186 | F: include/dt-bindings/net/ |
| 15187 | +F: include/linux/cn_proc.h | |
| 15185 | 15188 | F: include/linux/etherdevice.h |
| 15186 | 15189 | F: include/linux/fcdevice.h |
| 15187 | 15190 | F: include/linux/fddidevice.h |
| @@ -15189,6 +15192,7 @@ F: include/linux/hippidevice.h · 1 unmodified line | ||
| 15189 | 15192 | F: include/linux/if_* |
| 15190 | 15193 | F: include/linux/inetdevice.h |
| 15191 | 15194 | F: include/linux/netdevice.h |
| 15195 | +F: include/uapi/linux/cn_proc.h | |
| 15192 | 15196 | F: include/uapi/linux/if_* |
| 15193 | 15197 | F: include/uapi/linux/netdevice.h |
| 15194 | 15198 | X: drivers/net/wireless/ |
| @@ -18093,7 +18097,6 @@ F: drivers/net/ethernet/qualcomm/emac/ · 2898 unmodified lines | ||
| 18093 | 18097 | |
| 18094 | 18098 | QUALCOMM ETHQOS ETHERNET DRIVER |
| 18095 | 18099 | M: Vinod Koul <vkoul@kernel.org> |
| 18096 | −R: Bhupesh Sharma <bhupesh.sharma@linaro.org> | |
| 18097 | 18100 | L: netdev@vger.kernel.org |
| 18098 | 18101 | L: linux-arm-msm@vger.kernel.org |
| 18099 | 18102 | S: Maintained |
| @@ -20561,6 +20564,7 @@ F: Documentation/translations/sp_SP/ · 2461 unmodified lines | ||
| 20561 | 20564 | |
| 20562 | 20565 | SPARC + UltraSPARC (sparc/sparc64) |
| 20563 | 20566 | M: "David S. Miller" <davem@davemloft.net> |
| 20567 | +M: Andreas Larsson <andreas@gaisler.com> | |
| 20564 | 20568 | L: sparclinux@vger.kernel.org |
| 20565 | 20569 | S: Maintained |
| 20566 | 20570 | Q: http://patchwork.ozlabs.org/project/sparclinux/list/ |
| @@ -24351,13 +24355,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/zonefs.git · 3784 unmodified lines | ||
| 24351 | 24355 | F: Documentation/filesystems/zonefs.rst |
| 24352 | 24356 | F: fs/zonefs/ |
| 24353 | 24357 | |
| 24354 | −ZPOOL COMPRESSED PAGE STORAGE API | |
| 24355 | −M: Dan Streetman <ddstreet@ieee.org> | |
| 24356 | −L: linux-mm@kvack.org | |
| 24357 | −S: Maintained | |
| 24358 | −F: include/linux/zpool.h | |
| 24359 | −F: mm/zpool.c | |
| 24360 | − | |
| 24361 | 24358 | ZR36067 VIDEO FOR LINUX DRIVER |
| 24362 | 24359 | M: Corentin Labbe <clabbe@baylibre.com> |
| 24363 | 24360 | L: mjpeg-users@lists.sourceforge.net |
| @@ -24409,7 +24406,9 @@ M: Nhat Pham <nphamcs@gmail.com> · 45 unmodified lines | ||
| 24409 | 24406 | L: linux-mm@kvack.org |
| 24410 | 24407 | S: Maintained |
| 24411 | 24408 | F: Documentation/admin-guide/mm/zswap.rst |
| 24409 | +F: include/linux/zpool.h | |
| 24412 | 24410 | F: include/linux/zswap.h |
| 24411 | +F: mm/zpool.c | |
| 24413 | 24412 | F: mm/zswap.c |
| 24414 | 24413 | |
| 24415 | 24414 | THE REST |
| @@ -2,7 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | VERSION = 6 |
| 3 | 3 | PATCHLEVEL = 8 |
| 4 | 4 | SUBLEVEL = 0 |
| 5 | −EXTRAVERSION = -rc1 | |
| 5 | +EXTRAVERSION = -rc2 | |
| 6 | 6 | NAME = Hurr durr I'ma ninja sloth |
| 7 | 7 | |
| 8 | 8 | # *DOCUMENTATION* |
| @@ -294,15 +294,15 @@ may-sync-config := 1 · 285 unmodified lines | ||
| 294 | 294 | single-build := |
| 295 | 295 | |
| 296 | 296 | ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),) |
| 297 | − ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),) | |
| 297 | + ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),) | |
| 298 | 298 | need-config := |
| 299 | − endif | |
| 299 | + endif | |
| 300 | 300 | endif |
| 301 | 301 | |
| 302 | 302 | ifneq ($(filter $(no-sync-config-targets), $(MAKECMDGOALS)),) |
| 303 | − ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),) | |
| 303 | + ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),) | |
| 304 | 304 | may-sync-config := |
| 305 | − endif | |
| 305 | + endif | |
| 306 | 306 | endif |
| 307 | 307 | |
| 308 | 308 | need-compiler := $(may-sync-config) |
| @@ -323,9 +323,9 @@ endif · 14 unmodified lines | ||
| 323 | 323 | # We cannot build single targets and the others at the same time |
| 324 | 324 | ifneq ($(filter $(single-targets), $(MAKECMDGOALS)),) |
| 325 | 325 | single-build := 1 |
| 326 | − ifneq ($(filter-out $(single-targets), $(MAKECMDGOALS)),) | |
| 326 | + ifneq ($(filter-out $(single-targets), $(MAKECMDGOALS)),) | |
| 327 | 327 | mixed-build := 1 |
| 328 | − endif | |
| 328 | + endif | |
| 329 | 329 | endif |
| 330 | 330 | |
| 331 | 331 | # For "make -j clean all", "make -j mrproper defconfig all", etc. |
| @@ -1666,7 +1666,7 @@ help: · 1334 unmodified lines | ||
| 1666 | 1666 | @echo ' (sparse by default)' |
| 1667 | 1667 | @echo ' make C=2 [targets] Force check of all c source with $$CHECK' |
| 1668 | 1668 | @echo ' make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections' |
| 1669 | − @echo ' make W=n [targets] Enable extra build checks, n=1,2,3 where' | |
| 1669 | + @echo ' make W=n [targets] Enable extra build checks, n=1,2,3,c,e where' | |
| 1670 | 1670 | @echo ' 1: warnings which may be relevant and do not occur too often' |
| 1671 | 1671 | @echo ' 2: warnings which occur quite often but may still be relevant' |
| 1672 | 1672 | @echo ' 3: more obscure warnings, can most likely be ignored' |
| @@ -673,6 +673,7 @@ config SHADOW_CALL_STACK · 672 unmodified lines | ||
| 673 | 673 | bool "Shadow Call Stack" |
| 674 | 674 | depends on ARCH_SUPPORTS_SHADOW_CALL_STACK |
| 675 | 675 | depends on DYNAMIC_FTRACE_WITH_ARGS || DYNAMIC_FTRACE_WITH_REGS || !FUNCTION_GRAPH_TRACER |
| 676 | + depends on MMU | |
| 676 | 677 | help |
| 677 | 678 | This option enables the compiler's Shadow Call Stack, which |
| 678 | 679 | uses a shadow stack to protect function return addresses from |
| @@ -45,8 +45,8 @@ · 44 unmodified lines | ||
| 45 | 45 | num-chipselects = <1>; |
| 46 | 46 | cs-gpios = <&gpio0 ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>; |
| 47 | 47 | |
| 48 | − tpmdev@0 { | |
| 49 | − compatible = "tcg,tpm_tis-spi"; | |
| 48 | + tpm@0 { | |
| 49 | + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; | |
| 50 | 50 | spi-max-frequency = <33000000>; |
| 51 | 51 | reg = <0>; |
| 52 | 52 | }; |
| @@ -80,8 +80,8 @@ · 79 unmodified lines | ||
| 80 | 80 | gpio-miso = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_HIGH>; |
| 81 | 81 | num-chipselects = <1>; |
| 82 | 82 | |
| 83 | − tpmdev@0 { | |
| 84 | − compatible = "tcg,tpm_tis-spi"; | |
| 83 | + tpm@0 { | |
| 84 | + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; | |
| 85 | 85 | spi-max-frequency = <33000000>; |
| 86 | 86 | reg = <0>; |
| 87 | 87 | }; |
| @@ -456,7 +456,7 @@ · 455 unmodified lines | ||
| 456 | 456 | status = "okay"; |
| 457 | 457 | |
| 458 | 458 | tpm: tpm@2e { |
| 459 | − compatible = "tcg,tpm-tis-i2c"; | |
| 459 | + compatible = "nuvoton,npct75x", "tcg,tpm-tis-i2c"; | |
| 460 | 460 | reg = <0x2e>; |
| 461 | 461 | }; |
| 462 | 462 | }; |
| @@ -35,8 +35,8 @@ · 34 unmodified lines | ||
| 35 | 35 | gpio-mosi = <&gpio0 ASPEED_GPIO(X, 4) GPIO_ACTIVE_HIGH>; |
| 36 | 36 | gpio-miso = <&gpio0 ASPEED_GPIO(X, 5) GPIO_ACTIVE_HIGH>; |
| 37 | 37 | |
| 38 | − tpmdev@0 { | |
| 39 | − compatible = "tcg,tpm_tis-spi"; | |
| 38 | + tpm@0 { | |
| 39 | + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; | |
| 40 | 40 | spi-max-frequency = <33000000>; |
| 41 | 41 | reg = <0>; |
| 42 | 42 | }; |
| @@ -116,7 +116,7 @@ · 115 unmodified lines | ||
| 116 | 116 | tpm_tis: tpm@1 { |
| 117 | 117 | pinctrl-names = "default"; |
| 118 | 118 | pinctrl-0 = <&pinctrl_tpm>; |
| 119 | − compatible = "tcg,tpm_tis-spi"; | |
| 119 | + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; | |
| 120 | 120 | reg = <1>; |
| 121 | 121 | spi-max-frequency = <20000000>; |
| 122 | 122 | interrupt-parent = <&gpio5>; |
| @@ -130,7 +130,7 @@ · 129 unmodified lines | ||
| 130 | 130 | * TCG specification - Section 6.4.1 Clocking: |
| 131 | 131 | * TPM shall support a SPI clock frequency range of 10-24 MHz. |
| 132 | 132 | */ |
| 133 | − st33htph: tpm-tis@0 { | |
| 133 | + st33htph: tpm@0 { | |
| 134 | 134 | compatible = "st,st33htpm-spi", "tcg,tpm_tis-spi"; |
| 135 | 135 | reg = <0>; |
| 136 | 136 | spi-max-frequency = <24000000>; |
| @@ -434,6 +434,7 @@ · 433 unmodified lines | ||
| 434 | 434 | }; |
| 435 | 435 | |
| 436 | 436 | &fimd { |
| 437 | + samsung,invert-vclk; | |
| 437 | 438 | status = "okay"; |
| 438 | 439 | }; |
| 439 | 440 | |
| @@ -217,7 +217,7 @@ · 216 unmodified lines | ||
| 217 | 217 | pinctrl-names = "default"; |
| 218 | 218 | pinctrl-0 = <&spi1_pins>; |
| 219 | 219 | |
| 220 | − tpm_spi_tis@0 { | |
| 220 | + tpm@0 { | |
| 221 | 221 | compatible = "tcg,tpm_tis-spi"; |
| 222 | 222 | reg = <0>; |
| 223 | 223 | spi-max-frequency = <500000>; |
| @@ -289,7 +289,7 @@ · 288 unmodified lines | ||
| 289 | 289 | #clock-cells = <1>; |
| 290 | 290 | clocks = <&cmu_top CLK_DOUT_CMU_MISC_BUS>, |
| 291 | 291 | <&cmu_top CLK_DOUT_CMU_MISC_SSS>; |
| 292 | − clock-names = "dout_cmu_misc_bus", "dout_cmu_misc_sss"; | |
| 292 | + clock-names = "bus", "sss"; | |
| 293 | 293 | }; |
| 294 | 294 | |
| 295 | 295 | watchdog_cl0: watchdog@10060000 { |
| @@ -120,7 +120,7 @@ · 119 unmodified lines | ||
| 120 | 120 | }; |
| 121 | 121 | |
| 122 | 122 | tpm: tpm@1 { |
| 123 | − compatible = "tcg,tpm_tis-spi"; | |
| 123 | + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; | |
| 124 | 124 | interrupts = <11 IRQ_TYPE_LEVEL_LOW>; |
| 125 | 125 | interrupt-parent = <&gpio2>; |
| 126 | 126 | pinctrl-names = "default"; |
| @@ -89,7 +89,7 @@ · 88 unmodified lines | ||
| 89 | 89 | status = "okay"; |
| 90 | 90 | |
| 91 | 91 | tpm@1 { |
| 92 | − compatible = "tcg,tpm_tis-spi"; | |
| 92 | + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; | |
| 93 | 93 | reg = <0x1>; |
| 94 | 94 | spi-max-frequency = <36000000>; |
| 95 | 95 | }; |
| @@ -109,7 +109,7 @@ · 108 unmodified lines | ||
| 109 | 109 | status = "okay"; |
| 110 | 110 | |
| 111 | 111 | tpm@1 { |
| 112 | − compatible = "tcg,tpm_tis-spi"; | |
| 112 | + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; | |
| 113 | 113 | reg = <0x1>; |
| 114 | 114 | spi-max-frequency = <36000000>; |
| 115 | 115 | }; |
| @@ -234,7 +234,7 @@ · 233 unmodified lines | ||
| 234 | 234 | status = "okay"; |
| 235 | 235 | |
| 236 | 236 | tpm: tpm@0 { |
| 237 | − compatible = "infineon,slb9670"; | |
| 237 | + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; | |
| 238 | 238 | reg = <0>; |
| 239 | 239 | pinctrl-names = "default"; |
| 240 | 240 | pinctrl-0 = <&pinctrl_tpm>; |
| @@ -103,7 +103,7 @@ · 102 unmodified lines | ||
| 103 | 103 | status = "okay"; |
| 104 | 104 | |
| 105 | 105 | tpm@1 { |
| 106 | − compatible = "tcg,tpm_tis-spi"; | |
| 106 | + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; | |
| 107 | 107 | reg = <0x1>; |
| 108 | 108 | spi-max-frequency = <36000000>; |
| 109 | 109 | }; |
| @@ -115,7 +115,7 @@ · 114 unmodified lines | ||
| 115 | 115 | status = "okay"; |
| 116 | 116 | |
| 117 | 117 | tpm@1 { |
| 118 | − compatible = "tcg,tpm_tis-spi"; | |
| 118 | + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; | |
| 119 | 119 | reg = <0x1>; |
| 120 | 120 | spi-max-frequency = <36000000>; |
| 121 | 121 | }; |
| @@ -196,7 +196,7 @@ · 195 unmodified lines | ||
| 196 | 196 | status = "okay"; |
| 197 | 197 | |
| 198 | 198 | tpm@0 { |
| 199 | − compatible = "tcg,tpm_tis-spi"; | |
| 199 | + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; | |
| 200 | 200 | reg = <0x0>; |
| 201 | 201 | spi-max-frequency = <36000000>; |
| 202 | 202 | }; |
| @@ -65,7 +65,7 @@ · 64 unmodified lines | ||
| 65 | 65 | status = "okay"; |
| 66 | 66 | |
| 67 | 67 | tpm@0 { |
| 68 | − compatible = "infineon,slb9670"; | |
| 68 | + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; | |
| 69 | 69 | reg = <0>; |
| 70 | 70 | spi-max-frequency = <43000000>; |
| 71 | 71 | }; |
| @@ -888,7 +888,7 @@ · 887 unmodified lines | ||
| 888 | 888 | status = "okay"; |
| 889 | 889 | cs-gpios = <&pio 86 GPIO_ACTIVE_LOW>; |
| 890 | 890 | |
| 891 | − cr50@0 { | |
| 891 | + tpm@0 { | |
| 892 | 892 | compatible = "google,cr50"; |
| 893 | 893 | reg = <0>; |
| 894 | 894 | spi-max-frequency = <1000000>; |
| @@ -1402,7 +1402,7 @@ · 1401 unmodified lines | ||
| 1402 | 1402 | pinctrl-names = "default"; |
| 1403 | 1403 | pinctrl-0 = <&spi5_pins>; |
| 1404 | 1404 | |
| 1405 | − cr50@0 { | |
| 1405 | + tpm@0 { | |
| 1406 | 1406 | compatible = "google,cr50"; |
| 1407 | 1407 | reg = <0>; |
| 1408 | 1408 | interrupts-extended = <&pio 171 IRQ_TYPE_EDGE_RISING>; |
| @@ -70,7 +70,7 @@ · 69 unmodified lines | ||
| 70 | 70 | &spi0 { |
| 71 | 71 | status = "okay"; |
| 72 | 72 | |
| 73 | − cr50@0 { | |
| 73 | + tpm@0 { | |
| 74 | 74 | compatible = "google,cr50"; |
| 75 | 75 | reg = <0>; |
| 76 | 76 | interrupt-parent = <&gpio0>; |
| @@ -706,7 +706,7 @@ camera: &i2c7 { · 705 unmodified lines | ||
| 706 | 706 | &spi2 { |
| 707 | 707 | status = "okay"; |
| 708 | 708 | |
| 709 | − cr50@0 { | |
| 709 | + tpm@0 { | |
| 710 | 710 | compatible = "google,cr50"; |
| 711 | 711 | reg = <0>; |
| 712 | 712 | interrupt-parent = <&gpio1>; |
| @@ -60,7 +60,7 @@ int kvm_own_lsx(struct kvm_vcpu *vcpu); · 59 unmodified lines | ||
| 60 | 60 | void kvm_save_lsx(struct loongarch_fpu *fpu); |
| 61 | 61 | void kvm_restore_lsx(struct loongarch_fpu *fpu); |
| 62 | 62 | #else |
| 63 | −static inline int kvm_own_lsx(struct kvm_vcpu *vcpu) { } | |
| 63 | +static inline int kvm_own_lsx(struct kvm_vcpu *vcpu) { return -EINVAL; } | |
| 64 | 64 | static inline void kvm_save_lsx(struct loongarch_fpu *fpu) { } |
| 65 | 65 | static inline void kvm_restore_lsx(struct loongarch_fpu *fpu) { } |
| 66 | 66 | #endif |
| @@ -70,7 +70,7 @@ int kvm_own_lasx(struct kvm_vcpu *vcpu); · 3 unmodified lines | ||
| 70 | 70 | void kvm_save_lasx(struct loongarch_fpu *fpu); |
| 71 | 71 | void kvm_restore_lasx(struct loongarch_fpu *fpu); |
| 72 | 72 | #else |
| 73 | −static inline int kvm_own_lasx(struct kvm_vcpu *vcpu) { } | |
| 73 | +static inline int kvm_own_lasx(struct kvm_vcpu *vcpu) { return -EINVAL; } | |
| 74 | 74 | static inline void kvm_save_lasx(struct loongarch_fpu *fpu) { } |
| 75 | 75 | static inline void kvm_restore_lasx(struct loongarch_fpu *fpu) { } |
| 76 | 76 | #endif |
| @@ -509,7 +509,6 @@ asmlinkage void start_secondary(void) · 508 unmodified lines | ||
| 509 | 509 | sync_counter(); |
| 510 | 510 | cpu = raw_smp_processor_id(); |
| 511 | 511 | set_my_cpu_offset(per_cpu_offset(cpu)); |
| 512 | − rcutree_report_cpu_starting(cpu); | |
| 513 | 512 | |
| 514 | 513 | cpu_probe(); |
| 515 | 514 | constant_clockevent_init(); |
| @@ -675,7 +675,7 @@ static bool fault_supports_huge_mapping(struct kvm_memory_slot *memslot, · 674 unmodified lines | ||
| 675 | 675 | * |
| 676 | 676 | * There are several ways to safely use this helper: |
| 677 | 677 | * |
| 678 | − * - Check mmu_invalidate_retry_hva() after grabbing the mapping level, before | |
| 678 | + * - Check mmu_invalidate_retry_gfn() after grabbing the mapping level, before | |
| 679 | 679 | * consuming it. In this case, mmu_lock doesn't need to be held during the |
| 680 | 680 | * lookup, but it does need to be held while checking the MMU notifier. |
| 681 | 681 | * |
| @@ -855,7 +855,7 @@ retry: · 173 unmodified lines | ||
| 855 | 855 | |
| 856 | 856 | /* Check if an invalidation has taken place since we got pfn */ |
| 857 | 857 | spin_lock(&kvm->mmu_lock); |
| 858 | − if (mmu_invalidate_retry_hva(kvm, mmu_seq, hva)) { | |
| 858 | + if (mmu_invalidate_retry_gfn(kvm, mmu_seq, gfn)) { | |
| 859 | 859 | /* |
| 860 | 860 | * This can happen when mappings are changed asynchronously, but |
| 861 | 861 | * also synchronously if a COW is triggered by |
| @@ -284,12 +284,16 @@ static void setup_tlb_handler(int cpu) · 283 unmodified lines | ||
| 284 | 284 | set_handler(EXCCODE_TLBNR * VECSIZE, handle_tlb_protect, VECSIZE); |
| 285 | 285 | set_handler(EXCCODE_TLBNX * VECSIZE, handle_tlb_protect, VECSIZE); |
| 286 | 286 | set_handler(EXCCODE_TLBPE * VECSIZE, handle_tlb_protect, VECSIZE); |
| 287 | − } | |
| 287 | + } else { | |
| 288 | + int vec_sz __maybe_unused; | |
| 289 | + void *addr __maybe_unused; | |
| 290 | + struct page *page __maybe_unused; | |
| 291 | + | |
| 292 | + /* Avoid lockdep warning */ | |
| 293 | + rcutree_report_cpu_starting(cpu); | |
| 294 | + | |
| 288 | 295 | #ifdef CONFIG_NUMA |
| 289 | − else { | |
| 290 | − void *addr; | |
| 291 | − struct page *page; | |
| 292 | − const int vec_sz = sizeof(exception_handlers); | |
| 296 | + vec_sz = sizeof(exception_handlers); | |
| 293 | 297 | |
| 294 | 298 | if (pcpu_handlers[cpu]) |
| 295 | 299 | return; |
| @@ -305,8 +309,8 @@ static void setup_tlb_handler(int cpu) · 9 unmodified lines | ||
| 305 | 309 | csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_EENTRY); |
| 306 | 310 | csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_MERRENTRY); |
| 307 | 311 | csr_write64(pcpu_handlers[cpu] + 80*VECSIZE, LOONGARCH_CSR_TLBRENTRY); |
| 308 | − } | |
| 309 | 312 | #endif |
| 313 | + } | |
| 310 | 314 | } |
| 311 | 315 | |
| 312 | 316 | void tlb_init(int cpu) |
| @@ -15,10 +15,10 @@ · 14 unmodified lines | ||
| 15 | 15 | KBUILD_DEFCONFIG := multi_defconfig |
| 16 | 16 | |
| 17 | 17 | ifdef cross_compiling |
| 18 | − ifeq ($(CROSS_COMPILE),) | |
| 18 | + ifeq ($(CROSS_COMPILE),) | |
| 19 | 19 | CROSS_COMPILE := $(call cc-cross-prefix, \ |
| 20 | 20 | m68k-linux-gnu- m68k-linux- m68k-unknown-linux-gnu-) |
| 21 | − endif | |
| 21 | + endif | |
| 22 | 22 | endif |
| 23 | 23 | |
| 24 | 24 | # |
| @@ -40,6 +40,7 @@ · 39 unmodified lines | ||
| 40 | 40 | #include <linux/string.h> |
| 41 | 41 | |
| 42 | 42 | #include <asm/bootinfo.h> |
| 43 | +#include <prom.h> | |
| 43 | 44 | |
| 44 | 45 | int prom_argc; |
| 45 | 46 | char **prom_argv; |
| @@ -30,13 +30,11 @@ · 29 unmodified lines | ||
| 30 | 30 | #include <linux/mm.h> |
| 31 | 31 | #include <linux/dma-map-ops.h> /* for dma_default_coherent */ |
| 32 | 32 | |
| 33 | +#include <asm/bootinfo.h> | |
| 33 | 34 | #include <asm/mipsregs.h> |
| 34 | 35 | |
| 35 | 36 | #include <au1000.h> |
| 36 | 37 | |
| 37 | −extern void __init board_setup(void); | |
| 38 | −extern void __init alchemy_set_lpj(void); | |
| 39 | − | |
| 40 | 38 | static bool alchemy_dma_coherent(void) |
| 41 | 39 | { |
| 42 | 40 | switch (alchemy_get_cputype()) { |
| @@ -702,7 +702,7 @@ static struct ssb_sprom bcm63xx_sprom = { · 701 unmodified lines | ||
| 702 | 702 | .boardflags_hi = 0x0000, |
| 703 | 703 | }; |
| 704 | 704 | |
| 705 | −int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out) | |
| 705 | +static int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out) | |
| 706 | 706 | { |
| 707 | 707 | if (bus->bustype == SSB_BUSTYPE_PCI) { |
| 708 | 708 | memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom)); |
| @@ -26,7 +26,7 @@ static struct platform_device bcm63xx_rng_device = { · 25 unmodified lines | ||
| 26 | 26 | .resource = rng_resources, |
| 27 | 27 | }; |
| 28 | 28 | |
| 29 | −int __init bcm63xx_rng_register(void) | |
| 29 | +static int __init bcm63xx_rng_register(void) | |
| 30 | 30 | { |
| 31 | 31 | if (!BCMCPU_IS_6368()) |
| 32 | 32 | return -ENODEV; |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/kernel.h> |
| 11 | 11 | #include <linux/platform_device.h> |
| 12 | 12 | #include <bcm63xx_cpu.h> |
| 13 | +#include <bcm63xx_dev_uart.h> | |
| 13 | 14 | |
| 14 | 15 | static struct resource uart0_resources[] = { |
| 15 | 16 | { |
| @@ -34,7 +34,7 @@ static struct platform_device bcm63xx_wdt_device = { · 33 unmodified lines | ||
| 34 | 34 | }, |
| 35 | 35 | }; |
| 36 | 36 | |
| 37 | −int __init bcm63xx_wdt_register(void) | |
| 37 | +static int __init bcm63xx_wdt_register(void) | |
| 38 | 38 | { |
| 39 | 39 | wdt_resources[0].start = bcm63xx_regset_address(RSET_WDT); |
| 40 | 40 | wdt_resources[0].end = wdt_resources[0].start; |
| @@ -72,7 +72,7 @@ static inline int enable_irq_for_cpu(int cpu, struct irq_data *d, · 71 unmodified lines | ||
| 72 | 72 | */ |
| 73 | 73 | |
| 74 | 74 | #define BUILD_IPIC_INTERNAL(width) \ |
| 75 | −void __dispatch_internal_##width(int cpu) \ | |
| 75 | +static void __dispatch_internal_##width(int cpu) \ | |
| 76 | 76 | { \ |
| 77 | 77 | u32 pending[width / 32]; \ |
| 78 | 78 | unsigned int src, tgt; \ |
| @@ -159,7 +159,7 @@ void __init plat_mem_setup(void) · 158 unmodified lines | ||
| 159 | 159 | board_setup(); |
| 160 | 160 | } |
| 161 | 161 | |
| 162 | −int __init bcm63xx_register_devices(void) | |
| 162 | +static int __init bcm63xx_register_devices(void) | |
| 163 | 163 | { |
| 164 | 164 | /* register gpiochip */ |
| 165 | 165 | bcm63xx_gpio_init(); |
| @@ -178,7 +178,7 @@ int bcm63xx_timer_set(int id, int monotonic, unsigned int countdown_us) · 177 unmodified lines | ||
| 178 | 178 | |
| 179 | 179 | EXPORT_SYMBOL(bcm63xx_timer_set); |
| 180 | 180 | |
| 181 | −int bcm63xx_timer_init(void) | |
| 181 | +static int bcm63xx_timer_init(void) | |
| 182 | 182 | { |
| 183 | 183 | int ret, irq; |
| 184 | 184 | u32 reg; |
| @@ -23,9 +23,6 @@ · 22 unmodified lines | ||
| 23 | 23 | |
| 24 | 24 | #include <cobalt.h> |
| 25 | 25 | |
| 26 | −extern void cobalt_machine_restart(char *command); | |
| 27 | −extern void cobalt_machine_halt(void); | |
| 28 | − | |
| 29 | 26 | const char *get_system_type(void) |
| 30 | 27 | { |
| 31 | 28 | switch (cobalt_board_id) { |
| @@ -37,7 +37,7 @@ static unsigned int nr_prom_mem __initdata; · 36 unmodified lines | ||
| 37 | 37 | */ |
| 38 | 38 | #define ARC_PAGE_SHIFT 12 |
| 39 | 39 | |
| 40 | −struct linux_mdesc * __init ArcGetMemoryDescriptor(struct linux_mdesc *Current) | |
| 40 | +static struct linux_mdesc * __init ArcGetMemoryDescriptor(struct linux_mdesc *Current) | |
| 41 | 41 | { |
| 42 | 42 | return (struct linux_mdesc *) ARC_CALL1(get_mdesc, Current); |
| 43 | 43 | } |
| @@ -597,6 +597,9 @@ · 596 unmodified lines | ||
| 597 | 597 | |
| 598 | 598 | #include <asm/cpu.h> |
| 599 | 599 | |
| 600 | +void alchemy_set_lpj(void); | |
| 601 | +void board_setup(void); | |
| 602 | + | |
| 600 | 603 | /* helpers to access the SYS_* registers */ |
| 601 | 604 | static inline unsigned long alchemy_rdsys(int regofs) |
| 602 | 605 | { |
| @@ -19,4 +19,7 @@ extern int cobalt_board_id; · 18 unmodified lines | ||
| 19 | 19 | #define COBALT_BRD_ID_QUBE2 0x5 |
| 20 | 20 | #define COBALT_BRD_ID_RAQ2 0x6 |
| 21 | 21 | |
| 22 | +void cobalt_machine_halt(void); | |
| 23 | +void cobalt_machine_restart(char *command); | |
| 24 | + | |
| 22 | 25 | #endif /* __ASM_COBALT_H */ |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | #include <asm/cpu-features.h> |
| 13 | 13 | #include <asm/cpu-info.h> |
| 14 | +#include <asm/fpu.h> | |
| 14 | 15 | |
| 15 | 16 | #ifdef CONFIG_MIPS_FP_SUPPORT |
| 16 | 17 | |
| @@ -309,6 +310,11 @@ void mips_set_personality_nan(struct arch_elf_state *state) · 292 unmodified lines | ||
| 309 | 310 | struct cpuinfo_mips *c = &boot_cpu_data; |
| 310 | 311 | struct task_struct *t = current; |
| 311 | 312 | |
| 313 | + /* Do this early so t->thread.fpu.fcr31 won't be clobbered in case | |
| 314 | + * we are preempted before the lose_fpu(0) in start_thread. | |
| 315 | + */ | |
| 316 | + lose_fpu(0); | |
| 317 | + | |
| 312 | 318 | t->thread.fpu.fcr31 = c->fpu_csr31; |
| 313 | 319 | switch (state->nan_2008) { |
| 314 | 320 | case 0: |
| @@ -2007,7 +2007,13 @@ unsigned long vi_handlers[64]; · 2006 unmodified lines | ||
| 2007 | 2007 | |
| 2008 | 2008 | void reserve_exception_space(phys_addr_t addr, unsigned long size) |
| 2009 | 2009 | { |
| 2010 | − memblock_reserve(addr, size); | |
| 2010 | + /* | |
| 2011 | + * reserve exception space on CPUs other than CPU0 | |
| 2012 | + * is too late, since memblock is unavailable when APs | |
| 2013 | + * up | |
| 2014 | + */ | |
| 2015 | + if (smp_processor_id() == 0) | |
| 2016 | + memblock_reserve(addr, size); | |
| 2011 | 2017 | } |
| 2012 | 2018 | |
| 2013 | 2019 | void __init *set_except_vector(int n, void *addr) |
| @@ -108,10 +108,9 @@ void __init prom_init(void) · 107 unmodified lines | ||
| 108 | 108 | prom_init_cmdline(); |
| 109 | 109 | |
| 110 | 110 | #if defined(CONFIG_MIPS_MT_SMP) |
| 111 | − if (cpu_has_mipsmt) { | |
| 112 | − lantiq_smp_ops = vsmp_smp_ops; | |
| 111 | + lantiq_smp_ops = vsmp_smp_ops; | |
| 112 | + if (cpu_has_mipsmt) | |
| 113 | 113 | lantiq_smp_ops.init_secondary = lantiq_init_secondary; |
| 114 | − register_smp_ops(&lantiq_smp_ops); | |
| 115 | − } | |
| 114 | + register_smp_ops(&lantiq_smp_ops); | |
| 116 | 115 | #endif |
| 117 | 116 | } |
| @@ -103,6 +103,9 @@ void __init szmem(unsigned int node) · 102 unmodified lines | ||
| 103 | 103 | if (loongson_sysconf.vgabios_addr) |
| 104 | 104 | memblock_reserve(virt_to_phys((void *)loongson_sysconf.vgabios_addr), |
| 105 | 105 | SZ_256K); |
| 106 | + /* set nid for reserved memory */ | |
| 107 | + memblock_set_node((u64)node << 44, (u64)(node + 1) << 44, | |
| 108 | + &memblock.reserved, node); | |
| 106 | 109 | } |
| 107 | 110 | |
| 108 | 111 | #ifndef CONFIG_NUMA |
| @@ -132,6 +132,8 @@ static void __init node_mem_init(unsigned int node) · 131 unmodified lines | ||
| 132 | 132 | |
| 133 | 133 | /* Reserve pfn range 0~node[0]->node_start_pfn */ |
| 134 | 134 | memblock_reserve(0, PAGE_SIZE * start_pfn); |
| 135 | + /* set nid for reserved memory on node 0 */ | |
| 136 | + memblock_set_node(0, 1ULL << 44, &memblock.reserved, 0); | |
| 135 | 137 | } |
| 136 | 138 | } |
| 137 | 139 | |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | |
| 6 | 6 | obj-y := ip27-berr.o ip27-irq.o ip27-init.o ip27-klconfig.o \ |
| 7 | 7 | ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-reset.o ip27-timer.o \ |
| 8 | − ip27-hubio.o ip27-xtalk.o | |
| 8 | + ip27-xtalk.o | |
| 9 | 9 | |
| 10 | 10 | obj-$(CONFIG_EARLY_PRINTK) += ip27-console.o |
| 11 | 11 | obj-$(CONFIG_SMP) += ip27-smp.o |
| @@ -22,6 +22,8 @@ · 21 unmodified lines | ||
| 22 | 22 | #include <asm/traps.h> |
| 23 | 23 | #include <linux/uaccess.h> |
| 24 | 24 | |
| 25 | +#include "ip27-common.h" | |
| 26 | + | |
| 25 | 27 | static void dump_hub_information(unsigned long errst0, unsigned long errst1) |
| 26 | 28 | { |
| 27 | 29 | static char *err_type[2][8] = { |
| @@ -57,7 +59,7 @@ static void dump_hub_information(unsigned long errst0, unsigned long errst1) · 29 unmodified lines | ||
| 57 | 59 | [st0.pi_stat0_fmt.s0_err_type] ? : "invalid"); |
| 58 | 60 | } |
| 59 | 61 | |
| 60 | −int ip27_be_handler(struct pt_regs *regs, int is_fixup) | |
| 62 | +static int ip27_be_handler(struct pt_regs *regs, int is_fixup) | |
| 61 | 63 | { |
| 62 | 64 | unsigned long errst0, errst1; |
| 63 | 65 | int data = regs->cp0_cause & 4; |
| @@ -10,6 +10,7 @@ extern void hub_rt_clock_event_init(void); · 9 unmodified lines | ||
| 10 | 10 | extern void hub_rtc_init(nasid_t nasid); |
| 11 | 11 | extern void install_cpu_nmi_handler(int slice); |
| 12 | 12 | extern void install_ipi(void); |
| 13 | +extern void ip27_be_init(void); | |
| 13 | 14 | extern void ip27_reboot_setup(void); |
| 14 | 15 | extern const struct plat_smp_ops ip27_smp_ops; |
| 15 | 16 | extern unsigned long node_getfirstfree(nasid_t nasid); |
| @@ -17,4 +18,5 @@ extern void per_cpu_init(void); · 1 unmodified line | ||
| 17 | 18 | extern void replicate_kernel_text(void); |
| 18 | 19 | extern void setup_replication_mask(void); |
| 19 | 20 | |
| 21 | + | |
| 20 | 22 | #endif /* __IP27_COMMON_H */ |
| @@ -1,185 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −/* | |
| 3 | − * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. | |
| 4 | − * Copyright (C) 2004 Christoph Hellwig. | |
| 5 | − * | |
| 6 | − * Support functions for the HUB ASIC - mostly PIO mapping related. | |
| 7 | − */ | |
| 8 | − | |
| 9 | −#include <linux/bitops.h> | |
| 10 | −#include <linux/string.h> | |
| 11 | −#include <linux/mmzone.h> | |
| 12 | −#include <asm/sn/addrs.h> | |
| 13 | −#include <asm/sn/arch.h> | |
| 14 | −#include <asm/sn/agent.h> | |
| 15 | −#include <asm/sn/io.h> | |
| 16 | −#include <asm/xtalk/xtalk.h> | |
| 17 | − | |
| 18 | − | |
| 19 | −static int force_fire_and_forget = 1; | |
| 20 | − | |
| 21 | −/** | |
| 22 | − * hub_pio_map - establish a HUB PIO mapping | |
| 23 | − * | |
| 24 | − * @nasid: nasid to perform PIO mapping on | |
| 25 | − * @widget: widget ID to perform PIO mapping for | |
| 26 | − * @xtalk_addr: xtalk_address that needs to be mapped | |
| 27 | − * @size: size of the PIO mapping | |
| 28 | − * | |
| 29 | − **/ | |
| 30 | −unsigned long hub_pio_map(nasid_t nasid, xwidgetnum_t widget, | |
| 31 | − unsigned long xtalk_addr, size_t size) | |
| 32 | −{ | |
| 33 | − unsigned i; | |
| 34 | − | |
| 35 | − /* use small-window mapping if possible */ | |
| 36 | − if ((xtalk_addr % SWIN_SIZE) + size <= SWIN_SIZE) | |
| 37 | − return NODE_SWIN_BASE(nasid, widget) + (xtalk_addr % SWIN_SIZE); | |
| 38 | − | |
| 39 | − if ((xtalk_addr % BWIN_SIZE) + size > BWIN_SIZE) { | |
| 40 | − printk(KERN_WARNING "PIO mapping at hub %d widget %d addr 0x%lx" | |
| 41 | − " too big (%ld)\n", | |
| 42 | − nasid, widget, xtalk_addr, size); | |
| 43 | − return 0; | |
| 44 | − } | |
| 45 | − | |
| 46 | − xtalk_addr &= ~(BWIN_SIZE-1); | |
| 47 | − for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) { | |
| 48 | − if (test_and_set_bit(i, hub_data(nasid)->h_bigwin_used)) | |
| 49 | − continue; | |
| 50 | − | |
| 51 | − /* | |
| 52 | − * The code below does a PIO write to setup an ITTE entry. | |
| 53 | − * | |
| 54 | − * We need to prevent other CPUs from seeing our updated | |
| 55 | − * memory shadow of the ITTE (in the piomap) until the ITTE | |
| 56 | − * entry is actually set up; otherwise, another CPU might | |
| 57 | − * attempt a PIO prematurely. | |
| 58 | − * | |
| 59 | − * Also, the only way we can know that an entry has been | |
| 60 | − * received by the hub and can be used by future PIO reads/ | |
| 61 | − * writes is by reading back the ITTE entry after writing it. | |
| 62 | − * | |
| 63 | − * For these two reasons, we PIO read back the ITTE entry | |
| 64 | − * after we write it. | |
| 65 | − */ | |
| 66 | − IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr); | |
| 67 | − __raw_readq(IIO_ITTE_GET(nasid, i)); | |
| 68 | − | |
| 69 | − return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE); | |
| 70 | − } | |
| 71 | − | |
| 72 | − printk(KERN_WARNING "unable to establish PIO mapping for at" | |
| 73 | − " hub %d widget %d addr 0x%lx\n", | |
| 74 | − nasid, widget, xtalk_addr); | |
| 75 | − return 0; | |
| 76 | −} | |
| 77 | − | |
| 78 | − | |
| 79 | −/* | |
| 80 | − * hub_setup_prb(nasid, prbnum, credits, conveyor) | |
| 81 | − * | |
| 82 | − * Put a PRB into fire-and-forget mode if conveyor isn't set. Otherwise, | |
| 83 | − * put it into conveyor belt mode with the specified number of credits. | |
| 84 | − */ | |
| 85 | −static void hub_setup_prb(nasid_t nasid, int prbnum, int credits) | |
| 86 | −{ | |
| 87 | − union iprb_u prb; | |
| 88 | − int prb_offset; | |
| 89 | − | |
| 90 | − /* | |
| 91 | − * Get the current register value. | |
| 92 | − */ | |
| 93 | − prb_offset = IIO_IOPRB(prbnum); | |
| 94 | − prb.iprb_regval = REMOTE_HUB_L(nasid, prb_offset); | |
| 95 | − | |
| 96 | − /* | |
| 97 | − * Clear out some fields. | |
| 98 | − */ | |
| 99 | − prb.iprb_ovflow = 1; | |
| 100 | − prb.iprb_bnakctr = 0; | |
| 101 | − prb.iprb_anakctr = 0; | |
| 102 | − | |
| 103 | − /* | |
| 104 | − * Enable or disable fire-and-forget mode. | |
| 105 | − */ | |
| 106 | − prb.iprb_ff = force_fire_and_forget ? 1 : 0; | |
| 107 | − | |
| 108 | − /* | |
| 109 | − * Set the appropriate number of PIO credits for the widget. | |
| 110 | − */ | |
| 111 | − prb.iprb_xtalkctr = credits; | |
| 112 | − | |
| 113 | − /* | |
| 114 | − * Store the new value to the register. | |
| 115 | − */ | |
| 116 | − REMOTE_HUB_S(nasid, prb_offset, prb.iprb_regval); | |
| 117 | −} | |
| 118 | − | |
| 119 | −/** | |
| 120 | − * hub_set_piomode - set pio mode for a given hub | |
| 121 | − * | |
| 122 | − * @nasid: physical node ID for the hub in question | |
| 123 | − * | |
| 124 | − * Put the hub into either "PIO conveyor belt" mode or "fire-and-forget" mode. | |
| 125 | − * To do this, we have to make absolutely sure that no PIOs are in progress | |
| 126 | − * so we turn off access to all widgets for the duration of the function. | |
| 127 | − * | |
| 128 | − * XXX - This code should really check what kind of widget we're talking | |
| 129 | − * to. Bridges can only handle three requests, but XG will do more. | |
| 130 | − * How many can crossbow handle to widget 0? We're assuming 1. | |
| 131 | − * | |
| 132 | − * XXX - There is a bug in the crossbow that link reset PIOs do not | |
| 133 | − * return write responses. The easiest solution to this problem is to | |
| 134 | − * leave widget 0 (xbow) in fire-and-forget mode at all times. This | |
| 135 | − * only affects pio's to xbow registers, which should be rare. | |
| 136 | − **/ | |
| 137 | −static void hub_set_piomode(nasid_t nasid) | |
| 138 | −{ | |
| 139 | − u64 ii_iowa; | |
| 140 | − union hubii_wcr_u ii_wcr; | |
| 141 | − unsigned i; | |
| 142 | − | |
| 143 | − ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS); | |
| 144 | − REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0); | |
| 145 | − | |
| 146 | − ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR); | |
| 147 | − | |
| 148 | − if (ii_wcr.iwcr_dir_con) { | |
| 149 | − /* | |
| 150 | − * Assume a bridge here. | |
| 151 | − */ | |
| 152 | − hub_setup_prb(nasid, 0, 3); | |
| 153 | − } else { | |
| 154 | − /* | |
| 155 | − * Assume a crossbow here. | |
| 156 | − */ | |
| 157 | − hub_setup_prb(nasid, 0, 1); | |
| 158 | − } | |
| 159 | − | |
| 160 | − /* | |
| 161 | − * XXX - Here's where we should take the widget type into | |
| 162 | − * when account assigning credits. | |
| 163 | − */ | |
| 164 | − for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++) | |
| 165 | − hub_setup_prb(nasid, i, 3); | |
| 166 | − | |
| 167 | − REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa); | |
| 168 | −} | |
| 169 | − | |
| 170 | −/* | |
| 171 | − * hub_pio_init - PIO-related hub initialization | |
| 172 | − * | |
| 173 | − * @hub: hubinfo structure for our hub | |
| 174 | − */ | |
| 175 | −void hub_pio_init(nasid_t nasid) | |
| 176 | −{ | |
| 177 | − unsigned i; | |
| 178 | − | |
| 179 | − /* initialize big window piomaps for this hub */ | |
| 180 | − bitmap_zero(hub_data(nasid)->h_bigwin_used, HUB_NUM_BIG_WINDOW); | |
| 181 | − for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) | |
| 182 | − IIO_ITTE_DISABLE(nasid, i); | |
| 183 | − | |
| 184 | − hub_set_piomode(nasid); | |
| 185 | −} | |
| @@ -23,6 +23,8 @@ · 22 unmodified lines | ||
| 23 | 23 | #include <asm/sn/intr.h> |
| 24 | 24 | #include <asm/sn/irq_alloc.h> |
| 25 | 25 | |
| 26 | +#include "ip27-common.h" | |
| 27 | + | |
| 26 | 28 | struct hub_irq_data { |
| 27 | 29 | u64 *irq_mask[2]; |
| 28 | 30 | cpuid_t cpu; |
| @@ -23,6 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | #include <asm/page.h> |
| 24 | 24 | #include <asm/pgalloc.h> |
| 25 | 25 | #include <asm/sections.h> |
| 26 | +#include <asm/sgialib.h> | |
| 26 | 27 | |
| 27 | 28 | #include <asm/sn/arch.h> |
| 28 | 29 | #include <asm/sn/agent.h> |
| @@ -11,6 +11,8 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <asm/sn/arch.h> |
| 12 | 12 | #include <asm/sn/agent.h> |
| 13 | 13 | |
| 14 | +#include "ip27-common.h" | |
| 15 | + | |
| 14 | 16 | #if 0 |
| 15 | 17 | #define NODE_NUM_CPUS(n) CNODE_NUM_CPUS(n) |
| 16 | 18 | #else |
| @@ -23,16 +25,7 @@ · 6 unmodified lines | ||
| 23 | 25 | typedef unsigned long machreg_t; |
| 24 | 26 | |
| 25 | 27 | static arch_spinlock_t nmi_lock = __ARCH_SPIN_LOCK_UNLOCKED; |
| 26 | − | |
| 27 | −/* | |
| 28 | − * Let's see what else we need to do here. Set up sp, gp? | |
| 29 | − */ | |
| 30 | −void nmi_dump(void) | |
| 31 | −{ | |
| 32 | − void cont_nmi_dump(void); | |
| 33 | − | |
| 34 | − cont_nmi_dump(); | |
| 35 | −} | |
| 28 | +static void nmi_dump(void); | |
| 36 | 29 | |
| 37 | 30 | void install_cpu_nmi_handler(int slice) |
| 38 | 31 | { |
| @@ -53,7 +46,7 @@ void install_cpu_nmi_handler(int slice) · 14 unmodified lines | ||
| 53 | 46 | * into the eframe format for the node under consideration. |
| 54 | 47 | */ |
| 55 | 48 | |
| 56 | −void nmi_cpu_eframe_save(nasid_t nasid, int slice) | |
| 49 | +static void nmi_cpu_eframe_save(nasid_t nasid, int slice) | |
| 57 | 50 | { |
| 58 | 51 | struct reg_struct *nr; |
| 59 | 52 | int i; |
| @@ -129,7 +122,7 @@ void nmi_cpu_eframe_save(nasid_t nasid, int slice) · 69 unmodified lines | ||
| 129 | 122 | pr_emerg("\n"); |
| 130 | 123 | } |
| 131 | 124 | |
| 132 | −void nmi_dump_hub_irq(nasid_t nasid, int slice) | |
| 125 | +static void nmi_dump_hub_irq(nasid_t nasid, int slice) | |
| 133 | 126 | { |
| 134 | 127 | u64 mask0, mask1, pend0, pend1; |
| 135 | 128 | |
| @@ -153,7 +146,7 @@ void nmi_dump_hub_irq(nasid_t nasid, int slice) · 17 unmodified lines | ||
| 153 | 146 | * Copy the cpu registers which have been saved in the IP27prom format |
| 154 | 147 | * into the eframe format for the node under consideration. |
| 155 | 148 | */ |
| 156 | −void nmi_node_eframe_save(nasid_t nasid) | |
| 149 | +static void nmi_node_eframe_save(nasid_t nasid) | |
| 157 | 150 | { |
| 158 | 151 | int slice; |
| 159 | 152 | |
| @@ -170,8 +163,7 @@ void nmi_node_eframe_save(nasid_t nasid) · 10 unmodified lines | ||
| 170 | 163 | /* |
| 171 | 164 | * Save the nmi cpu registers for all cpus in the system. |
| 172 | 165 | */ |
| 173 | −void | |
| 174 | −nmi_eframes_save(void) | |
| 166 | +static void nmi_eframes_save(void) | |
| 175 | 167 | { |
| 176 | 168 | nasid_t nasid; |
| 177 | 169 | |
| @@ -179,8 +171,7 @@ nmi_eframes_save(void) · 1 unmodified line | ||
| 179 | 171 | nmi_node_eframe_save(nasid); |
| 180 | 172 | } |
| 181 | 173 | |
| 182 | −void | |
| 183 | −cont_nmi_dump(void) | |
| 174 | +static void nmi_dump(void) | |
| 184 | 175 | { |
| 185 | 176 | #ifndef REAL_NMI_SIGNAL |
| 186 | 177 | static atomic_t nmied_cpus = ATOMIC_INIT(0); |
| @@ -3,6 +3,7 @@ · 2 unmodified lines | ||
| 3 | 3 | #include <linux/io.h> |
| 4 | 4 | |
| 5 | 5 | #include <asm/sn/ioc3.h> |
| 6 | +#include <asm/setup.h> | |
| 6 | 7 | |
| 7 | 8 | static inline struct ioc3_uartregs *console_uart(void) |
| 8 | 9 | { |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/percpu.h> |
| 15 | 15 | #include <linux/memblock.h> |
| 16 | 16 | |
| 17 | +#include <asm/bootinfo.h> | |
| 17 | 18 | #include <asm/smp-ops.h> |
| 18 | 19 | #include <asm/sgialib.h> |
| 19 | 20 | #include <asm/time.h> |
| @@ -18,6 +18,8 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <asm/ip32/crime.h> |
| 19 | 19 | #include <asm/ip32/mace.h> |
| 20 | 20 | |
| 21 | +#include "ip32-common.h" | |
| 22 | + | |
| 21 | 23 | struct sgi_crime __iomem *crime; |
| 22 | 24 | struct sgi_mace __iomem *mace; |
| 23 | 25 | |
| @@ -39,7 +41,7 @@ void __init crime_init(void) · 15 unmodified lines | ||
| 39 | 41 | id, rev, field, (unsigned long) CRIME_BASE); |
| 40 | 42 | } |
| 41 | 43 | |
| 42 | −irqreturn_t crime_memerr_intr(unsigned int irq, void *dev_id) | |
| 44 | +irqreturn_t crime_memerr_intr(int irq, void *dev_id) | |
| 43 | 45 | { |
| 44 | 46 | unsigned long stat, addr; |
| 45 | 47 | int fatal = 0; |
| @@ -90,7 +92,7 @@ irqreturn_t crime_memerr_intr(unsigned int irq, void *dev_id) · 44 unmodified lines | ||
| 90 | 92 | return IRQ_HANDLED; |
| 91 | 93 | } |
| 92 | 94 | |
| 93 | −irqreturn_t crime_cpuerr_intr(unsigned int irq, void *dev_id) | |
| 95 | +irqreturn_t crime_cpuerr_intr(int irq, void *dev_id) | |
| 94 | 96 | { |
| 95 | 97 | unsigned long stat = crime->cpu_error_stat & CRIME_CPU_ERROR_MASK; |
| 96 | 98 | unsigned long addr = crime->cpu_error_addr & CRIME_CPU_ERROR_ADDR_MASK; |
| @@ -18,6 +18,8 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <asm/ptrace.h> |
| 19 | 19 | #include <asm/tlbdebug.h> |
| 20 | 20 | |
| 21 | +#include "ip32-common.h" | |
| 22 | + | |
| 21 | 23 | static int ip32_be_handler(struct pt_regs *regs, int is_fixup) |
| 22 | 24 | { |
| 23 | 25 | int data = regs->cp0_cause & 4; |
| @@ -0,0 +1,15 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | + | |
| 3 | +#ifndef __IP32_COMMON_H | |
| 4 | +#define __IP32_COMMON_H | |
| 5 | + | |
| 6 | +#include <linux/init.h> | |
| 7 | +#include <linux/interrupt.h> | |
| 8 | + | |
| 9 | +void __init crime_init(void); | |
| 10 | +irqreturn_t crime_memerr_intr(int irq, void *dev_id); | |
| 11 | +irqreturn_t crime_cpuerr_intr(int irq, void *dev_id); | |
| 12 | +void __init ip32_be_init(void); | |
| 13 | +void ip32_prepare_poweroff(void); | |
| 14 | + | |
| 15 | +#endif /* __IP32_COMMON_H */ | |
| @@ -28,6 +28,8 @@ · 27 unmodified lines | ||
| 28 | 28 | #include <asm/ip32/mace.h> |
| 29 | 29 | #include <asm/ip32/ip32_ints.h> |
| 30 | 30 | |
| 31 | +#include "ip32-common.h" | |
| 32 | + | |
| 31 | 33 | /* issue a PIO read to make sure no PIO writes are pending */ |
| 32 | 34 | static inline void flush_crime_bus(void) |
| 33 | 35 | { |
| @@ -107,10 +109,6 @@ static inline void flush_mace_bus(void) · 73 unmodified lines | ||
| 107 | 109 | * is quite different anyway. |
| 108 | 110 | */ |
| 109 | 111 | |
| 110 | −/* Some initial interrupts to set up */ | |
| 111 | −extern irqreturn_t crime_memerr_intr(int irq, void *dev_id); | |
| 112 | −extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id); | |
| 113 | − | |
| 114 | 112 | /* |
| 115 | 113 | * This is for pure CRIME interrupts - ie not MACE. The advantage? |
| 116 | 114 | * We get to split the register in half and do faster lookups. |
| @@ -15,6 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | #include <asm/ip32/crime.h> |
| 16 | 16 | #include <asm/bootinfo.h> |
| 17 | 17 | #include <asm/page.h> |
| 18 | +#include <asm/sgialib.h> | |
| 18 | 19 | |
| 19 | 20 | extern void crime_init(void); |
| 20 | 21 | |
| @@ -29,6 +29,8 @@ · 28 unmodified lines | ||
| 29 | 29 | #include <asm/ip32/crime.h> |
| 30 | 30 | #include <asm/ip32/ip32_ints.h> |
| 31 | 31 | |
| 32 | +#include "ip32-common.h" | |
| 33 | + | |
| 32 | 34 | #define POWERDOWN_TIMEOUT 120 |
| 33 | 35 | /* |
| 34 | 36 | * Blink frequency during reboot grace period and when panicked. |
| @@ -26,8 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | #include <asm/ip32/mace.h> |
| 27 | 27 | #include <asm/ip32/ip32_ints.h> |
| 28 | 28 | |
| 29 | −extern void ip32_be_init(void); | |
| 30 | −extern void crime_init(void); | |
| 29 | +#include "ip32-common.h" | |
| 31 | 30 | |
| 32 | 31 | #ifdef CONFIG_SGI_O2MACE_ETH |
| 33 | 32 | /* |
| @@ -25,7 +25,6 @@ config PARISC · 24 unmodified lines | ||
| 25 | 25 | select RTC_DRV_GENERIC |
| 26 | 26 | select INIT_ALL_POSSIBLE |
| 27 | 27 | select BUG |
| 28 | − select BUILDTIME_TABLE_SORT | |
| 29 | 28 | select HAVE_KERNEL_UNCOMPRESSED |
| 30 | 29 | select HAVE_PCI |
| 31 | 30 | select HAVE_PERF_EVENTS |
| @@ -50,12 +50,12 @@ export CROSS32CC · 49 unmodified lines | ||
| 50 | 50 | |
| 51 | 51 | # Set default cross compiler for kernel build |
| 52 | 52 | ifdef cross_compiling |
| 53 | − ifeq ($(CROSS_COMPILE),) | |
| 53 | + ifeq ($(CROSS_COMPILE),) | |
| 54 | 54 | CC_SUFFIXES = linux linux-gnu unknown-linux-gnu suse-linux |
| 55 | 55 | CROSS_COMPILE := $(call cc-cross-prefix, \ |
| 56 | 56 | $(foreach a,$(CC_ARCHES), \ |
| 57 | 57 | $(foreach s,$(CC_SUFFIXES),$(a)-$(s)-))) |
| 58 | − endif | |
| 58 | + endif | |
| 59 | 59 | endif |
| 60 | 60 | |
| 61 | 61 | ifdef CONFIG_DYNAMIC_FTRACE |
| @@ -576,6 +576,7 @@ · 575 unmodified lines | ||
| 576 | 576 | .section __ex_table,"aw" ! \ |
| 577 | 577 | .align 4 ! \ |
| 578 | 578 | .word (fault_addr - .), (except_addr - .) ! \ |
| 579 | + or %r0,%r0,%r0 ! \ | |
| 579 | 580 | .previous |
| 580 | 581 | |
| 581 | 582 | |
| @@ -0,0 +1,64 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | +#ifndef __PARISC_EXTABLE_H | |
| 3 | +#define __PARISC_EXTABLE_H | |
| 4 | + | |
| 5 | +#include <asm/ptrace.h> | |
| 6 | +#include <linux/compiler.h> | |
| 7 | + | |
| 8 | +/* | |
| 9 | + * The exception table consists of three addresses: | |
| 10 | + * | |
| 11 | + * - A relative address to the instruction that is allowed to fault. | |
| 12 | + * - A relative address at which the program should continue (fixup routine) | |
| 13 | + * - An asm statement which specifies which CPU register will | |
| 14 | + * receive -EFAULT when an exception happens if the lowest bit in | |
| 15 | + * the fixup address is set. | |
| 16 | + * | |
| 17 | + * Note: The register specified in the err_opcode instruction will be | |
| 18 | + * modified at runtime if a fault happens. Register %r0 will be ignored. | |
| 19 | + * | |
| 20 | + * Since relative addresses are used, 32bit values are sufficient even on | |
| 21 | + * 64bit kernel. | |
| 22 | + */ | |
| 23 | + | |
| 24 | +struct pt_regs; | |
| 25 | +int fixup_exception(struct pt_regs *regs); | |
| 26 | + | |
| 27 | +#define ARCH_HAS_RELATIVE_EXTABLE | |
| 28 | +struct exception_table_entry { | |
| 29 | + int insn; /* relative address of insn that is allowed to fault. */ | |
| 30 | + int fixup; /* relative address of fixup routine */ | |
| 31 | + int err_opcode; /* sample opcode with register which holds error code */ | |
| 32 | +}; | |
| 33 | + | |
| 34 | +#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr, opcode )\ | |
| 35 | + ".section __ex_table,\"aw\"\n" \ | |
| 36 | + ".align 4\n" \ | |
| 37 | + ".word (" #fault_addr " - .), (" #except_addr " - .)\n" \ | |
| 38 | + opcode "\n" \ | |
| 39 | + ".previous\n" | |
| 40 | + | |
| 41 | +/* | |
| 42 | + * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry | |
| 43 | + * (with lowest bit set) for which the fault handler in fixup_exception() will | |
| 44 | + * load -EFAULT on fault into the register specified by the err_opcode instruction, | |
| 45 | + * and zeroes the target register in case of a read fault in get_user(). | |
| 46 | + */ | |
| 47 | +#define ASM_EXCEPTIONTABLE_VAR(__err_var) \ | |
| 48 | + int __err_var = 0 | |
| 49 | +#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr, register )\ | |
| 50 | + ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1, "or %%r0,%%r0," register) | |
| 51 | + | |
| 52 | +static inline void swap_ex_entry_fixup(struct exception_table_entry *a, | |
| 53 | + struct exception_table_entry *b, | |
| 54 | + struct exception_table_entry tmp, | |
| 55 | + int delta) | |
| 56 | +{ | |
| 57 | + a->fixup = b->fixup + delta; | |
| 58 | + b->fixup = tmp.fixup - delta; | |
| 59 | + a->err_opcode = b->err_opcode; | |
| 60 | + b->err_opcode = tmp.err_opcode; | |
| 61 | +} | |
| 62 | +#define swap_ex_entry_fixup swap_ex_entry_fixup | |
| 63 | + | |
| 64 | +#endif | |
| @@ -8,7 +8,8 @@ · 7 unmodified lines | ||
| 8 | 8 | "copy %%r0,%0\n" \ |
| 9 | 9 | "8:\tlpa %%r0(%1),%0\n" \ |
| 10 | 10 | "9:\n" \ |
| 11 | − ASM_EXCEPTIONTABLE_ENTRY(8b, 9b) \ | |
| 11 | + ASM_EXCEPTIONTABLE_ENTRY(8b, 9b, \ | |
| 12 | + "or %%r0,%%r0,%%r0") \ | |
| 12 | 13 | : "=&r" (pa) \ |
| 13 | 14 | : "r" (va) \ |
| 14 | 15 | : "memory" \ |
| @@ -22,7 +23,8 @@ · 7 unmodified lines | ||
| 22 | 23 | "copy %%r0,%0\n" \ |
| 23 | 24 | "8:\tlpa %%r0(%%sr3,%1),%0\n" \ |
| 24 | 25 | "9:\n" \ |
| 25 | − ASM_EXCEPTIONTABLE_ENTRY(8b, 9b) \ | |
| 26 | + ASM_EXCEPTIONTABLE_ENTRY(8b, 9b, \ | |
| 27 | + "or %%r0,%%r0,%%r0") \ | |
| 26 | 28 | : "=&r" (pa) \ |
| 27 | 29 | : "r" (va) \ |
| 28 | 30 | : "memory" \ |
| @@ -7,6 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | */ |
| 8 | 8 | #include <asm/page.h> |
| 9 | 9 | #include <asm/cache.h> |
| 10 | +#include <asm/extable.h> | |
| 10 | 11 | |
| 11 | 12 | #include <linux/bug.h> |
| 12 | 13 | #include <linux/string.h> |
| @@ -26,37 +27,6 @@ · 13 unmodified lines | ||
| 26 | 27 | #define STD_USER(sr, x, ptr) __put_user_asm(sr, "std", x, ptr) |
| 27 | 28 | #endif |
| 28 | 29 | |
| 29 | −/* | |
| 30 | − * The exception table contains two values: the first is the relative offset to | |
| 31 | − * the address of the instruction that is allowed to fault, and the second is | |
| 32 | − * the relative offset to the address of the fixup routine. Since relative | |
| 33 | − * addresses are used, 32bit values are sufficient even on 64bit kernel. | |
| 34 | − */ | |
| 35 | − | |
| 36 | −#define ARCH_HAS_RELATIVE_EXTABLE | |
| 37 | −struct exception_table_entry { | |
| 38 | − int insn; /* relative address of insn that is allowed to fault. */ | |
| 39 | − int fixup; /* relative address of fixup routine */ | |
| 40 | −}; | |
| 41 | − | |
| 42 | −#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\ | |
| 43 | − ".section __ex_table,\"aw\"\n" \ | |
| 44 | − ".align 4\n" \ | |
| 45 | − ".word (" #fault_addr " - .), (" #except_addr " - .)\n\t" \ | |
| 46 | − ".previous\n" | |
| 47 | − | |
| 48 | −/* | |
| 49 | − * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry | |
| 50 | − * (with lowest bit set) for which the fault handler in fixup_exception() will | |
| 51 | − * load -EFAULT into %r29 for a read or write fault, and zeroes the target | |
| 52 | − * register in case of a read fault in get_user(). | |
| 53 | − */ | |
| 54 | −#define ASM_EXCEPTIONTABLE_REG 29 | |
| 55 | −#define ASM_EXCEPTIONTABLE_VAR(__variable) \ | |
| 56 | − register long __variable __asm__ ("r29") = 0 | |
| 57 | −#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr )\ | |
| 58 | − ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1) | |
| 59 | − | |
| 60 | 30 | #define __get_user_internal(sr, val, ptr) \ |
| 61 | 31 | ({ \ |
| 62 | 32 | ASM_EXCEPTIONTABLE_VAR(__gu_err); \ |
| @@ -83,7 +53,7 @@ struct exception_table_entry { · 20 unmodified lines | ||
| 83 | 53 | \ |
| 84 | 54 | __asm__("1: " ldx " 0(%%sr%2,%3),%0\n" \ |
| 85 | 55 | "9:\n" \ |
| 86 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ | |
| 56 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%1") \ | |
| 87 | 57 | : "=r"(__gu_val), "+r"(__gu_err) \ |
| 88 | 58 | : "i"(sr), "r"(ptr)); \ |
| 89 | 59 | \ |
| @@ -115,8 +85,8 @@ struct exception_table_entry { · 25 unmodified lines | ||
| 115 | 85 | "1: ldw 0(%%sr%2,%3),%0\n" \ |
| 116 | 86 | "2: ldw 4(%%sr%2,%3),%R0\n" \ |
| 117 | 87 | "9:\n" \ |
| 118 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ | |
| 119 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ | |
| 88 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%1") \ | |
| 89 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b, "%1") \ | |
| 120 | 90 | : "=&r"(__gu_tmp.l), "+r"(__gu_err) \ |
| 121 | 91 | : "i"(sr), "r"(ptr)); \ |
| 122 | 92 | \ |
| @@ -174,7 +144,7 @@ struct exception_table_entry { · 51 unmodified lines | ||
| 174 | 144 | __asm__ __volatile__ ( \ |
| 175 | 145 | "1: " stx " %1,0(%%sr%2,%3)\n" \ |
| 176 | 146 | "9:\n" \ |
| 177 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ | |
| 147 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%0") \ | |
| 178 | 148 | : "+r"(__pu_err) \ |
| 179 | 149 | : "r"(x), "i"(sr), "r"(ptr)) |
| 180 | 150 | |
| @@ -186,15 +156,14 @@ struct exception_table_entry { · 5 unmodified lines | ||
| 186 | 156 | "1: stw %1,0(%%sr%2,%3)\n" \ |
| 187 | 157 | "2: stw %R1,4(%%sr%2,%3)\n" \ |
| 188 | 158 | "9:\n" \ |
| 189 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ | |
| 190 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ | |
| 159 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%0") \ | |
| 160 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b, "%0") \ | |
| 191 | 161 | : "+r"(__pu_err) \ |
| 192 | 162 | : "r"(__val), "i"(sr), "r"(ptr)); \ |
| 193 | 163 | } while (0) |
| 194 | 164 | |
| 195 | 165 | #endif /* !defined(CONFIG_64BIT) */ |
| 196 | 166 | |
| 197 | − | |
| 198 | 167 | /* |
| 199 | 168 | * Complex access routines -- external declarations |
| 200 | 169 | */ |
| @@ -216,7 +185,4 @@ unsigned long __must_check raw_copy_from_user(void *dst, const void __user *src, · 15 unmodified lines | ||
| 216 | 185 | #define INLINE_COPY_TO_USER |
| 217 | 186 | #define INLINE_COPY_FROM_USER |
| 218 | 187 | |
| 219 | −struct pt_regs; | |
| 220 | −int fixup_exception(struct pt_regs *regs); | |
| 221 | − | |
| 222 | 188 | #endif /* __PARISC_UACCESS_H */ |
| @@ -58,7 +58,7 @@ int pa_serialize_tlb_flushes __ro_after_init; · 57 unmodified lines | ||
| 58 | 58 | |
| 59 | 59 | struct pdc_cache_info cache_info __ro_after_init; |
| 60 | 60 | #ifndef CONFIG_PA20 |
| 61 | −struct pdc_btlb_info btlb_info __ro_after_init; | |
| 61 | +struct pdc_btlb_info btlb_info; | |
| 62 | 62 | #endif |
| 63 | 63 | |
| 64 | 64 | DEFINE_STATIC_KEY_TRUE(parisc_has_cache); |
| @@ -264,6 +264,10 @@ parisc_cache_init(void) · 199 unmodified lines | ||
| 264 | 264 | icache_stride = CAFL_STRIDE(cache_info.ic_conf); |
| 265 | 265 | #undef CAFL_STRIDE |
| 266 | 266 | |
| 267 | + /* stride needs to be non-zero, otherwise cache flushes will not work */ | |
| 268 | + WARN_ON(cache_info.dc_size && dcache_stride == 0); | |
| 269 | + WARN_ON(cache_info.ic_size && icache_stride == 0); | |
| 270 | + | |
| 267 | 271 | if ((boot_cpu_data.pdc.capabilities & PDC_MODEL_NVA_MASK) == |
| 268 | 272 | PDC_MODEL_NVA_UNSUPPORTED) { |
| 269 | 273 | printk(KERN_WARNING "parisc_cache_init: Only equivalent aliasing supported!\n"); |
| @@ -850,7 +854,7 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes, · 580 unmodified lines | ||
| 850 | 854 | #endif |
| 851 | 855 | " fic,m %3(%4,%0)\n" |
| 852 | 856 | "2: sync\n" |
| 853 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b) | |
| 857 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b, "%1") | |
| 854 | 858 | : "+r" (start), "+r" (error) |
| 855 | 859 | : "r" (end), "r" (dcache_stride), "i" (SR_USER)); |
| 856 | 860 | } |
| @@ -865,7 +869,7 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes, · 8 unmodified lines | ||
| 865 | 869 | #endif |
| 866 | 870 | " fdc,m %3(%4,%0)\n" |
| 867 | 871 | "2: sync\n" |
| 868 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b) | |
| 872 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b, "%1") | |
| 869 | 873 | : "+r" (start), "+r" (error) |
| 870 | 874 | : "r" (end), "r" (icache_stride), "i" (SR_USER)); |
| 871 | 875 | } |
| @@ -742,7 +742,7 @@ parse_tree_node(struct device *parent, int index, struct hardware_path *modpath) · 741 unmodified lines | ||
| 742 | 742 | }; |
| 743 | 743 | |
| 744 | 744 | if (device_for_each_child(parent, &recurse_data, descend_children)) |
| 745 | − { /* nothing */ }; | |
| 745 | + { /* nothing */ } | |
| 746 | 746 | |
| 747 | 747 | return d.dev; |
| 748 | 748 | } |
| @@ -1004,6 +1004,9 @@ static __init int qemu_print_iodc_data(struct device *lin_dev, void *data) · 255 unmodified lines | ||
| 1004 | 1004 | |
| 1005 | 1005 | pr_info("\n"); |
| 1006 | 1006 | |
| 1007 | + /* Prevent hung task messages when printing on serial console */ | |
| 1008 | + cond_resched(); | |
| 1009 | + | |
| 1007 | 1010 | pr_info("#define HPA_%08lx_DESCRIPTION \"%s\"\n", |
| 1008 | 1011 | hpa, parisc_hardware_description(&dev->id)); |
| 1009 | 1012 | |
| @@ -120,8 +120,8 @@ static int emulate_ldh(struct pt_regs *regs, int toreg) · 119 unmodified lines | ||
| 120 | 120 | "2: ldbs 1(%%sr1,%3), %0\n" |
| 121 | 121 | " depw %2, 23, 24, %0\n" |
| 122 | 122 | "3: \n" |
| 123 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) | |
| 124 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) | |
| 123 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") | |
| 124 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") | |
| 125 | 125 | : "+r" (val), "+r" (ret), "=&r" (temp1) |
| 126 | 126 | : "r" (saddr), "r" (regs->isr) ); |
| 127 | 127 | |
| @@ -152,8 +152,8 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop) · 24 unmodified lines | ||
| 152 | 152 | " mtctl %2,11\n" |
| 153 | 153 | " vshd %0,%3,%0\n" |
| 154 | 154 | "3: \n" |
| 155 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) | |
| 156 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) | |
| 155 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") | |
| 156 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") | |
| 157 | 157 | : "+r" (val), "+r" (ret), "=&r" (temp1), "=&r" (temp2) |
| 158 | 158 | : "r" (saddr), "r" (regs->isr) ); |
| 159 | 159 | |
| @@ -189,8 +189,8 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) · 29 unmodified lines | ||
| 189 | 189 | " mtsar %%r19\n" |
| 190 | 190 | " shrpd %0,%%r20,%%sar,%0\n" |
| 191 | 191 | "3: \n" |
| 192 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) | |
| 193 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) | |
| 192 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") | |
| 193 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") | |
| 194 | 194 | : "=r" (val), "+r" (ret) |
| 195 | 195 | : "0" (val), "r" (saddr), "r" (regs->isr) |
| 196 | 196 | : "r19", "r20" ); |
| @@ -209,9 +209,9 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) · 12 unmodified lines | ||
| 209 | 209 | " vshd %0,%R0,%0\n" |
| 210 | 210 | " vshd %R0,%4,%R0\n" |
| 211 | 211 | "4: \n" |
| 212 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 4b) | |
| 213 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 4b) | |
| 214 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b) | |
| 212 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 4b, "%1") | |
| 213 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 4b, "%1") | |
| 214 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b, "%1") | |
| 215 | 215 | : "+r" (val), "+r" (ret), "+r" (saddr), "=&r" (shift), "=&r" (temp1) |
| 216 | 216 | : "r" (regs->isr) ); |
| 217 | 217 | } |
| @@ -244,8 +244,8 @@ static int emulate_sth(struct pt_regs *regs, int frreg) · 26 unmodified lines | ||
| 244 | 244 | "1: stb %1, 0(%%sr1, %3)\n" |
| 245 | 245 | "2: stb %2, 1(%%sr1, %3)\n" |
| 246 | 246 | "3: \n" |
| 247 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) | |
| 248 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) | |
| 247 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%0") | |
| 248 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%0") | |
| 249 | 249 | : "+r" (ret), "=&r" (temp1) |
| 250 | 250 | : "r" (val), "r" (regs->ior), "r" (regs->isr) ); |
| 251 | 251 | |
| @@ -285,8 +285,8 @@ static int emulate_stw(struct pt_regs *regs, int frreg, int flop) · 33 unmodified lines | ||
| 285 | 285 | " stw %%r20,0(%%sr1,%2)\n" |
| 286 | 286 | " stw %%r21,4(%%sr1,%2)\n" |
| 287 | 287 | "3: \n" |
| 288 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) | |
| 289 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) | |
| 288 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%0") | |
| 289 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%0") | |
| 290 | 290 | : "+r" (ret) |
| 291 | 291 | : "r" (val), "r" (regs->ior), "r" (regs->isr) |
| 292 | 292 | : "r19", "r20", "r21", "r22", "r1" ); |
| @@ -329,10 +329,10 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop) · 36 unmodified lines | ||
| 329 | 329 | "3: std %%r20,0(%%sr1,%2)\n" |
| 330 | 330 | "4: std %%r21,8(%%sr1,%2)\n" |
| 331 | 331 | "5: \n" |
| 332 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 5b) | |
| 333 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 5b) | |
| 334 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 5b) | |
| 335 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 5b) | |
| 332 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 5b, "%0") | |
| 333 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 5b, "%0") | |
| 334 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 5b, "%0") | |
| 335 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 5b, "%0") | |
| 336 | 336 | : "+r" (ret) |
| 337 | 337 | : "r" (val), "r" (regs->ior), "r" (regs->isr) |
| 338 | 338 | : "r19", "r20", "r21", "r22", "r1" ); |
| @@ -357,11 +357,11 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop) · 18 unmodified lines | ||
| 357 | 357 | "4: stw %%r1,4(%%sr1,%2)\n" |
| 358 | 358 | "5: stw %R1,8(%%sr1,%2)\n" |
| 359 | 359 | "6: \n" |
| 360 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 6b) | |
| 361 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 6b) | |
| 362 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 6b) | |
| 363 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 6b) | |
| 364 | − ASM_EXCEPTIONTABLE_ENTRY_EFAULT(5b, 6b) | |
| 360 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 6b, "%0") | |
| 361 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 6b, "%0") | |
| 362 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 6b, "%0") | |
| 363 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 6b, "%0") | |
| 364 | + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(5b, 6b, "%0") | |
| 365 | 365 | : "+r" (ret) |
| 366 | 366 | : "r" (val), "r" (regs->ior), "r" (regs->isr) |
| 367 | 367 | : "r19", "r20", "r21", "r1" ); |
| @@ -127,7 +127,7 @@ SECTIONS · 126 unmodified lines | ||
| 127 | 127 | } |
| 128 | 128 | #endif |
| 129 | 129 | |
| 130 | − RO_DATA(8) | |
| 130 | + RO_DATA(PAGE_SIZE) | |
| 131 | 131 | |
| 132 | 132 | /* unwind info */ |
| 133 | 133 | . = ALIGN(4); |
| @@ -150,11 +150,16 @@ int fixup_exception(struct pt_regs *regs) · 149 unmodified lines | ||
| 150 | 150 | * Fix up get_user() and put_user(). |
| 151 | 151 | * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() sets the least-significant |
| 152 | 152 | * bit in the relative address of the fixup routine to indicate |
| 153 | − * that gr[ASM_EXCEPTIONTABLE_REG] should be loaded with | |
| 154 | − * -EFAULT to report a userspace access error. | |
| 153 | + * that the register encoded in the "or %r0,%r0,register" | |
| 154 | + * opcode should be loaded with -EFAULT to report a userspace | |
| 155 | + * access error. | |
| 155 | 156 | */ |
| 156 | 157 | if (fix->fixup & 1) { |
| 157 | − regs->gr[ASM_EXCEPTIONTABLE_REG] = -EFAULT; | |
| 158 | + int fault_error_reg = fix->err_opcode & 0x1f; | |
| 159 | + if (!WARN_ON(!fault_error_reg)) | |
| 160 | + regs->gr[fault_error_reg] = -EFAULT; | |
| 161 | + pr_debug("Unalignment fixup of register %d at %pS\n", | |
| 162 | + fault_error_reg, (void*)regs->iaoq[0]); | |
| 158 | 163 | |
| 159 | 164 | /* zero target register for get_user() */ |
| 160 | 165 | if (parisc_acctyp(0, regs->iir) == VM_READ) { |
| @@ -93,144 +93,160 @@ · 92 unmodified lines | ||
| 93 | 93 | <&cpu63_intc 3>; |
| 94 | 94 | }; |
| 95 | 95 | |
| 96 | − clint_mtimer0: timer@70ac000000 { | |
| 96 | + clint_mtimer0: timer@70ac004000 { | |
| 97 | 97 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 98 | − reg = <0x00000070 0xac000000 0x00000000 0x00007ff8>; | |
| 98 | + reg = <0x00000070 0xac004000 0x00000000 0x0000c000>; | |
| 99 | + reg-names = "mtimecmp"; | |
| 99 | 100 | interrupts-extended = <&cpu0_intc 7>, |
| 100 | 101 | <&cpu1_intc 7>, |
| 101 | 102 | <&cpu2_intc 7>, |
| 102 | 103 | <&cpu3_intc 7>; |
| 103 | 104 | }; |
| 104 | 105 | |
| 105 | − clint_mtimer1: timer@70ac010000 { | |
| 106 | + clint_mtimer1: timer@70ac014000 { | |
| 106 | 107 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 107 | − reg = <0x00000070 0xac010000 0x00000000 0x00007ff8>; | |
| 108 | + reg = <0x00000070 0xac014000 0x00000000 0x0000c000>; | |
| 109 | + reg-names = "mtimecmp"; | |
| 108 | 110 | interrupts-extended = <&cpu4_intc 7>, |
| 109 | 111 | <&cpu5_intc 7>, |
| 110 | 112 | <&cpu6_intc 7>, |
| 111 | 113 | <&cpu7_intc 7>; |
| 112 | 114 | }; |
| 113 | 115 | |
| 114 | − clint_mtimer2: timer@70ac020000 { | |
| 116 | + clint_mtimer2: timer@70ac024000 { | |
| 115 | 117 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 116 | − reg = <0x00000070 0xac020000 0x00000000 0x00007ff8>; | |
| 118 | + reg = <0x00000070 0xac024000 0x00000000 0x0000c000>; | |
| 119 | + reg-names = "mtimecmp"; | |
| 117 | 120 | interrupts-extended = <&cpu8_intc 7>, |
| 118 | 121 | <&cpu9_intc 7>, |
| 119 | 122 | <&cpu10_intc 7>, |
| 120 | 123 | <&cpu11_intc 7>; |
| 121 | 124 | }; |
| 122 | 125 | |
| 123 | − clint_mtimer3: timer@70ac030000 { | |
| 126 | + clint_mtimer3: timer@70ac034000 { | |
| 124 | 127 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 125 | − reg = <0x00000070 0xac030000 0x00000000 0x00007ff8>; | |
| 128 | + reg = <0x00000070 0xac034000 0x00000000 0x0000c000>; | |
| 129 | + reg-names = "mtimecmp"; | |
| 126 | 130 | interrupts-extended = <&cpu12_intc 7>, |
| 127 | 131 | <&cpu13_intc 7>, |
| 128 | 132 | <&cpu14_intc 7>, |
| 129 | 133 | <&cpu15_intc 7>; |
| 130 | 134 | }; |
| 131 | 135 | |
| 132 | − clint_mtimer4: timer@70ac040000 { | |
| 136 | + clint_mtimer4: timer@70ac044000 { | |
| 133 | 137 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 134 | − reg = <0x00000070 0xac040000 0x00000000 0x00007ff8>; | |
| 138 | + reg = <0x00000070 0xac044000 0x00000000 0x0000c000>; | |
| 139 | + reg-names = "mtimecmp"; | |
| 135 | 140 | interrupts-extended = <&cpu16_intc 7>, |
| 136 | 141 | <&cpu17_intc 7>, |
| 137 | 142 | <&cpu18_intc 7>, |
| 138 | 143 | <&cpu19_intc 7>; |
| 139 | 144 | }; |
| 140 | 145 | |
| 141 | − clint_mtimer5: timer@70ac050000 { | |
| 146 | + clint_mtimer5: timer@70ac054000 { | |
| 142 | 147 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 143 | − reg = <0x00000070 0xac050000 0x00000000 0x00007ff8>; | |
| 148 | + reg = <0x00000070 0xac054000 0x00000000 0x0000c000>; | |
| 149 | + reg-names = "mtimecmp"; | |
| 144 | 150 | interrupts-extended = <&cpu20_intc 7>, |
| 145 | 151 | <&cpu21_intc 7>, |
| 146 | 152 | <&cpu22_intc 7>, |
| 147 | 153 | <&cpu23_intc 7>; |
| 148 | 154 | }; |
| 149 | 155 | |
| 150 | − clint_mtimer6: timer@70ac060000 { | |
| 156 | + clint_mtimer6: timer@70ac064000 { | |
| 151 | 157 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 152 | − reg = <0x00000070 0xac060000 0x00000000 0x00007ff8>; | |
| 158 | + reg = <0x00000070 0xac064000 0x00000000 0x0000c000>; | |
| 159 | + reg-names = "mtimecmp"; | |
| 153 | 160 | interrupts-extended = <&cpu24_intc 7>, |
| 154 | 161 | <&cpu25_intc 7>, |
| 155 | 162 | <&cpu26_intc 7>, |
| 156 | 163 | <&cpu27_intc 7>; |
| 157 | 164 | }; |
| 158 | 165 | |
| 159 | − clint_mtimer7: timer@70ac070000 { | |
| 166 | + clint_mtimer7: timer@70ac074000 { | |
| 160 | 167 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 161 | − reg = <0x00000070 0xac070000 0x00000000 0x00007ff8>; | |
| 168 | + reg = <0x00000070 0xac074000 0x00000000 0x0000c000>; | |
| 169 | + reg-names = "mtimecmp"; | |
| 162 | 170 | interrupts-extended = <&cpu28_intc 7>, |
| 163 | 171 | <&cpu29_intc 7>, |
| 164 | 172 | <&cpu30_intc 7>, |
| 165 | 173 | <&cpu31_intc 7>; |
| 166 | 174 | }; |
| 167 | 175 | |
| 168 | − clint_mtimer8: timer@70ac080000 { | |
| 176 | + clint_mtimer8: timer@70ac084000 { | |
| 169 | 177 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 170 | − reg = <0x00000070 0xac080000 0x00000000 0x00007ff8>; | |
| 178 | + reg = <0x00000070 0xac084000 0x00000000 0x0000c000>; | |
| 179 | + reg-names = "mtimecmp"; | |
| 171 | 180 | interrupts-extended = <&cpu32_intc 7>, |
| 172 | 181 | <&cpu33_intc 7>, |
| 173 | 182 | <&cpu34_intc 7>, |
| 174 | 183 | <&cpu35_intc 7>; |
| 175 | 184 | }; |
| 176 | 185 | |
| 177 | − clint_mtimer9: timer@70ac090000 { | |
| 186 | + clint_mtimer9: timer@70ac094000 { | |
| 178 | 187 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 179 | − reg = <0x00000070 0xac090000 0x00000000 0x00007ff8>; | |
| 188 | + reg = <0x00000070 0xac094000 0x00000000 0x0000c000>; | |
| 189 | + reg-names = "mtimecmp"; | |
| 180 | 190 | interrupts-extended = <&cpu36_intc 7>, |
| 181 | 191 | <&cpu37_intc 7>, |
| 182 | 192 | <&cpu38_intc 7>, |
| 183 | 193 | <&cpu39_intc 7>; |
| 184 | 194 | }; |
| 185 | 195 | |
| 186 | − clint_mtimer10: timer@70ac0a0000 { | |
| 196 | + clint_mtimer10: timer@70ac0a4000 { | |
| 187 | 197 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 188 | − reg = <0x00000070 0xac0a0000 0x00000000 0x00007ff8>; | |
| 198 | + reg = <0x00000070 0xac0a4000 0x00000000 0x0000c000>; | |
| 199 | + reg-names = "mtimecmp"; | |
| 189 | 200 | interrupts-extended = <&cpu40_intc 7>, |
| 190 | 201 | <&cpu41_intc 7>, |
| 191 | 202 | <&cpu42_intc 7>, |
| 192 | 203 | <&cpu43_intc 7>; |
| 193 | 204 | }; |
| 194 | 205 | |
| 195 | − clint_mtimer11: timer@70ac0b0000 { | |
| 206 | + clint_mtimer11: timer@70ac0b4000 { | |
| 196 | 207 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 197 | − reg = <0x00000070 0xac0b0000 0x00000000 0x00007ff8>; | |
| 208 | + reg = <0x00000070 0xac0b4000 0x00000000 0x0000c000>; | |
| 209 | + reg-names = "mtimecmp"; | |
| 198 | 210 | interrupts-extended = <&cpu44_intc 7>, |
| 199 | 211 | <&cpu45_intc 7>, |
| 200 | 212 | <&cpu46_intc 7>, |
| 201 | 213 | <&cpu47_intc 7>; |
| 202 | 214 | }; |
| 203 | 215 | |
| 204 | − clint_mtimer12: timer@70ac0c0000 { | |
| 216 | + clint_mtimer12: timer@70ac0c4000 { | |
| 205 | 217 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 206 | − reg = <0x00000070 0xac0c0000 0x00000000 0x00007ff8>; | |
| 218 | + reg = <0x00000070 0xac0c4000 0x00000000 0x0000c000>; | |
| 219 | + reg-names = "mtimecmp"; | |
| 207 | 220 | interrupts-extended = <&cpu48_intc 7>, |
| 208 | 221 | <&cpu49_intc 7>, |
| 209 | 222 | <&cpu50_intc 7>, |
| 210 | 223 | <&cpu51_intc 7>; |
| 211 | 224 | }; |
| 212 | 225 | |
| 213 | − clint_mtimer13: timer@70ac0d0000 { | |
| 226 | + clint_mtimer13: timer@70ac0d4000 { | |
| 214 | 227 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 215 | − reg = <0x00000070 0xac0d0000 0x00000000 0x00007ff8>; | |
| 228 | + reg = <0x00000070 0xac0d4000 0x00000000 0x0000c000>; | |
| 229 | + reg-names = "mtimecmp"; | |
| 216 | 230 | interrupts-extended = <&cpu52_intc 7>, |
| 217 | 231 | <&cpu53_intc 7>, |
| 218 | 232 | <&cpu54_intc 7>, |
| 219 | 233 | <&cpu55_intc 7>; |
| 220 | 234 | }; |
| 221 | 235 | |
| 222 | − clint_mtimer14: timer@70ac0e0000 { | |
| 236 | + clint_mtimer14: timer@70ac0e4000 { | |
| 223 | 237 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 224 | − reg = <0x00000070 0xac0e0000 0x00000000 0x00007ff8>; | |
| 238 | + reg = <0x00000070 0xac0e4000 0x00000000 0x0000c000>; | |
| 239 | + reg-names = "mtimecmp"; | |
| 225 | 240 | interrupts-extended = <&cpu56_intc 7>, |
| 226 | 241 | <&cpu57_intc 7>, |
| 227 | 242 | <&cpu58_intc 7>, |
| 228 | 243 | <&cpu59_intc 7>; |
| 229 | 244 | }; |
| 230 | 245 | |
| 231 | − clint_mtimer15: timer@70ac0f0000 { | |
| 246 | + clint_mtimer15: timer@70ac0f4000 { | |
| 232 | 247 | compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; |
| 233 | − reg = <0x00000070 0xac0f0000 0x00000000 0x00007ff8>; | |
| 248 | + reg = <0x00000070 0xac0f4000 0x00000000 0x0000c000>; | |
| 249 | + reg-names = "mtimecmp"; | |
| 234 | 250 | interrupts-extended = <&cpu60_intc 7>, |
| 235 | 251 | <&cpu61_intc 7>, |
| 236 | 252 | <&cpu62_intc 7>, |
| @@ -115,7 +115,9 @@ archprepare: · 114 unmodified lines | ||
| 115 | 115 | $(Q)$(MAKE) $(build)=$(HOST_DIR)/um include/generated/user_constants.h |
| 116 | 116 | |
| 117 | 117 | LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static |
| 118 | −LINK-$(CONFIG_LD_SCRIPT_DYN) += $(call cc-option, -no-pie) | |
| 118 | +ifdef CONFIG_LD_SCRIPT_DYN | |
| 119 | +LINK-$(call gcc-min-version, 60100)$(CONFIG_CC_IS_CLANG) += -no-pie | |
| 120 | +endif | |
| 119 | 121 | LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib |
| 120 | 122 | |
| 121 | 123 | CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) \ |
| @@ -112,13 +112,13 @@ ifeq ($(CONFIG_X86_32),y) · 111 unmodified lines | ||
| 112 | 112 | # temporary until string.h is fixed |
| 113 | 113 | KBUILD_CFLAGS += -ffreestanding |
| 114 | 114 | |
| 115 | − ifeq ($(CONFIG_STACKPROTECTOR),y) | |
| 116 | − ifeq ($(CONFIG_SMP),y) | |
| 115 | + ifeq ($(CONFIG_STACKPROTECTOR),y) | |
| 116 | + ifeq ($(CONFIG_SMP),y) | |
| 117 | 117 | KBUILD_CFLAGS += -mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard |
| 118 | − else | |
| 118 | + else | |
| 119 | 119 | KBUILD_CFLAGS += -mstack-protector-guard=global |
| 120 | − endif | |
| 121 | − endif | |
| 120 | + endif | |
| 121 | + endif | |
| 122 | 122 | else |
| 123 | 123 | BITS := 64 |
| 124 | 124 | UTS_MACHINE := x86_64 |
| @@ -81,10 +81,8 @@ · 80 unmodified lines | ||
| 81 | 81 | #define X86_FEATURE_K6_MTRR ( 3*32+ 1) /* AMD K6 nonstandard MTRRs */ |
| 82 | 82 | #define X86_FEATURE_CYRIX_ARR ( 3*32+ 2) /* Cyrix ARRs (= MTRRs) */ |
| 83 | 83 | #define X86_FEATURE_CENTAUR_MCR ( 3*32+ 3) /* Centaur MCRs (= MTRRs) */ |
| 84 | − | |
| 85 | −/* CPU types for specific tunings: */ | |
| 86 | 84 | #define X86_FEATURE_K8 ( 3*32+ 4) /* "" Opteron, Athlon64 */ |
| 87 | −/* FREE, was #define X86_FEATURE_K7 ( 3*32+ 5) "" Athlon */ | |
| 85 | +#define X86_FEATURE_ZEN5 ( 3*32+ 5) /* "" CPU based on Zen5 microarchitecture */ | |
| 88 | 86 | #define X86_FEATURE_P3 ( 3*32+ 6) /* "" P3 */ |
| 89 | 87 | #define X86_FEATURE_P4 ( 3*32+ 7) /* "" P4 */ |
| 90 | 88 | #define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* TSC ticks at a constant rate */ |
| @@ -162,6 +162,8 @@ · 161 unmodified lines | ||
| 162 | 162 | #define INTEL_FAM6_ATOM_CRESTMONT_X 0xAF /* Sierra Forest */ |
| 163 | 163 | #define INTEL_FAM6_ATOM_CRESTMONT 0xB6 /* Grand Ridge */ |
| 164 | 164 | |
| 165 | +#define INTEL_FAM6_ATOM_DARKMONT_X 0xDD /* Clearwater Forest */ | |
| 166 | + | |
| 165 | 167 | /* Xeon Phi */ |
| 166 | 168 | |
| 167 | 169 | #define INTEL_FAM6_XEON_PHI_KNL 0x57 /* Knights Landing */ |
| @@ -64,6 +64,7 @@ static inline bool kmsan_virt_addr_valid(void *addr) · 63 unmodified lines | ||
| 64 | 64 | { |
| 65 | 65 | unsigned long x = (unsigned long)addr; |
| 66 | 66 | unsigned long y = x - __START_KERNEL_map; |
| 67 | + bool ret; | |
| 67 | 68 | |
| 68 | 69 | /* use the carry flag to determine if x was < __START_KERNEL_map */ |
| 69 | 70 | if (unlikely(x > y)) { |
| @@ -79,7 +80,21 @@ static inline bool kmsan_virt_addr_valid(void *addr) · 9 unmodified lines | ||
| 79 | 80 | return false; |
| 80 | 81 | } |
| 81 | 82 | |
| 82 | − return pfn_valid(x >> PAGE_SHIFT); | |
| 83 | + /* | |
| 84 | + * pfn_valid() relies on RCU, and may call into the scheduler on exiting | |
| 85 | + * the critical section. However, this would result in recursion with | |
| 86 | + * KMSAN. Therefore, disable preemption here, and re-enable preemption | |
| 87 | + * below while suppressing reschedules to avoid recursion. | |
| 88 | + * | |
| 89 | + * Note, this sacrifices occasionally breaking scheduling guarantees. | |
| 90 | + * Although, a kernel compiled with KMSAN has already given up on any | |
| 91 | + * performance guarantees due to being heavily instrumented. | |
| 92 | + */ | |
| 93 | + preempt_disable(); | |
| 94 | + ret = pfn_valid(x >> PAGE_SHIFT); | |
| 95 | + preempt_enable_no_resched(); | |
| 96 | + | |
| 97 | + return ret; | |
| 83 | 98 | } |
| 84 | 99 | |
| 85 | 100 | #endif /* !MODULE */ |
| @@ -58,12 +58,29 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs); · 57 unmodified lines | ||
| 58 | 58 | ,,regs->di,,regs->si,,regs->dx \ |
| 59 | 59 | ,,regs->r10,,regs->r8,,regs->r9) \ |
| 60 | 60 | |
| 61 | + | |
| 62 | +/* SYSCALL_PT_ARGS is Adapted from s390x */ | |
| 63 | +#define SYSCALL_PT_ARG6(m, t1, t2, t3, t4, t5, t6) \ | |
| 64 | + SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5), m(t6, (regs->bp)) | |
| 65 | +#define SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5) \ | |
| 66 | + SYSCALL_PT_ARG4(m, t1, t2, t3, t4), m(t5, (regs->di)) | |
| 67 | +#define SYSCALL_PT_ARG4(m, t1, t2, t3, t4) \ | |
| 68 | + SYSCALL_PT_ARG3(m, t1, t2, t3), m(t4, (regs->si)) | |
| 69 | +#define SYSCALL_PT_ARG3(m, t1, t2, t3) \ | |
| 70 | + SYSCALL_PT_ARG2(m, t1, t2), m(t3, (regs->dx)) | |
| 71 | +#define SYSCALL_PT_ARG2(m, t1, t2) \ | |
| 72 | + SYSCALL_PT_ARG1(m, t1), m(t2, (regs->cx)) | |
| 73 | +#define SYSCALL_PT_ARG1(m, t1) m(t1, (regs->bx)) | |
| 74 | +#define SYSCALL_PT_ARGS(x, ...) SYSCALL_PT_ARG##x(__VA_ARGS__) | |
| 75 | + | |
| 76 | +#define __SC_COMPAT_CAST(t, a) \ | |
| 77 | + (__typeof(__builtin_choose_expr(__TYPE_IS_L(t), 0, 0U))) \ | |
| 78 | + (unsigned int)a | |
| 79 | + | |
| 61 | 80 | /* Mapping of registers to parameters for syscalls on i386 */ |
| 62 | 81 | #define SC_IA32_REGS_TO_ARGS(x, ...) \ |
| 63 | − __MAP(x,__SC_ARGS \ | |
| 64 | − ,,(unsigned int)regs->bx,,(unsigned int)regs->cx \ | |
| 65 | − ,,(unsigned int)regs->dx,,(unsigned int)regs->si \ | |
| 66 | − ,,(unsigned int)regs->di,,(unsigned int)regs->bp) | |
| 82 | + SYSCALL_PT_ARGS(x, __SC_COMPAT_CAST, \ | |
| 83 | + __MAP(x, __SC_TYPE, __VA_ARGS__)) \ | |
| 67 | 84 | |
| 68 | 85 | #define __SYS_STUB0(abi, name) \ |
| 69 | 86 | long __##abi##_##name(const struct pt_regs *regs); \ |
| @@ -403,7 +403,7 @@ noinstr void BUG_func(void) · 402 unmodified lines | ||
| 403 | 403 | { |
| 404 | 404 | BUG(); |
| 405 | 405 | } |
| 406 | −EXPORT_SYMBOL_GPL(BUG_func); | |
| 406 | +EXPORT_SYMBOL(BUG_func); | |
| 407 | 407 | |
| 408 | 408 | #define CALL_RIP_REL_OPCODE 0xff |
| 409 | 409 | #define CALL_RIP_REL_MODRM 0x15 |
| @@ -538,7 +538,7 @@ static void bsp_init_amd(struct cpuinfo_x86 *c) · 537 unmodified lines | ||
| 538 | 538 | |
| 539 | 539 | /* Figure out Zen generations: */ |
| 540 | 540 | switch (c->x86) { |
| 541 | − case 0x17: { | |
| 541 | + case 0x17: | |
| 542 | 542 | switch (c->x86_model) { |
| 543 | 543 | case 0x00 ... 0x2f: |
| 544 | 544 | case 0x50 ... 0x5f: |
| @@ -554,8 +554,8 @@ static void bsp_init_amd(struct cpuinfo_x86 *c) · 9 unmodified lines | ||
| 554 | 554 | goto warn; |
| 555 | 555 | } |
| 556 | 556 | break; |
| 557 | − } | |
| 558 | − case 0x19: { | |
| 557 | + | |
| 558 | + case 0x19: | |
| 559 | 559 | switch (c->x86_model) { |
| 560 | 560 | case 0x00 ... 0x0f: |
| 561 | 561 | case 0x20 ... 0x5f: |
| @@ -569,7 +569,20 @@ static void bsp_init_amd(struct cpuinfo_x86 *c) · 7 unmodified lines | ||
| 569 | 569 | goto warn; |
| 570 | 570 | } |
| 571 | 571 | break; |
| 572 | − } | |
| 572 | + | |
| 573 | + case 0x1a: | |
| 574 | + switch (c->x86_model) { | |
| 575 | + case 0x00 ... 0x0f: | |
| 576 | + case 0x20 ... 0x2f: | |
| 577 | + case 0x40 ... 0x4f: | |
| 578 | + case 0x70 ... 0x7f: | |
| 579 | + setup_force_cpu_cap(X86_FEATURE_ZEN5); | |
| 580 | + break; | |
| 581 | + default: | |
| 582 | + goto warn; | |
| 583 | + } | |
| 584 | + break; | |
| 585 | + | |
| 573 | 586 | default: |
| 574 | 587 | break; |
| 575 | 588 | } |
| @@ -1039,6 +1052,11 @@ static void init_amd_zen4(struct cpuinfo_x86 *c) · 463 unmodified lines | ||
| 1039 | 1052 | msr_set_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT); |
| 1040 | 1053 | } |
| 1041 | 1054 | |
| 1055 | +static void init_amd_zen5(struct cpuinfo_x86 *c) | |
| 1056 | +{ | |
| 1057 | + init_amd_zen_common(); | |
| 1058 | +} | |
| 1059 | + | |
| 1042 | 1060 | static void init_amd(struct cpuinfo_x86 *c) |
| 1043 | 1061 | { |
| 1044 | 1062 | u64 vm_cr; |
| @@ -1084,6 +1102,8 @@ static void init_amd(struct cpuinfo_x86 *c) · 39 unmodified lines | ||
| 1084 | 1102 | init_amd_zen3(c); |
| 1085 | 1103 | else if (boot_cpu_has(X86_FEATURE_ZEN4)) |
| 1086 | 1104 | init_amd_zen4(c); |
| 1105 | + else if (boot_cpu_has(X86_FEATURE_ZEN5)) | |
| 1106 | + init_amd_zen5(c); | |
| 1087 | 1107 | |
| 1088 | 1108 | /* |
| 1089 | 1109 | * Enable workaround for FXSAVE leak on CPUs |
| @@ -205,12 +205,19 @@ static int bio_copy_user_iov(struct request *rq, struct rq_map_data *map_data, · 204 unmodified lines | ||
| 205 | 205 | /* |
| 206 | 206 | * success |
| 207 | 207 | */ |
| 208 | − if ((iov_iter_rw(iter) == WRITE && | |
| 209 | − (!map_data || !map_data->null_mapped)) || | |
| 210 | − (map_data && map_data->from_user)) { | |
| 208 | + if (iov_iter_rw(iter) == WRITE && | |
| 209 | + (!map_data || !map_data->null_mapped)) { | |
| 211 | 210 | ret = bio_copy_from_iter(bio, iter); |
| 212 | 211 | if (ret) |
| 213 | 212 | goto cleanup; |
| 213 | + } else if (map_data && map_data->from_user) { | |
| 214 | + struct iov_iter iter2 = *iter; | |
| 215 | + | |
| 216 | + /* This is the copy-in part of SG_DXFER_TO_FROM_DEV. */ | |
| 217 | + iter2.data_source = ITER_SOURCE; | |
| 218 | + ret = bio_copy_from_iter(bio, &iter2); | |
| 219 | + if (ret) | |
| 220 | + goto cleanup; | |
| 214 | 221 | } else { |
| 215 | 222 | if (bmd->is_our_pages) |
| 216 | 223 | zero_fill_bio(bio); |
| @@ -20,8 +20,6 @@ static int blkpg_do_ioctl(struct block_device *bdev, · 19 unmodified lines | ||
| 20 | 20 | struct blkpg_partition p; |
| 21 | 21 | sector_t start, length; |
| 22 | 22 | |
| 23 | − if (disk->flags & GENHD_FL_NO_PART) | |
| 24 | − return -EINVAL; | |
| 25 | 23 | if (!capable(CAP_SYS_ADMIN)) |
| 26 | 24 | return -EACCES; |
| 27 | 25 | if (copy_from_user(&p, upart, sizeof(struct blkpg_partition))) |
| @@ -439,6 +439,11 @@ int bdev_add_partition(struct gendisk *disk, int partno, sector_t start, · 438 unmodified lines | ||
| 439 | 439 | goto out; |
| 440 | 440 | } |
| 441 | 441 | |
| 442 | + if (disk->flags & GENHD_FL_NO_PART) { | |
| 443 | + ret = -EINVAL; | |
| 444 | + goto out; | |
| 445 | + } | |
| 446 | + | |
| 442 | 447 | if (partition_overlaps(disk, start, length, -1)) { |
| 443 | 448 | ret = -EBUSY; |
| 444 | 449 | goto out; |
| @@ -102,7 +102,7 @@ static int reset_pending_show(struct seq_file *s, void *v) · 101 unmodified lines | ||
| 102 | 102 | { |
| 103 | 103 | struct ivpu_device *vdev = seq_to_ivpu(s); |
| 104 | 104 | |
| 105 | − seq_printf(s, "%d\n", atomic_read(&vdev->pm->in_reset)); | |
| 105 | + seq_printf(s, "%d\n", atomic_read(&vdev->pm->reset_pending)); | |
| 106 | 106 | return 0; |
| 107 | 107 | } |
| 108 | 108 | |
| @@ -130,7 +130,9 @@ dvfs_mode_fops_write(struct file *file, const char __user *user_buf, size_t size · 21 unmodified lines | ||
| 130 | 130 | |
| 131 | 131 | fw->dvfs_mode = dvfs_mode; |
| 132 | 132 | |
| 133 | − ivpu_pm_schedule_recovery(vdev); | |
| 133 | + ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev)); | |
| 134 | + if (ret) | |
| 135 | + return ret; | |
| 134 | 136 | |
| 135 | 137 | return size; |
| 136 | 138 | } |
| @@ -190,7 +192,10 @@ fw_profiling_freq_fops_write(struct file *file, const char __user *user_buf, · 53 unmodified lines | ||
| 190 | 192 | return ret; |
| 191 | 193 | |
| 192 | 194 | ivpu_hw_profiling_freq_drive(vdev, enable); |
| 193 | − ivpu_pm_schedule_recovery(vdev); | |
| 195 | + | |
| 196 | + ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev)); | |
| 197 | + if (ret) | |
| 198 | + return ret; | |
| 194 | 199 | |
| 195 | 200 | return size; |
| 196 | 201 | } |
| @@ -301,11 +306,18 @@ static ssize_t · 104 unmodified lines | ||
| 301 | 306 | ivpu_force_recovery_fn(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) |
| 302 | 307 | { |
| 303 | 308 | struct ivpu_device *vdev = file->private_data; |
| 309 | + int ret; | |
| 304 | 310 | |
| 305 | 311 | if (!size) |
| 306 | 312 | return -EINVAL; |
| 307 | 313 | |
| 308 | − ivpu_pm_schedule_recovery(vdev); | |
| 314 | + ret = ivpu_rpm_get(vdev); | |
| 315 | + if (ret) | |
| 316 | + return ret; | |
| 317 | + | |
| 318 | + ivpu_pm_trigger_recovery(vdev, "debugfs"); | |
| 319 | + flush_work(&vdev->pm->recovery_work); | |
| 320 | + ivpu_rpm_put(vdev); | |
| 309 | 321 | return size; |
| 310 | 322 | } |
| 311 | 323 | |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | #include <linux/firmware.h> |
| 7 | 7 | #include <linux/module.h> |
| 8 | 8 | #include <linux/pci.h> |
| 9 | +#include <linux/pm_runtime.h> | |
| 9 | 10 | |
| 10 | 11 | #include <drm/drm_accel.h> |
| 11 | 12 | #include <drm/drm_file.h> |
| @@ -17,6 +18,7 @@ · 5 unmodified lines | ||
| 17 | 18 | #include "ivpu_debugfs.h" |
| 18 | 19 | #include "ivpu_drv.h" |
| 19 | 20 | #include "ivpu_fw.h" |
| 21 | +#include "ivpu_fw_log.h" | |
| 20 | 22 | #include "ivpu_gem.h" |
| 21 | 23 | #include "ivpu_hw.h" |
| 22 | 24 | #include "ivpu_ipc.h" |
| @@ -65,22 +67,20 @@ struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv) · 42 unmodified lines | ||
| 65 | 67 | return file_priv; |
| 66 | 68 | } |
| 67 | 69 | |
| 68 | −struct ivpu_file_priv *ivpu_file_priv_get_by_ctx_id(struct ivpu_device *vdev, unsigned long id) | |
| 70 | +static void file_priv_unbind(struct ivpu_device *vdev, struct ivpu_file_priv *file_priv) | |
| 69 | 71 | { |
| 70 | − struct ivpu_file_priv *file_priv; | |
| 71 | − | |
| 72 | − xa_lock_irq(&vdev->context_xa); | |
| 73 | − file_priv = xa_load(&vdev->context_xa, id); | |
| 74 | − /* file_priv may still be in context_xa during file_priv_release() */ | |
| 75 | − if (file_priv && !kref_get_unless_zero(&file_priv->ref)) | |
| 76 | − file_priv = NULL; | |
| 77 | − xa_unlock_irq(&vdev->context_xa); | |
| 78 | − | |
| 79 | − if (file_priv) | |
| 80 | − ivpu_dbg(vdev, KREF, "file_priv get by id: ctx %u refcount %u\n", | |
| 81 | − file_priv->ctx.id, kref_read(&file_priv->ref)); | |
| 82 | − | |
| 83 | − return file_priv; | |
| 72 | + mutex_lock(&file_priv->lock); | |
| 73 | + if (file_priv->bound) { | |
| 74 | + ivpu_dbg(vdev, FILE, "file_priv unbind: ctx %u\n", file_priv->ctx.id); | |
| 75 | + | |
| 76 | + ivpu_cmdq_release_all_locked(file_priv); | |
| 77 | + ivpu_jsm_context_release(vdev, file_priv->ctx.id); | |
| 78 | + ivpu_bo_unbind_all_bos_from_context(vdev, &file_priv->ctx); | |
| 79 | + ivpu_mmu_user_context_fini(vdev, &file_priv->ctx); | |
| 80 | + file_priv->bound = false; | |
| 81 | + drm_WARN_ON(&vdev->drm, !xa_erase_irq(&vdev->context_xa, file_priv->ctx.id)); | |
| 82 | + } | |
| 83 | + mutex_unlock(&file_priv->lock); | |
| 84 | 84 | } |
| 85 | 85 | |
| 86 | 86 | static void file_priv_release(struct kref *ref) |
| @@ -88,13 +88,15 @@ static void file_priv_release(struct kref *ref) · 1 unmodified line | ||
| 88 | 88 | struct ivpu_file_priv *file_priv = container_of(ref, struct ivpu_file_priv, ref); |
| 89 | 89 | struct ivpu_device *vdev = file_priv->vdev; |
| 90 | 90 | |
| 91 | − ivpu_dbg(vdev, FILE, "file_priv release: ctx %u\n", file_priv->ctx.id); | |
| 91 | + ivpu_dbg(vdev, FILE, "file_priv release: ctx %u bound %d\n", | |
| 92 | + file_priv->ctx.id, (bool)file_priv->bound); | |
| 93 | + | |
| 94 | + pm_runtime_get_sync(vdev->drm.dev); | |
| 95 | + mutex_lock(&vdev->context_list_lock); | |
| 96 | + file_priv_unbind(vdev, file_priv); | |
| 97 | + mutex_unlock(&vdev->context_list_lock); | |
| 98 | + pm_runtime_put_autosuspend(vdev->drm.dev); | |
| 92 | 99 | |
| 93 | − ivpu_cmdq_release_all(file_priv); | |
| 94 | − ivpu_jsm_context_release(vdev, file_priv->ctx.id); | |
| 95 | − ivpu_bo_remove_all_bos_from_context(vdev, &file_priv->ctx); | |
| 96 | − ivpu_mmu_user_context_fini(vdev, &file_priv->ctx); | |
| 97 | − drm_WARN_ON(&vdev->drm, xa_erase_irq(&vdev->context_xa, file_priv->ctx.id) != file_priv); | |
| 98 | 100 | mutex_destroy(&file_priv->lock); |
| 99 | 101 | kfree(file_priv); |
| 100 | 102 | } |
| @@ -176,9 +178,6 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f · 75 unmodified lines | ||
| 176 | 178 | case DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS: |
| 177 | 179 | args->value = vdev->hw->ranges.user.start; |
| 178 | 180 | break; |
| 179 | − case DRM_IVPU_PARAM_CONTEXT_PRIORITY: | |
| 180 | − args->value = file_priv->priority; | |
| 181 | − break; | |
| 182 | 181 | case DRM_IVPU_PARAM_CONTEXT_ID: |
| 183 | 182 | args->value = file_priv->ctx.id; |
| 184 | 183 | break; |
| @@ -218,17 +217,10 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f · 33 unmodified lines | ||
| 218 | 217 | |
| 219 | 218 | static int ivpu_set_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file) |
| 220 | 219 | { |
| 221 | − struct ivpu_file_priv *file_priv = file->driver_priv; | |
| 222 | 220 | struct drm_ivpu_param *args = data; |
| 223 | 221 | int ret = 0; |
| 224 | 222 | |
| 225 | 223 | switch (args->param) { |
| 226 | − case DRM_IVPU_PARAM_CONTEXT_PRIORITY: | |
| 227 | − if (args->value <= DRM_IVPU_CONTEXT_PRIORITY_REALTIME) | |
| 228 | − file_priv->priority = args->value; | |
| 229 | − else | |
| 230 | − ret = -EINVAL; | |
| 231 | − break; | |
| 232 | 224 | default: |
| 233 | 225 | ret = -EINVAL; |
| 234 | 226 | } |
| @@ -241,50 +233,53 @@ static int ivpu_open(struct drm_device *dev, struct drm_file *file) · 6 unmodified lines | ||
| 241 | 233 | struct ivpu_device *vdev = to_ivpu_device(dev); |
| 242 | 234 | struct ivpu_file_priv *file_priv; |
| 243 | 235 | u32 ctx_id; |
| 244 | − void *old; | |
| 245 | − int ret; | |
| 236 | + int idx, ret; | |
| 246 | 237 | |
| 247 | − ret = xa_alloc_irq(&vdev->context_xa, &ctx_id, NULL, vdev->context_xa_limit, GFP_KERNEL); | |
| 248 | − if (ret) { | |
| 249 | − ivpu_err(vdev, "Failed to allocate context id: %d\n", ret); | |
| 250 | − return ret; | |
| 251 | − } | |
| 238 | + if (!drm_dev_enter(dev, &idx)) | |
| 239 | + return -ENODEV; | |
| 252 | 240 | |
| 253 | 241 | file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); |
| 254 | 242 | if (!file_priv) { |
| 255 | 243 | ret = -ENOMEM; |
| 256 | − goto err_xa_erase; | |
| 244 | + goto err_dev_exit; | |
| 257 | 245 | } |
| 258 | 246 | |
| 259 | 247 | file_priv->vdev = vdev; |
| 260 | − file_priv->priority = DRM_IVPU_CONTEXT_PRIORITY_NORMAL; | |
| 248 | + file_priv->bound = true; | |
| 261 | 249 | kref_init(&file_priv->ref); |
| 262 | 250 | mutex_init(&file_priv->lock); |
| 263 | 251 | |
| 252 | + mutex_lock(&vdev->context_list_lock); | |
| 253 | + | |
| 254 | + ret = xa_alloc_irq(&vdev->context_xa, &ctx_id, file_priv, | |
| 255 | + vdev->context_xa_limit, GFP_KERNEL); | |
| 256 | + if (ret) { | |
| 257 | + ivpu_err(vdev, "Failed to allocate context id: %d\n", ret); | |
| 258 | + goto err_unlock; | |
| 259 | + } | |
| 260 | + | |
| 264 | 261 | ret = ivpu_mmu_user_context_init(vdev, &file_priv->ctx, ctx_id); |
| 265 | 262 | if (ret) |
| 266 | − goto err_mutex_destroy; | |
| 263 | + goto err_xa_erase; | |
| 267 | 264 | |
| 268 | − old = xa_store_irq(&vdev->context_xa, ctx_id, file_priv, GFP_KERNEL); | |
| 269 | − if (xa_is_err(old)) { | |
| 270 | − ret = xa_err(old); | |
| 271 | − ivpu_err(vdev, "Failed to store context %u: %d\n", ctx_id, ret); | |
| 272 | − goto err_ctx_fini; | |
| 273 | − } | |
| 265 | + mutex_unlock(&vdev->context_list_lock); | |
| 266 | + drm_dev_exit(idx); | |
| 267 | + | |
| 268 | + file->driver_priv = file_priv; | |
| 274 | 269 | |
| 275 | 270 | ivpu_dbg(vdev, FILE, "file_priv create: ctx %u process %s pid %d\n", |
| 276 | 271 | ctx_id, current->comm, task_pid_nr(current)); |
| 277 | 272 | |
| 278 | − file->driver_priv = file_priv; | |
| 279 | 273 | return 0; |
| 280 | 274 | |
| 281 | −err_ctx_fini: | |
| 282 | − ivpu_mmu_user_context_fini(vdev, &file_priv->ctx); | |
| 283 | −err_mutex_destroy: | |
| 284 | − mutex_destroy(&file_priv->lock); | |
| 285 | − kfree(file_priv); | |
| 286 | 275 | err_xa_erase: |
| 287 | 276 | xa_erase_irq(&vdev->context_xa, ctx_id); |
| 277 | +err_unlock: | |
| 278 | + mutex_unlock(&vdev->context_list_lock); | |
| 279 | + mutex_destroy(&file_priv->lock); | |
| 280 | + kfree(file_priv); | |
| 281 | +err_dev_exit: | |
| 282 | + drm_dev_exit(idx); | |
| 288 | 283 | return ret; |
| 289 | 284 | } |
| 290 | 285 | |
| @@ -340,8 +335,6 @@ static int ivpu_wait_for_ready(struct ivpu_device *vdev) · 49 unmodified lines | ||
| 340 | 335 | |
| 341 | 336 | if (!ret) |
| 342 | 337 | ivpu_dbg(vdev, PM, "VPU ready message received successfully\n"); |
| 343 | − else | |
| 344 | − ivpu_hw_diagnose_failure(vdev); | |
| 345 | 338 | |
| 346 | 339 | return ret; |
| 347 | 340 | } |
| @@ -369,6 +362,9 @@ int ivpu_boot(struct ivpu_device *vdev) · 21 unmodified lines | ||
| 369 | 362 | ret = ivpu_wait_for_ready(vdev); |
| 370 | 363 | if (ret) { |
| 371 | 364 | ivpu_err(vdev, "Failed to boot the firmware: %d\n", ret); |
| 365 | + ivpu_hw_diagnose_failure(vdev); | |
| 366 | + ivpu_mmu_evtq_dump(vdev); | |
| 367 | + ivpu_fw_log_dump(vdev); | |
| 372 | 368 | return ret; |
| 373 | 369 | } |
| 374 | 370 | |
| @@ -540,6 +536,10 @@ static int ivpu_dev_init(struct ivpu_device *vdev) · 165 unmodified lines | ||
| 540 | 536 | lockdep_set_class(&vdev->submitted_jobs_xa.xa_lock, &submitted_jobs_xa_lock_class_key); |
| 541 | 537 | INIT_LIST_HEAD(&vdev->bo_list); |
| 542 | 538 | |
| 539 | + ret = drmm_mutex_init(&vdev->drm, &vdev->context_list_lock); | |
| 540 | + if (ret) | |
| 541 | + goto err_xa_destroy; | |
| 542 | + | |
| 543 | 543 | ret = drmm_mutex_init(&vdev->drm, &vdev->bo_list_lock); |
| 544 | 544 | if (ret) |
| 545 | 545 | goto err_xa_destroy; |
| @@ -611,14 +611,30 @@ err_xa_destroy: · 65 unmodified lines | ||
| 611 | 611 | return ret; |
| 612 | 612 | } |
| 613 | 613 | |
| 614 | +static void ivpu_bo_unbind_all_user_contexts(struct ivpu_device *vdev) | |
| 615 | +{ | |
| 616 | + struct ivpu_file_priv *file_priv; | |
| 617 | + unsigned long ctx_id; | |
| 618 | + | |
| 619 | + mutex_lock(&vdev->context_list_lock); | |
| 620 | + | |
| 621 | + xa_for_each(&vdev->context_xa, ctx_id, file_priv) | |
| 622 | + file_priv_unbind(vdev, file_priv); | |
| 623 | + | |
| 624 | + mutex_unlock(&vdev->context_list_lock); | |
| 625 | +} | |
| 626 | + | |
| 614 | 627 | static void ivpu_dev_fini(struct ivpu_device *vdev) |
| 615 | 628 | { |
| 616 | 629 | ivpu_pm_disable(vdev); |
| 617 | 630 | ivpu_shutdown(vdev); |
| 618 | 631 | if (IVPU_WA(d3hot_after_power_off)) |
| 619 | 632 | pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot); |
| 633 | + | |
| 634 | + ivpu_jobs_abort_all(vdev); | |
| 620 | 635 | ivpu_job_done_consumer_fini(vdev); |
| 621 | 636 | ivpu_pm_cancel_recovery(vdev); |
| 637 | + ivpu_bo_unbind_all_user_contexts(vdev); | |
| 622 | 638 | |
| 623 | 639 | ivpu_ipc_fini(vdev); |
| 624 | 640 | ivpu_fw_fini(vdev); |
| @@ -56,6 +56,7 @@ · 55 unmodified lines | ||
| 56 | 56 | #define IVPU_DBG_JSM BIT(10) |
| 57 | 57 | #define IVPU_DBG_KREF BIT(11) |
| 58 | 58 | #define IVPU_DBG_RPM BIT(12) |
| 59 | +#define IVPU_DBG_MMU_MAP BIT(13) | |
| 59 | 60 | |
| 60 | 61 | #define ivpu_err(vdev, fmt, ...) \ |
| 61 | 62 | drm_err(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__) |
| @@ -114,6 +115,7 @@ struct ivpu_device { · 52 unmodified lines | ||
| 114 | 115 | |
| 115 | 116 | struct ivpu_mmu_context gctx; |
| 116 | 117 | struct ivpu_mmu_context rctx; |
| 118 | + struct mutex context_list_lock; /* Protects user context addition/removal */ | |
| 117 | 119 | struct xarray context_xa; |
| 118 | 120 | struct xa_limit context_xa_limit; |
| 119 | 121 | |
| @@ -145,8 +147,8 @@ struct ivpu_file_priv { · 25 unmodified lines | ||
| 145 | 147 | struct mutex lock; /* Protects cmdq */ |
| 146 | 148 | struct ivpu_cmdq *cmdq[IVPU_NUM_ENGINES]; |
| 147 | 149 | struct ivpu_mmu_context ctx; |
| 148 | − u32 priority; | |
| 149 | 150 | bool has_mmu_faults; |
| 151 | + bool bound; | |
| 150 | 152 | }; |
| 151 | 153 | |
| 152 | 154 | extern int ivpu_dbg_mask; |
| @@ -162,7 +164,6 @@ extern bool ivpu_disable_mmu_cont_pages; · 9 unmodified lines | ||
| 162 | 164 | extern int ivpu_test_mode; |
| 163 | 165 | |
| 164 | 166 | struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv); |
| 165 | −struct ivpu_file_priv *ivpu_file_priv_get_by_ctx_id(struct ivpu_device *vdev, unsigned long id); | |
| 166 | 167 | void ivpu_file_priv_put(struct ivpu_file_priv **link); |
| 167 | 168 | |
| 168 | 169 | int ivpu_boot(struct ivpu_device *vdev); |
| @@ -24,14 +24,11 @@ static const struct drm_gem_object_funcs ivpu_gem_funcs; · 23 unmodified lines | ||
| 24 | 24 | |
| 25 | 25 | static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, const char *action) |
| 26 | 26 | { |
| 27 | − if (bo->ctx) | |
| 28 | − ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u ctx %d vpu_addr 0x%llx mmu_mapped %d\n", | |
| 29 | − action, ivpu_bo_size(bo), (bool)bo->base.pages, (bool)bo->base.sgt, | |
| 30 | − bo->handle, bo->ctx->id, bo->vpu_addr, bo->mmu_mapped); | |
| 31 | − else | |
| 32 | − ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u (not added to context)\n", | |
| 33 | − action, ivpu_bo_size(bo), (bool)bo->base.pages, (bool)bo->base.sgt, | |
| 34 | − bo->handle); | |
| 27 | + ivpu_dbg(vdev, BO, | |
| 28 | + "%6s: bo %8p vpu_addr %9llx size %8zu ctx %d has_pages %d dma_mapped %d mmu_mapped %d wc %d imported %d\n", | |
| 29 | + action, bo, bo->vpu_addr, ivpu_bo_size(bo), bo->ctx ? bo->ctx->id : 0, | |
| 30 | + (bool)bo->base.pages, (bool)bo->base.sgt, bo->mmu_mapped, bo->base.map_wc, | |
| 31 | + (bool)bo->base.base.import_attach); | |
| 35 | 32 | } |
| 36 | 33 | |
| 37 | 34 | /* |
| @@ -49,12 +46,7 @@ int __must_check ivpu_bo_pin(struct ivpu_bo *bo) · 11 unmodified lines | ||
| 49 | 46 | mutex_lock(&bo->lock); |
| 50 | 47 | |
| 51 | 48 | ivpu_dbg_bo(vdev, bo, "pin"); |
| 52 | − | |
| 53 | − if (!bo->ctx) { | |
| 54 | − ivpu_err(vdev, "vpu_addr not allocated for BO %d\n", bo->handle); | |
| 55 | − ret = -EINVAL; | |
| 56 | − goto unlock; | |
| 57 | − } | |
| 49 | + drm_WARN_ON(&vdev->drm, !bo->ctx); | |
| 58 | 50 | |
| 59 | 51 | if (!bo->mmu_mapped) { |
| 60 | 52 | struct sg_table *sgt = drm_gem_shmem_get_pages_sgt(&bo->base); |
| @@ -85,7 +77,10 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, · 24 unmodified lines | ||
| 85 | 77 | const struct ivpu_addr_range *range) |
| 86 | 78 | { |
| 87 | 79 | struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); |
| 88 | − int ret; | |
| 80 | + int idx, ret; | |
| 81 | + | |
| 82 | + if (!drm_dev_enter(&vdev->drm, &idx)) | |
| 83 | + return -ENODEV; | |
| 89 | 84 | |
| 90 | 85 | mutex_lock(&bo->lock); |
| 91 | 86 | |
| @@ -101,6 +96,8 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, · 9 unmodified lines | ||
| 101 | 96 | |
| 102 | 97 | mutex_unlock(&bo->lock); |
| 103 | 98 | |
| 99 | + drm_dev_exit(idx); | |
| 100 | + | |
| 104 | 101 | return ret; |
| 105 | 102 | } |
| 106 | 103 | |
| @@ -108,11 +105,7 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo) · 1 unmodified line | ||
| 108 | 105 | { |
| 109 | 106 | struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); |
| 110 | 107 | |
| 111 | − lockdep_assert_held(&bo->lock); | |
| 112 | − | |
| 113 | − ivpu_dbg_bo(vdev, bo, "unbind"); | |
| 114 | − | |
| 115 | − /* TODO: dma_unmap */ | |
| 108 | + lockdep_assert(lockdep_is_held(&bo->lock) || !kref_read(&bo->base.base.refcount)); | |
| 116 | 109 | |
| 117 | 110 | if (bo->mmu_mapped) { |
| 118 | 111 | drm_WARN_ON(&vdev->drm, !bo->ctx); |
| @@ -124,19 +117,23 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo) · 5 unmodified lines | ||
| 124 | 117 | |
| 125 | 118 | if (bo->ctx) { |
| 126 | 119 | ivpu_mmu_context_remove_node(bo->ctx, &bo->mm_node); |
| 127 | − bo->vpu_addr = 0; | |
| 128 | 120 | bo->ctx = NULL; |
| 129 | 121 | } |
| 130 | −} | |
| 131 | 122 | |
| 132 | −static void ivpu_bo_unbind(struct ivpu_bo *bo) | |
| 133 | −{ | |
| 134 | − mutex_lock(&bo->lock); | |
| 135 | − ivpu_bo_unbind_locked(bo); | |
| 136 | − mutex_unlock(&bo->lock); | |
| 123 | + if (bo->base.base.import_attach) | |
| 124 | + return; | |
| 125 | + | |
| 126 | + dma_resv_lock(bo->base.base.resv, NULL); | |
| 127 | + if (bo->base.sgt) { | |
| 128 | + dma_unmap_sgtable(vdev->drm.dev, bo->base.sgt, DMA_BIDIRECTIONAL, 0); | |
| 129 | + sg_free_table(bo->base.sgt); | |
| 130 | + kfree(bo->base.sgt); | |
| 131 | + bo->base.sgt = NULL; | |
| 132 | + } | |
| 133 | + dma_resv_unlock(bo->base.base.resv); | |
| 137 | 134 | } |
| 138 | 135 | |
| 139 | −void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx) | |
| 136 | +void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx) | |
| 140 | 137 | { |
| 141 | 138 | struct ivpu_bo *bo; |
| 142 | 139 | |
| @@ -146,8 +143,10 @@ void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_m · 3 unmodified lines | ||
| 146 | 143 | mutex_lock(&vdev->bo_list_lock); |
| 147 | 144 | list_for_each_entry(bo, &vdev->bo_list, bo_list_node) { |
| 148 | 145 | mutex_lock(&bo->lock); |
| 149 | − if (bo->ctx == ctx) | |
| 146 | + if (bo->ctx == ctx) { | |
| 147 | + ivpu_dbg_bo(vdev, bo, "unbind"); | |
| 150 | 148 | ivpu_bo_unbind_locked(bo); |
| 149 | + } | |
| 151 | 150 | mutex_unlock(&bo->lock); |
| 152 | 151 | } |
| 153 | 152 | mutex_unlock(&vdev->bo_list_lock); |
| @@ -199,9 +198,6 @@ ivpu_bo_create(struct ivpu_device *vdev, u64 size, u32 flags) · 45 unmodified lines | ||
| 199 | 198 | list_add_tail(&bo->bo_list_node, &vdev->bo_list); |
| 200 | 199 | mutex_unlock(&vdev->bo_list_lock); |
| 201 | 200 | |
| 202 | − ivpu_dbg(vdev, BO, "create: vpu_addr 0x%llx size %zu flags 0x%x\n", | |
| 203 | − bo->vpu_addr, bo->base.base.size, flags); | |
| 204 | − | |
| 205 | 201 | return bo; |
| 206 | 202 | } |
| 207 | 203 | |
| @@ -212,6 +208,12 @@ static int ivpu_bo_open(struct drm_gem_object *obj, struct drm_file *file) · 4 unmodified lines | ||
| 212 | 208 | struct ivpu_bo *bo = to_ivpu_bo(obj); |
| 213 | 209 | struct ivpu_addr_range *range; |
| 214 | 210 | |
| 211 | + if (bo->ctx) { | |
| 212 | + ivpu_warn(vdev, "Can't add BO to ctx %u: already in ctx %u\n", | |
| 213 | + file_priv->ctx.id, bo->ctx->id); | |
| 214 | + return -EALREADY; | |
| 215 | + } | |
| 216 | + | |
| 215 | 217 | if (bo->flags & DRM_IVPU_BO_SHAVE_MEM) |
| 216 | 218 | range = &vdev->hw->ranges.shave; |
| 217 | 219 | else if (bo->flags & DRM_IVPU_BO_DMA_MEM) |
| @@ -227,62 +229,24 @@ static void ivpu_bo_free(struct drm_gem_object *obj) · 9 unmodified lines | ||
| 227 | 229 | struct ivpu_device *vdev = to_ivpu_device(obj->dev); |
| 228 | 230 | struct ivpu_bo *bo = to_ivpu_bo(obj); |
| 229 | 231 | |
| 232 | + ivpu_dbg_bo(vdev, bo, "free"); | |
| 233 | + | |
| 230 | 234 | mutex_lock(&vdev->bo_list_lock); |
| 231 | 235 | list_del(&bo->bo_list_node); |
| 232 | 236 | mutex_unlock(&vdev->bo_list_lock); |
| 233 | 237 | |
| 234 | 238 | drm_WARN_ON(&vdev->drm, !dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ)); |
| 235 | 239 | |
| 236 | − ivpu_dbg_bo(vdev, bo, "free"); | |
| 237 | − | |
| 238 | − ivpu_bo_unbind(bo); | |
| 240 | + ivpu_bo_unbind_locked(bo); | |
| 239 | 241 | mutex_destroy(&bo->lock); |
| 240 | 242 | |
| 241 | 243 | drm_WARN_ON(obj->dev, bo->base.pages_use_count > 1); |
| 242 | 244 | drm_gem_shmem_free(&bo->base); |
| 243 | 245 | } |
| 244 | 246 | |
| 245 | −static const struct dma_buf_ops ivpu_bo_dmabuf_ops = { | |
| 246 | − .cache_sgt_mapping = true, | |
| 247 | − .attach = drm_gem_map_attach, | |
| 248 | − .detach = drm_gem_map_detach, | |
| 249 | − .map_dma_buf = drm_gem_map_dma_buf, | |
| 250 | − .unmap_dma_buf = drm_gem_unmap_dma_buf, | |
| 251 | − .release = drm_gem_dmabuf_release, | |
| 252 | − .mmap = drm_gem_dmabuf_mmap, | |
| 253 | − .vmap = drm_gem_dmabuf_vmap, | |
| 254 | − .vunmap = drm_gem_dmabuf_vunmap, | |
| 255 | −}; | |
| 256 | − | |
| 257 | −static struct dma_buf *ivpu_bo_export(struct drm_gem_object *obj, int flags) | |
| 258 | −{ | |
| 259 | − struct drm_device *dev = obj->dev; | |
| 260 | − struct dma_buf_export_info exp_info = { | |
| 261 | − .exp_name = KBUILD_MODNAME, | |
| 262 | − .owner = dev->driver->fops->owner, | |
| 263 | − .ops = &ivpu_bo_dmabuf_ops, | |
| 264 | − .size = obj->size, | |
| 265 | − .flags = flags, | |
| 266 | − .priv = obj, | |
| 267 | − .resv = obj->resv, | |
| 268 | − }; | |
| 269 | − void *sgt; | |
| 270 | − | |
| 271 | − /* | |
| 272 | − * Make sure that pages are allocated and dma-mapped before exporting the bo. | |
| 273 | − * DMA-mapping is required if the bo will be imported to the same device. | |
| 274 | − */ | |
| 275 | − sgt = drm_gem_shmem_get_pages_sgt(to_drm_gem_shmem_obj(obj)); | |
| 276 | − if (IS_ERR(sgt)) | |
| 277 | − return sgt; | |
| 278 | − | |
| 279 | − return drm_gem_dmabuf_export(dev, &exp_info); | |
| 280 | −} | |
| 281 | − | |
| 282 | 247 | static const struct drm_gem_object_funcs ivpu_gem_funcs = { |
| 283 | 248 | .free = ivpu_bo_free, |
| 284 | 249 | .open = ivpu_bo_open, |
| 285 | − .export = ivpu_bo_export, | |
| 286 | 250 | .print_info = drm_gem_shmem_object_print_info, |
| 287 | 251 | .pin = drm_gem_shmem_object_pin, |
| 288 | 252 | .unpin = drm_gem_shmem_object_unpin, |
| @@ -315,11 +279,9 @@ int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fi · 26 unmodified lines | ||
| 315 | 279 | return PTR_ERR(bo); |
| 316 | 280 | } |
| 317 | 281 | |
| 318 | − ret = drm_gem_handle_create(file, &bo->base.base, &bo->handle); | |
| 319 | − if (!ret) { | |
| 282 | + ret = drm_gem_handle_create(file, &bo->base.base, &args->handle); | |
| 283 | + if (!ret) | |
| 320 | 284 | args->vpu_addr = bo->vpu_addr; |
| 321 | − args->handle = bo->handle; | |
| 322 | − } | |
| 323 | 285 | |
| 324 | 286 | drm_gem_object_put(&bo->base.base); |
| 325 | 287 | |
| @@ -361,7 +323,9 @@ ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 fla · 35 unmodified lines | ||
| 361 | 323 | if (ret) |
| 362 | 324 | goto err_put; |
| 363 | 325 | |
| 326 | + dma_resv_lock(bo->base.base.resv, NULL); | |
| 364 | 327 | ret = drm_gem_shmem_vmap(&bo->base, &map); |
| 328 | + dma_resv_unlock(bo->base.base.resv); | |
| 365 | 329 | if (ret) |
| 366 | 330 | goto err_put; |
| 367 | 331 | |
| @@ -376,7 +340,10 @@ void ivpu_bo_free_internal(struct ivpu_bo *bo) · 8 unmodified lines | ||
| 376 | 340 | { |
| 377 | 341 | struct iosys_map map = IOSYS_MAP_INIT_VADDR(bo->base.vaddr); |
| 378 | 342 | |
| 343 | + dma_resv_lock(bo->base.base.resv, NULL); | |
| 379 | 344 | drm_gem_shmem_vunmap(&bo->base, &map); |
| 345 | + dma_resv_unlock(bo->base.base.resv); | |
| 346 | + | |
| 380 | 347 | drm_gem_object_put(&bo->base.base); |
| 381 | 348 | } |
| 382 | 349 | |
| @@ -432,19 +399,11 @@ int ivpu_bo_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file · 49 unmodified lines | ||
| 432 | 399 | |
| 433 | 400 | static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p) |
| 434 | 401 | { |
| 435 | − unsigned long dma_refcount = 0; | |
| 436 | − | |
| 437 | 402 | mutex_lock(&bo->lock); |
| 438 | 403 | |
| 439 | − if (bo->base.base.dma_buf && bo->base.base.dma_buf->file) | |
| 440 | − dma_refcount = atomic_long_read(&bo->base.base.dma_buf->file->f_count); | |
| 441 | − | |
| 442 | − drm_printf(p, "%-3u %-6d 0x%-12llx %-10lu 0x%-8x %-4u %-8lu", | |
| 443 | − bo->ctx->id, bo->handle, bo->vpu_addr, bo->base.base.size, | |
| 444 | − bo->flags, kref_read(&bo->base.base.refcount), dma_refcount); | |
| 445 | − | |
| 446 | − if (bo->base.base.import_attach) | |
| 447 | − drm_printf(p, " imported"); | |
| 404 | + drm_printf(p, "%-9p %-3u 0x%-12llx %-10lu 0x%-8x %-4u", | |
| 405 | + bo, bo->ctx->id, bo->vpu_addr, bo->base.base.size, | |
| 406 | + bo->flags, kref_read(&bo->base.base.refcount)); | |
| 448 | 407 | |
| 449 | 408 | if (bo->base.pages) |
| 450 | 409 | drm_printf(p, " has_pages"); |
| @@ -452,6 +411,9 @@ static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p) · 1 unmodified line | ||
| 452 | 411 | if (bo->mmu_mapped) |
| 453 | 412 | drm_printf(p, " mmu_mapped"); |
| 454 | 413 | |
| 414 | + if (bo->base.base.import_attach) | |
| 415 | + drm_printf(p, " imported"); | |
| 416 | + | |
| 455 | 417 | drm_printf(p, "\n"); |
| 456 | 418 | |
| 457 | 419 | mutex_unlock(&bo->lock); |
| @@ -462,8 +424,8 @@ void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p) · 4 unmodified lines | ||
| 462 | 424 | struct ivpu_device *vdev = to_ivpu_device(dev); |
| 463 | 425 | struct ivpu_bo *bo; |
| 464 | 426 | |
| 465 | − drm_printf(p, "%-3s %-6s %-14s %-10s %-10s %-4s %-8s %s\n", | |
| 466 | − "ctx", "handle", "vpu_addr", "size", "flags", "refs", "dma_refs", "attribs"); | |
| 427 | + drm_printf(p, "%-9s %-3s %-14s %-10s %-10s %-4s %s\n", | |
| 428 | + "bo", "ctx", "vpu_addr", "size", "flags", "refs", "attribs"); | |
| 467 | 429 | |
| 468 | 430 | mutex_lock(&vdev->bo_list_lock); |
| 469 | 431 | list_for_each_entry(bo, &vdev->bo_list, bo_list_node) |
| @@ -19,14 +19,13 @@ struct ivpu_bo { · 18 unmodified lines | ||
| 19 | 19 | |
| 20 | 20 | struct mutex lock; /* Protects: ctx, mmu_mapped, vpu_addr */ |
| 21 | 21 | u64 vpu_addr; |
| 22 | − u32 handle; | |
| 23 | 22 | u32 flags; |
| 24 | 23 | u32 job_status; /* Valid only for command buffer */ |
| 25 | 24 | bool mmu_mapped; |
| 26 | 25 | }; |
| 27 | 26 | |
| 28 | 27 | int ivpu_bo_pin(struct ivpu_bo *bo); |
| 29 | −void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx); | |
| 28 | +void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx); | |
| 30 | 29 | |
| 31 | 30 | struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size); |
| 32 | 31 | struct ivpu_bo *ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 flags); |
| @@ -875,24 +875,18 @@ static void ivpu_hw_37xx_irq_disable(struct ivpu_device *vdev) · 874 unmodified lines | ||
| 875 | 875 | |
| 876 | 876 | static void ivpu_hw_37xx_irq_wdt_nce_handler(struct ivpu_device *vdev) |
| 877 | 877 | { |
| 878 | − ivpu_err_ratelimited(vdev, "WDT NCE irq\n"); | |
| 879 | − | |
| 880 | − ivpu_pm_schedule_recovery(vdev); | |
| 878 | + ivpu_pm_trigger_recovery(vdev, "WDT NCE IRQ"); | |
| 881 | 879 | } |
| 882 | 880 | |
| 883 | 881 | static void ivpu_hw_37xx_irq_wdt_mss_handler(struct ivpu_device *vdev) |
| 884 | 882 | { |
| 885 | − ivpu_err_ratelimited(vdev, "WDT MSS irq\n"); | |
| 886 | − | |
| 887 | 883 | ivpu_hw_wdt_disable(vdev); |
| 888 | − ivpu_pm_schedule_recovery(vdev); | |
| 884 | + ivpu_pm_trigger_recovery(vdev, "WDT MSS IRQ"); | |
| 889 | 885 | } |
| 890 | 886 | |
| 891 | 887 | static void ivpu_hw_37xx_irq_noc_firewall_handler(struct ivpu_device *vdev) |
| 892 | 888 | { |
| 893 | − ivpu_err_ratelimited(vdev, "NOC Firewall irq\n"); | |
| 894 | − | |
| 895 | − ivpu_pm_schedule_recovery(vdev); | |
| 889 | + ivpu_pm_trigger_recovery(vdev, "NOC Firewall IRQ"); | |
| 896 | 890 | } |
| 897 | 891 | |
| 898 | 892 | /* Handler for IRQs from VPU core (irqV) */ |
| @@ -970,7 +964,7 @@ static bool ivpu_hw_37xx_irqb_handler(struct ivpu_device *vdev, int irq) · 71 unmodified lines | ||
| 970 | 964 | REGB_WR32(VPU_37XX_BUTTRESS_INTERRUPT_STAT, status); |
| 971 | 965 | |
| 972 | 966 | if (schedule_recovery) |
| 973 | − ivpu_pm_schedule_recovery(vdev); | |
| 967 | + ivpu_pm_trigger_recovery(vdev, "Buttress IRQ"); | |
| 974 | 968 | |
| 975 | 969 | return true; |
| 976 | 970 | } |
| @@ -746,7 +746,7 @@ static int ivpu_hw_40xx_info_init(struct ivpu_device *vdev) · 745 unmodified lines | ||
| 746 | 746 | return 0; |
| 747 | 747 | } |
| 748 | 748 | |
| 749 | −static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) | |
| 749 | +static int ivpu_hw_40xx_ip_reset(struct ivpu_device *vdev) | |
| 750 | 750 | { |
| 751 | 751 | int ret; |
| 752 | 752 | u32 val; |
| @@ -768,6 +768,23 @@ static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) · 15 unmodified lines | ||
| 768 | 768 | return ret; |
| 769 | 769 | } |
| 770 | 770 | |
| 771 | +static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) | |
| 772 | +{ | |
| 773 | + int ret = 0; | |
| 774 | + | |
| 775 | + if (ivpu_hw_40xx_ip_reset(vdev)) { | |
| 776 | + ivpu_err(vdev, "Failed to reset VPU IP\n"); | |
| 777 | + ret = -EIO; | |
| 778 | + } | |
| 779 | + | |
| 780 | + if (ivpu_pll_disable(vdev)) { | |
| 781 | + ivpu_err(vdev, "Failed to disable PLL\n"); | |
| 782 | + ret = -EIO; | |
| 783 | + } | |
| 784 | + | |
| 785 | + return ret; | |
| 786 | +} | |
| 787 | + | |
| 771 | 788 | static int ivpu_hw_40xx_d0i3_enable(struct ivpu_device *vdev) |
| 772 | 789 | { |
| 773 | 790 | int ret; |
| @@ -913,7 +930,7 @@ static int ivpu_hw_40xx_power_down(struct ivpu_device *vdev) · 139 unmodified lines | ||
| 913 | 930 | |
| 914 | 931 | ivpu_hw_40xx_save_d0i3_entry_timestamp(vdev); |
| 915 | 932 | |
| 916 | − if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_reset(vdev)) | |
| 933 | + if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_ip_reset(vdev)) | |
| 917 | 934 | ivpu_warn(vdev, "Failed to reset the VPU\n"); |
| 918 | 935 | |
| 919 | 936 | if (ivpu_pll_disable(vdev)) { |
| @@ -1032,18 +1049,18 @@ static void ivpu_hw_40xx_irq_disable(struct ivpu_device *vdev) · 112 unmodified lines | ||
| 1032 | 1049 | static void ivpu_hw_40xx_irq_wdt_nce_handler(struct ivpu_device *vdev) |
| 1033 | 1050 | { |
| 1034 | 1051 | /* TODO: For LNN hang consider engine reset instead of full recovery */ |
| 1035 | − ivpu_pm_schedule_recovery(vdev); | |
| 1052 | + ivpu_pm_trigger_recovery(vdev, "WDT NCE IRQ"); | |
| 1036 | 1053 | } |
| 1037 | 1054 | |
| 1038 | 1055 | static void ivpu_hw_40xx_irq_wdt_mss_handler(struct ivpu_device *vdev) |
| 1039 | 1056 | { |
| 1040 | 1057 | ivpu_hw_wdt_disable(vdev); |
| 1041 | − ivpu_pm_schedule_recovery(vdev); | |
| 1058 | + ivpu_pm_trigger_recovery(vdev, "WDT MSS IRQ"); | |
| 1042 | 1059 | } |
| 1043 | 1060 | |
| 1044 | 1061 | static void ivpu_hw_40xx_irq_noc_firewall_handler(struct ivpu_device *vdev) |
| 1045 | 1062 | { |
| 1046 | − ivpu_pm_schedule_recovery(vdev); | |
| 1063 | + ivpu_pm_trigger_recovery(vdev, "NOC Firewall IRQ"); | |
| 1047 | 1064 | } |
| 1048 | 1065 | |
| 1049 | 1066 | /* Handler for IRQs from VPU core (irqV) */ |
| @@ -1137,7 +1154,7 @@ static bool ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq) · 87 unmodified lines | ||
| 1137 | 1154 | REGB_WR32(VPU_40XX_BUTTRESS_INTERRUPT_STAT, status); |
| 1138 | 1155 | |
| 1139 | 1156 | if (schedule_recovery) |
| 1140 | − ivpu_pm_schedule_recovery(vdev); | |
| 1157 | + ivpu_pm_trigger_recovery(vdev, "Buttress IRQ"); | |
| 1141 | 1158 | |
| 1142 | 1159 | return true; |
| 1143 | 1160 | } |
| @@ -343,10 +343,8 @@ int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *r · 342 unmodified lines | ||
| 343 | 343 | hb_ret = ivpu_ipc_send_receive_internal(vdev, &hb_req, VPU_JSM_MSG_QUERY_ENGINE_HB_DONE, |
| 344 | 344 | &hb_resp, VPU_IPC_CHAN_ASYNC_CMD, |
| 345 | 345 | vdev->timeout.jsm); |
| 346 | − if (hb_ret == -ETIMEDOUT) { | |
| 347 | − ivpu_hw_diagnose_failure(vdev); | |
| 348 | − ivpu_pm_schedule_recovery(vdev); | |
| 349 | − } | |
| 346 | + if (hb_ret == -ETIMEDOUT) | |
| 347 | + ivpu_pm_trigger_recovery(vdev, "IPC timeout"); | |
| 350 | 348 | |
| 351 | 349 | return ret; |
| 352 | 350 | } |
| @@ -112,22 +112,20 @@ static void ivpu_cmdq_release_locked(struct ivpu_file_priv *file_priv, u16 engin · 111 unmodified lines | ||
| 112 | 112 | } |
| 113 | 113 | } |
| 114 | 114 | |
| 115 | −void ivpu_cmdq_release_all(struct ivpu_file_priv *file_priv) | |
| 115 | +void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv) | |
| 116 | 116 | { |
| 117 | 117 | int i; |
| 118 | 118 | |
| 119 | − mutex_lock(&file_priv->lock); | |
| 119 | + lockdep_assert_held(&file_priv->lock); | |
| 120 | 120 | |
| 121 | 121 | for (i = 0; i < IVPU_NUM_ENGINES; i++) |
| 122 | 122 | ivpu_cmdq_release_locked(file_priv, i); |
| 123 | − | |
| 124 | − mutex_unlock(&file_priv->lock); | |
| 125 | 123 | } |
| 126 | 124 | |
| 127 | 125 | /* |
| 128 | 126 | * Mark the doorbell as unregistered and reset job queue pointers. |
| 129 | 127 | * This function needs to be called when the VPU hardware is restarted |
| 130 | − * and FW looses job queue state. The next time job queue is used it | |
| 128 | + * and FW loses job queue state. The next time job queue is used it | |
| 131 | 129 | * will be registered again. |
| 132 | 130 | */ |
| 133 | 131 | static void ivpu_cmdq_reset_locked(struct ivpu_file_priv *file_priv, u16 engine) |
| @@ -161,15 +159,13 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev) · 27 unmodified lines | ||
| 161 | 159 | struct ivpu_file_priv *file_priv; |
| 162 | 160 | unsigned long ctx_id; |
| 163 | 161 | |
| 164 | − xa_for_each(&vdev->context_xa, ctx_id, file_priv) { | |
| 165 | − file_priv = ivpu_file_priv_get_by_ctx_id(vdev, ctx_id); | |
| 166 | − if (!file_priv) | |
| 167 | − continue; | |
| 162 | + mutex_lock(&vdev->context_list_lock); | |
| 168 | 163 | |
| 164 | + xa_for_each(&vdev->context_xa, ctx_id, file_priv) | |
| 169 | 165 | ivpu_cmdq_reset_all(file_priv); |
| 170 | 166 | |
| 171 | − ivpu_file_priv_put(&file_priv); | |
| 172 | − } | |
| 167 | + mutex_unlock(&vdev->context_list_lock); | |
| 168 | + | |
| 173 | 169 | } |
| 174 | 170 | |
| 175 | 171 | static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job) |
| @@ -243,60 +239,32 @@ static struct dma_fence *ivpu_fence_create(struct ivpu_device *vdev) · 67 unmodified lines | ||
| 243 | 239 | return &fence->base; |
| 244 | 240 | } |
| 245 | 241 | |
| 246 | −static void job_get(struct ivpu_job *job, struct ivpu_job **link) | |
| 242 | +static void ivpu_job_destroy(struct ivpu_job *job) | |
| 247 | 243 | { |
| 248 | 244 | struct ivpu_device *vdev = job->vdev; |
| 249 | − | |
| 250 | − kref_get(&job->ref); | |
| 251 | − *link = job; | |
| 252 | − | |
| 253 | − ivpu_dbg(vdev, KREF, "Job get: id %u refcount %u\n", job->job_id, kref_read(&job->ref)); | |
| 254 | −} | |
| 255 | − | |
| 256 | −static void job_release(struct kref *ref) | |
| 257 | −{ | |
| 258 | − struct ivpu_job *job = container_of(ref, struct ivpu_job, ref); | |
| 259 | − struct ivpu_device *vdev = job->vdev; | |
| 260 | 245 | u32 i; |
| 261 | 246 | |
| 247 | + ivpu_dbg(vdev, JOB, "Job destroyed: id %3u ctx %2d engine %d", | |
| 248 | + job->job_id, job->file_priv->ctx.id, job->engine_idx); | |
| 249 | + | |
| 262 | 250 | for (i = 0; i < job->bo_count; i++) |
| 263 | 251 | if (job->bos[i]) |
| 264 | 252 | drm_gem_object_put(&job->bos[i]->base.base); |
| 265 | 253 | |
| 266 | 254 | dma_fence_put(job->done_fence); |
| 267 | 255 | ivpu_file_priv_put(&job->file_priv); |
| 268 | − | |
| 269 | − ivpu_dbg(vdev, KREF, "Job released: id %u\n", job->job_id); | |
| 270 | 256 | kfree(job); |
| 271 | − | |
| 272 | − /* Allow the VPU to get suspended, must be called after ivpu_file_priv_put() */ | |
| 273 | − ivpu_rpm_put(vdev); | |
| 274 | −} | |
| 275 | − | |
| 276 | −static void job_put(struct ivpu_job *job) | |
| 277 | −{ | |
| 278 | − struct ivpu_device *vdev = job->vdev; | |
| 279 | − | |
| 280 | − ivpu_dbg(vdev, KREF, "Job put: id %u refcount %u\n", job->job_id, kref_read(&job->ref)); | |
| 281 | − kref_put(&job->ref, job_release); | |
| 282 | 257 | } |
| 283 | 258 | |
| 284 | 259 | static struct ivpu_job * |
| 285 | −ivpu_create_job(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count) | |
| 260 | +ivpu_job_create(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count) | |
| 286 | 261 | { |
| 287 | 262 | struct ivpu_device *vdev = file_priv->vdev; |
| 288 | 263 | struct ivpu_job *job; |
| 289 | − int ret; | |
| 290 | − | |
| 291 | − ret = ivpu_rpm_get(vdev); | |
| 292 | − if (ret < 0) | |
| 293 | − return NULL; | |
| 294 | 264 | |
| 295 | 265 | job = kzalloc(struct_size(job, bos, bo_count), GFP_KERNEL); |
| 296 | 266 | if (!job) |
| 297 | − goto err_rpm_put; | |
| 298 | − | |
| 299 | − kref_init(&job->ref); | |
| 267 | + return NULL; | |
| 300 | 268 | |
| 301 | 269 | job->vdev = vdev; |
| 302 | 270 | job->engine_idx = engine_idx; |
| @@ -310,17 +278,14 @@ ivpu_create_job(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count) · 7 unmodified lines | ||
| 310 | 278 | job->file_priv = ivpu_file_priv_get(file_priv); |
| 311 | 279 | |
| 312 | 280 | ivpu_dbg(vdev, JOB, "Job created: ctx %2d engine %d", file_priv->ctx.id, job->engine_idx); |
| 313 | − | |
| 314 | 281 | return job; |
| 315 | 282 | |
| 316 | 283 | err_free_job: |
| 317 | 284 | kfree(job); |
| 318 | −err_rpm_put: | |
| 319 | − ivpu_rpm_put(vdev); | |
| 320 | 285 | return NULL; |
| 321 | 286 | } |
| 322 | 287 | |
| 323 | −static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status) | |
| 288 | +static int ivpu_job_signal_and_destroy(struct ivpu_device *vdev, u32 job_id, u32 job_status) | |
| 324 | 289 | { |
| 325 | 290 | struct ivpu_job *job; |
| 326 | 291 | |
| @@ -337,9 +302,10 @@ static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status) · 10 unmodified lines | ||
| 337 | 302 | ivpu_dbg(vdev, JOB, "Job complete: id %3u ctx %2d engine %d status 0x%x\n", |
| 338 | 303 | job->job_id, job->file_priv->ctx.id, job->engine_idx, job_status); |
| 339 | 304 | |
| 305 | + ivpu_job_destroy(job); | |
| 340 | 306 | ivpu_stop_job_timeout_detection(vdev); |
| 341 | 307 | |
| 342 | − job_put(job); | |
| 308 | + ivpu_rpm_put(vdev); | |
| 343 | 309 | return 0; |
| 344 | 310 | } |
| 345 | 311 | |
| @@ -349,10 +315,10 @@ void ivpu_jobs_abort_all(struct ivpu_device *vdev) · 3 unmodified lines | ||
| 349 | 315 | unsigned long id; |
| 350 | 316 | |
| 351 | 317 | xa_for_each(&vdev->submitted_jobs_xa, id, job) |
| 352 | − ivpu_job_done(vdev, id, VPU_JSM_STATUS_ABORTED); | |
| 318 | + ivpu_job_signal_and_destroy(vdev, id, VPU_JSM_STATUS_ABORTED); | |
| 353 | 319 | } |
| 354 | 320 | |
| 355 | −static int ivpu_direct_job_submission(struct ivpu_job *job) | |
| 321 | +static int ivpu_job_submit(struct ivpu_job *job) | |
| 356 | 322 | { |
| 357 | 323 | struct ivpu_file_priv *file_priv = job->file_priv; |
| 358 | 324 | struct ivpu_device *vdev = job->vdev; |
| @@ -360,53 +326,65 @@ static int ivpu_direct_job_submission(struct ivpu_job *job) · 1 unmodified line | ||
| 360 | 326 | struct ivpu_cmdq *cmdq; |
| 361 | 327 | int ret; |
| 362 | 328 | |
| 329 | + ret = ivpu_rpm_get(vdev); | |
| 330 | + if (ret < 0) | |
| 331 | + return ret; | |
| 332 | + | |
| 363 | 333 | mutex_lock(&file_priv->lock); |
| 364 | 334 | |
| 365 | 335 | cmdq = ivpu_cmdq_acquire(job->file_priv, job->engine_idx); |
| 366 | 336 | if (!cmdq) { |
| 367 | − ivpu_warn(vdev, "Failed get job queue, ctx %d engine %d\n", | |
| 368 | − file_priv->ctx.id, job->engine_idx); | |
| 337 | + ivpu_warn_ratelimited(vdev, "Failed get job queue, ctx %d engine %d\n", | |
| 338 | + file_priv->ctx.id, job->engine_idx); | |
| 369 | 339 | ret = -EINVAL; |
| 370 | − goto err_unlock; | |
| 340 | + goto err_unlock_file_priv; | |
| 371 | 341 | } |
| 372 | 342 | |
| 373 | 343 | job_id_range.min = FIELD_PREP(JOB_ID_CONTEXT_MASK, (file_priv->ctx.id - 1)); |
| 374 | 344 | job_id_range.max = job_id_range.min | JOB_ID_JOB_MASK; |
| 375 | 345 | |
| 376 | − job_get(job, &job); | |
| 377 | − ret = xa_alloc(&vdev->submitted_jobs_xa, &job->job_id, job, job_id_range, GFP_KERNEL); | |
| 346 | + xa_lock(&vdev->submitted_jobs_xa); | |
| 347 | + ret = __xa_alloc(&vdev->submitted_jobs_xa, &job->job_id, job, job_id_range, GFP_KERNEL); | |
| 378 | 348 | if (ret) { |
| 379 | − ivpu_warn_ratelimited(vdev, "Failed to allocate job id: %d\n", ret); | |
| 380 | − goto err_job_put; | |
| 349 | + ivpu_dbg(vdev, JOB, "Too many active jobs in ctx %d\n", | |
| 350 | + file_priv->ctx.id); | |
| 351 | + ret = -EBUSY; | |
| 352 | + goto err_unlock_submitted_jobs_xa; | |
| 381 | 353 | } |
| 382 | 354 | |
| 383 | 355 | ret = ivpu_cmdq_push_job(cmdq, job); |
| 384 | 356 | if (ret) |
| 385 | − goto err_xa_erase; | |
| 357 | + goto err_erase_xa; | |
| 386 | 358 | |
| 387 | 359 | ivpu_start_job_timeout_detection(vdev); |
| 388 | 360 | |
| 389 | − ivpu_dbg(vdev, JOB, "Job submitted: id %3u addr 0x%llx ctx %2d engine %d next %d\n", | |
| 390 | − job->job_id, job->cmd_buf_vpu_addr, file_priv->ctx.id, | |
| 391 | − job->engine_idx, cmdq->jobq->header.tail); | |
| 392 | − | |
| 393 | − if (ivpu_test_mode & IVPU_TEST_MODE_NULL_HW) { | |
| 394 | − ivpu_job_done(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS); | |
| 361 | + if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_HW)) { | |
| 395 | 362 | cmdq->jobq->header.head = cmdq->jobq->header.tail; |
| 396 | 363 | wmb(); /* Flush WC buffer for jobq header */ |
| 397 | 364 | } else { |
| 398 | 365 | ivpu_cmdq_ring_db(vdev, cmdq); |
| 399 | 366 | } |
| 400 | 367 | |
| 368 | + ivpu_dbg(vdev, JOB, "Job submitted: id %3u ctx %2d engine %d addr 0x%llx next %d\n", | |
| 369 | + job->job_id, file_priv->ctx.id, job->engine_idx, | |
| 370 | + job->cmd_buf_vpu_addr, cmdq->jobq->header.tail); | |
| 371 | + | |
| 372 | + xa_unlock(&vdev->submitted_jobs_xa); | |
| 373 | + | |
| 401 | 374 | mutex_unlock(&file_priv->lock); |
| 375 | + | |
| 376 | + if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_HW)) | |
| 377 | + ivpu_job_signal_and_destroy(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS); | |
| 378 | + | |
| 402 | 379 | return 0; |
| 403 | 380 | |
| 404 | −err_xa_erase: | |
| 405 | − xa_erase(&vdev->submitted_jobs_xa, job->job_id); | |
| 406 | −err_job_put: | |
| 407 | − job_put(job); | |
| 408 | −err_unlock: | |
| 381 | +err_erase_xa: | |
| 382 | + __xa_erase(&vdev->submitted_jobs_xa, job->job_id); | |
| 383 | +err_unlock_submitted_jobs_xa: | |
| 384 | + xa_unlock(&vdev->submitted_jobs_xa); | |
| 385 | +err_unlock_file_priv: | |
| 409 | 386 | mutex_unlock(&file_priv->lock); |
| 387 | + ivpu_rpm_put(vdev); | |
| 410 | 388 | return ret; |
| 411 | 389 | } |
| 412 | 390 | |
| @@ -488,6 +466,9 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) · 75 unmodified lines | ||
| 488 | 466 | if (params->engine > DRM_IVPU_ENGINE_COPY) |
| 489 | 467 | return -EINVAL; |
| 490 | 468 | |
| 469 | + if (params->priority > DRM_IVPU_JOB_PRIORITY_REALTIME) | |
| 470 | + return -EINVAL; | |
| 471 | + | |
| 491 | 472 | if (params->buffer_count == 0 || params->buffer_count > JOB_MAX_BUFFER_COUNT) |
| 492 | 473 | return -EINVAL; |
| 493 | 474 | |
| @@ -509,44 +490,49 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) · 15 unmodified lines | ||
| 509 | 490 | params->buffer_count * sizeof(u32)); |
| 510 | 491 | if (ret) { |
| 511 | 492 | ret = -EFAULT; |
| 512 | − goto free_handles; | |
| 493 | + goto err_free_handles; | |
| 513 | 494 | } |
| 514 | 495 | |
| 515 | 496 | if (!drm_dev_enter(&vdev->drm, &idx)) { |
| 516 | 497 | ret = -ENODEV; |
| 517 | − goto free_handles; | |
| 498 | + goto err_free_handles; | |
| 518 | 499 | } |
| 519 | 500 | |
| 520 | 501 | ivpu_dbg(vdev, JOB, "Submit ioctl: ctx %u buf_count %u\n", |
| 521 | 502 | file_priv->ctx.id, params->buffer_count); |
| 522 | 503 | |
| 523 | − job = ivpu_create_job(file_priv, params->engine, params->buffer_count); | |
| 504 | + job = ivpu_job_create(file_priv, params->engine, params->buffer_count); | |
| 524 | 505 | if (!job) { |
| 525 | 506 | ivpu_err(vdev, "Failed to create job\n"); |
| 526 | 507 | ret = -ENOMEM; |
| 527 | − goto dev_exit; | |
| 508 | + goto err_exit_dev; | |
| 528 | 509 | } |
| 529 | 510 | |
| 530 | 511 | ret = ivpu_job_prepare_bos_for_submit(file, job, buf_handles, params->buffer_count, |
| 531 | 512 | params->commands_offset); |
| 532 | 513 | if (ret) { |
| 533 | − ivpu_err(vdev, "Failed to prepare job, ret %d\n", ret); | |
| 534 | − goto job_put; | |
| 514 | + ivpu_err(vdev, "Failed to prepare job: %d\n", ret); | |
| 515 | + goto err_destroy_job; | |
| 535 | 516 | } |
| 536 | 517 | |
| 537 | − ret = ivpu_direct_job_submission(job); | |
| 538 | − if (ret) { | |
| 539 | − dma_fence_signal(job->done_fence); | |
| 540 | − ivpu_err(vdev, "Failed to submit job to the HW, ret %d\n", ret); | |
| 541 | − } | |
| 518 | + down_read(&vdev->pm->reset_lock); | |
| 519 | + ret = ivpu_job_submit(job); | |
| 520 | + up_read(&vdev->pm->reset_lock); | |
| 521 | + if (ret) | |
| 522 | + goto err_signal_fence; | |
| 542 | 523 | |
| 543 | −job_put: | |
| 544 | − job_put(job); | |
| 545 | −dev_exit: | |
| 546 | 524 | drm_dev_exit(idx); |
| 547 | −free_handles: | |
| 548 | 525 | kfree(buf_handles); |
| 526 | + return ret; | |
| 549 | 527 | |
| 528 | +err_signal_fence: | |
| 529 | + dma_fence_signal(job->done_fence); | |
| 530 | +err_destroy_job: | |
| 531 | + ivpu_job_destroy(job); | |
| 532 | +err_exit_dev: | |
| 533 | + drm_dev_exit(idx); | |
| 534 | +err_free_handles: | |
| 535 | + kfree(buf_handles); | |
| 550 | 536 | return ret; |
| 551 | 537 | } |
| 552 | 538 | |
| @@ -568,7 +554,7 @@ ivpu_job_done_callback(struct ivpu_device *vdev, struct ivpu_ipc_hdr *ipc_hdr, · 15 unmodified lines | ||
| 568 | 554 | } |
| 569 | 555 | |
| 570 | 556 | payload = (struct vpu_ipc_msg_payload_job_done *)&jsm_msg->payload; |
| 571 | − ret = ivpu_job_done(vdev, payload->job_id, payload->job_status); | |
| 557 | + ret = ivpu_job_signal_and_destroy(vdev, payload->job_id, payload->job_status); | |
| 572 | 558 | if (!ret && !xa_empty(&vdev->submitted_jobs_xa)) |
| 573 | 559 | ivpu_start_job_timeout_detection(vdev); |
| 574 | 560 | } |
| @@ -43,7 +43,6 @@ struct ivpu_cmdq { · 42 unmodified lines | ||
| 43 | 43 | will update the job status |
| 44 | 44 | */ |
| 45 | 45 | struct ivpu_job { |
| 46 | − struct kref ref; | |
| 47 | 46 | struct ivpu_device *vdev; |
| 48 | 47 | struct ivpu_file_priv *file_priv; |
| 49 | 48 | struct dma_fence *done_fence; |
| @@ -56,7 +55,7 @@ struct ivpu_job { · 6 unmodified lines | ||
| 56 | 55 | |
| 57 | 56 | int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file); |
| 58 | 57 | |
| 59 | −void ivpu_cmdq_release_all(struct ivpu_file_priv *file_priv); | |
| 58 | +void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv); | |
| 60 | 59 | void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev); |
| 61 | 60 | |
| 62 | 61 | void ivpu_job_done_consumer_init(struct ivpu_device *vdev); |
| @@ -7,6 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | #include <linux/highmem.h> |
| 8 | 8 | |
| 9 | 9 | #include "ivpu_drv.h" |
| 10 | +#include "ivpu_hw.h" | |
| 10 | 11 | #include "ivpu_hw_reg_io.h" |
| 11 | 12 | #include "ivpu_mmu.h" |
| 12 | 13 | #include "ivpu_mmu_context.h" |
| @@ -518,6 +519,7 @@ static int ivpu_mmu_cmdq_sync(struct ivpu_device *vdev) · 505 unmodified lines | ||
| 518 | 519 | |
| 519 | 520 | ivpu_err(vdev, "Timed out waiting for MMU consumer: %d, error: %s\n", ret, |
| 520 | 521 | ivpu_mmu_cmdq_err_to_str(err)); |
| 522 | + ivpu_hw_diagnose_failure(vdev); | |
| 521 | 523 | } |
| 522 | 524 | |
| 523 | 525 | return ret; |
| @@ -885,7 +887,6 @@ static u32 *ivpu_mmu_get_event(struct ivpu_device *vdev) · 361 unmodified lines | ||
| 885 | 887 | |
| 886 | 888 | void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev) |
| 887 | 889 | { |
| 888 | − bool schedule_recovery = false; | |
| 889 | 890 | u32 *event; |
| 890 | 891 | u32 ssid; |
| 891 | 892 | |
| @@ -895,14 +896,21 @@ void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev) · 3 unmodified lines | ||
| 895 | 896 | ivpu_mmu_dump_event(vdev, event); |
| 896 | 897 | |
| 897 | 898 | ssid = FIELD_GET(IVPU_MMU_EVT_SSID_MASK, event[0]); |
| 898 | − if (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID) | |
| 899 | − schedule_recovery = true; | |
| 900 | − else | |
| 901 | − ivpu_mmu_user_context_mark_invalid(vdev, ssid); | |
| 899 | + if (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID) { | |
| 900 | + ivpu_pm_trigger_recovery(vdev, "MMU event"); | |
| 901 | + return; | |
| 902 | + } | |
| 903 | + | |
| 904 | + ivpu_mmu_user_context_mark_invalid(vdev, ssid); | |
| 902 | 905 | } |
| 906 | +} | |
| 903 | 907 | |
| 904 | − if (schedule_recovery) | |
| 905 | − ivpu_pm_schedule_recovery(vdev); | |
| 908 | +void ivpu_mmu_evtq_dump(struct ivpu_device *vdev) | |
| 909 | +{ | |
| 910 | + u32 *event; | |
| 911 | + | |
| 912 | + while ((event = ivpu_mmu_get_event(vdev)) != NULL) | |
| 913 | + ivpu_mmu_dump_event(vdev, event); | |
| 906 | 914 | } |
| 907 | 915 | |
| 908 | 916 | void ivpu_mmu_irq_gerr_handler(struct ivpu_device *vdev) |
| @@ -46,5 +46,6 @@ int ivpu_mmu_invalidate_tlb(struct ivpu_device *vdev, u16 ssid); · 45 unmodified lines | ||
| 46 | 46 | |
| 47 | 47 | void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev); |
| 48 | 48 | void ivpu_mmu_irq_gerr_handler(struct ivpu_device *vdev); |
| 49 | +void ivpu_mmu_evtq_dump(struct ivpu_device *vdev); | |
| 49 | 50 | |
| 50 | 51 | #endif /* __IVPU_MMU_H__ */ |
| @@ -355,6 +355,9 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, · 354 unmodified lines | ||
| 355 | 355 | dma_addr_t dma_addr = sg_dma_address(sg) - sg->offset; |
| 356 | 356 | size_t size = sg_dma_len(sg) + sg->offset; |
| 357 | 357 | |
| 358 | + ivpu_dbg(vdev, MMU_MAP, "Map ctx: %u dma_addr: 0x%llx vpu_addr: 0x%llx size: %lu\n", | |
| 359 | + ctx->id, dma_addr, vpu_addr, size); | |
| 360 | + | |
| 358 | 361 | ret = ivpu_mmu_context_map_pages(vdev, ctx, vpu_addr, dma_addr, size, prot); |
| 359 | 362 | if (ret) { |
| 360 | 363 | ivpu_err(vdev, "Failed to map context pages\n"); |
| @@ -366,6 +369,7 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, · 5 unmodified lines | ||
| 366 | 369 | |
| 367 | 370 | /* Ensure page table modifications are flushed from wc buffers to memory */ |
| 368 | 371 | wmb(); |
| 372 | + | |
| 369 | 373 | mutex_unlock(&ctx->lock); |
| 370 | 374 | |
| 371 | 375 | ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id); |
| @@ -388,14 +392,19 @@ ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ct · 16 unmodified lines | ||
| 388 | 392 | mutex_lock(&ctx->lock); |
| 389 | 393 | |
| 390 | 394 | for_each_sgtable_dma_sg(sgt, sg, i) { |
| 395 | + dma_addr_t dma_addr = sg_dma_address(sg) - sg->offset; | |
| 391 | 396 | size_t size = sg_dma_len(sg) + sg->offset; |
| 392 | 397 | |
| 398 | + ivpu_dbg(vdev, MMU_MAP, "Unmap ctx: %u dma_addr: 0x%llx vpu_addr: 0x%llx size: %lu\n", | |
| 399 | + ctx->id, dma_addr, vpu_addr, size); | |
| 400 | + | |
| 393 | 401 | ivpu_mmu_context_unmap_pages(ctx, vpu_addr, size); |
| 394 | 402 | vpu_addr += size; |
| 395 | 403 | } |
| 396 | 404 | |
| 397 | 405 | /* Ensure page table modifications are flushed from wc buffers to memory */ |
| 398 | 406 | wmb(); |
| 407 | + | |
| 399 | 408 | mutex_unlock(&ctx->lock); |
| 400 | 409 | |
| 401 | 410 | ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id); |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | #include "ivpu_drv.h" |
| 14 | 14 | #include "ivpu_hw.h" |
| 15 | 15 | #include "ivpu_fw.h" |
| 16 | +#include "ivpu_fw_log.h" | |
| 16 | 17 | #include "ivpu_ipc.h" |
| 17 | 18 | #include "ivpu_job.h" |
| 18 | 19 | #include "ivpu_jsm_msg.h" |
| @@ -111,6 +112,14 @@ static void ivpu_pm_recovery_work(struct work_struct *work) · 92 unmodified lines | ||
| 111 | 112 | char *evt[2] = {"IVPU_PM_EVENT=IVPU_RECOVER", NULL}; |
| 112 | 113 | int ret; |
| 113 | 114 | |
| 115 | + ivpu_err(vdev, "Recovering the VPU (reset #%d)\n", atomic_read(&vdev->pm->reset_counter)); | |
| 116 | + | |
| 117 | + ret = pm_runtime_resume_and_get(vdev->drm.dev); | |
| 118 | + if (ret) | |
| 119 | + ivpu_err(vdev, "Failed to resume VPU: %d\n", ret); | |
| 120 | + | |
| 121 | + ivpu_fw_log_dump(vdev); | |
| 122 | + | |
| 114 | 123 | retry: |
| 115 | 124 | ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev)); |
| 116 | 125 | if (ret == -EAGAIN && !drm_dev_is_unplugged(&vdev->drm)) { |
| @@ -122,11 +131,13 @@ retry: · 5 unmodified lines | ||
| 122 | 131 | ivpu_err(vdev, "Failed to reset VPU: %d\n", ret); |
| 123 | 132 | |
| 124 | 133 | kobject_uevent_env(&vdev->drm.dev->kobj, KOBJ_CHANGE, evt); |
| 134 | + pm_runtime_mark_last_busy(vdev->drm.dev); | |
| 135 | + pm_runtime_put_autosuspend(vdev->drm.dev); | |
| 125 | 136 | } |
| 126 | 137 | |
| 127 | −void ivpu_pm_schedule_recovery(struct ivpu_device *vdev) | |
| 138 | +void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason) | |
| 128 | 139 | { |
| 129 | − struct ivpu_pm_info *pm = vdev->pm; | |
| 140 | + ivpu_err(vdev, "Recovery triggered by %s\n", reason); | |
| 130 | 141 | |
| 131 | 142 | if (ivpu_disable_recovery) { |
| 132 | 143 | ivpu_err(vdev, "Recovery not available when disable_recovery param is set\n"); |
| @@ -138,10 +149,11 @@ void ivpu_pm_schedule_recovery(struct ivpu_device *vdev) · 5 unmodified lines | ||
| 138 | 149 | return; |
| 139 | 150 | } |
| 140 | 151 | |
| 141 | − /* Schedule recovery if it's not in progress */ | |
| 142 | − if (atomic_cmpxchg(&pm->in_reset, 0, 1) == 0) { | |
| 143 | − ivpu_hw_irq_disable(vdev); | |
| 144 | − queue_work(system_long_wq, &pm->recovery_work); | |
| 152 | + /* Trigger recovery if it's not in progress */ | |
| 153 | + if (atomic_cmpxchg(&vdev->pm->reset_pending, 0, 1) == 0) { | |
| 154 | + ivpu_hw_diagnose_failure(vdev); | |
| 155 | + ivpu_hw_irq_disable(vdev); /* Disable IRQ early to protect from IRQ storm */ | |
| 156 | + queue_work(system_long_wq, &vdev->pm->recovery_work); | |
| 145 | 157 | } |
| 146 | 158 | } |
| 147 | 159 | |
| @@ -149,12 +161,8 @@ static void ivpu_job_timeout_work(struct work_struct *work) · 1 unmodified line | ||
| 149 | 161 | { |
| 150 | 162 | struct ivpu_pm_info *pm = container_of(work, struct ivpu_pm_info, job_timeout_work.work); |
| 151 | 163 | struct ivpu_device *vdev = pm->vdev; |
| 152 | − unsigned long timeout_ms = ivpu_tdr_timeout_ms ? ivpu_tdr_timeout_ms : vdev->timeout.tdr; | |
| 153 | 164 | |
| 154 | − ivpu_err(vdev, "TDR detected, timeout %lu ms", timeout_ms); | |
| 155 | − ivpu_hw_diagnose_failure(vdev); | |
| 156 | − | |
| 157 | − ivpu_pm_schedule_recovery(vdev); | |
| 165 | + ivpu_pm_trigger_recovery(vdev, "TDR"); | |
| 158 | 166 | } |
| 159 | 167 | |
| 160 | 168 | void ivpu_start_job_timeout_detection(struct ivpu_device *vdev) |
| @@ -227,6 +235,9 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev) · 66 unmodified lines | ||
| 227 | 235 | bool hw_is_idle = true; |
| 228 | 236 | int ret; |
| 229 | 237 | |
| 238 | + drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa)); | |
| 239 | + drm_WARN_ON(&vdev->drm, work_pending(&vdev->pm->recovery_work)); | |
| 240 | + | |
| 230 | 241 | ivpu_dbg(vdev, PM, "Runtime suspend..\n"); |
| 231 | 242 | |
| 232 | 243 | if (!ivpu_hw_is_idle(vdev) && vdev->pm->suspend_reschedule_counter) { |
| @@ -247,7 +258,8 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev) · 14 unmodified lines | ||
| 247 | 258 | ivpu_err(vdev, "Failed to set suspend VPU: %d\n", ret); |
| 248 | 259 | |
| 249 | 260 | if (!hw_is_idle) { |
| 250 | − ivpu_warn(vdev, "VPU failed to enter idle, force suspended.\n"); | |
| 261 | + ivpu_err(vdev, "VPU failed to enter idle, force suspended.\n"); | |
| 262 | + ivpu_fw_log_dump(vdev); | |
| 251 | 263 | ivpu_pm_prepare_cold_boot(vdev); |
| 252 | 264 | } else { |
| 253 | 265 | ivpu_pm_prepare_warm_boot(vdev); |
| @@ -308,11 +320,12 @@ void ivpu_pm_reset_prepare_cb(struct pci_dev *pdev) · 54 unmodified lines | ||
| 308 | 320 | { |
| 309 | 321 | struct ivpu_device *vdev = pci_get_drvdata(pdev); |
| 310 | 322 | |
| 311 | − pm_runtime_get_sync(vdev->drm.dev); | |
| 312 | − | |
| 313 | 323 | ivpu_dbg(vdev, PM, "Pre-reset..\n"); |
| 314 | 324 | atomic_inc(&vdev->pm->reset_counter); |
| 315 | − atomic_set(&vdev->pm->in_reset, 1); | |
| 325 | + atomic_set(&vdev->pm->reset_pending, 1); | |
| 326 | + | |
| 327 | + pm_runtime_get_sync(vdev->drm.dev); | |
| 328 | + down_write(&vdev->pm->reset_lock); | |
| 316 | 329 | ivpu_prepare_for_reset(vdev); |
| 317 | 330 | ivpu_hw_reset(vdev); |
| 318 | 331 | ivpu_pm_prepare_cold_boot(vdev); |
| @@ -329,9 +342,11 @@ void ivpu_pm_reset_done_cb(struct pci_dev *pdev) · 10 unmodified lines | ||
| 329 | 342 | ret = ivpu_resume(vdev); |
| 330 | 343 | if (ret) |
| 331 | 344 | ivpu_err(vdev, "Failed to set RESUME state: %d\n", ret); |
| 332 | − atomic_set(&vdev->pm->in_reset, 0); | |
| 345 | + up_write(&vdev->pm->reset_lock); | |
| 346 | + atomic_set(&vdev->pm->reset_pending, 0); | |
| 333 | 347 | ivpu_dbg(vdev, PM, "Post-reset done.\n"); |
| 334 | 348 | |
| 349 | + pm_runtime_mark_last_busy(vdev->drm.dev); | |
| 335 | 350 | pm_runtime_put_autosuspend(vdev->drm.dev); |
| 336 | 351 | } |
| 337 | 352 | |
| @@ -344,7 +359,10 @@ void ivpu_pm_init(struct ivpu_device *vdev) · 6 unmodified lines | ||
| 344 | 359 | pm->vdev = vdev; |
| 345 | 360 | pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT; |
| 346 | 361 | |
| 347 | − atomic_set(&pm->in_reset, 0); | |
| 362 | + init_rwsem(&pm->reset_lock); | |
| 363 | + atomic_set(&pm->reset_pending, 0); | |
| 364 | + atomic_set(&pm->reset_counter, 0); | |
| 365 | + | |
| 348 | 366 | INIT_WORK(&pm->recovery_work, ivpu_pm_recovery_work); |
| 349 | 367 | INIT_DELAYED_WORK(&pm->job_timeout_work, ivpu_job_timeout_work); |
| 350 | 368 | |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | #ifndef __IVPU_PM_H__ |
| 7 | 7 | #define __IVPU_PM_H__ |
| 8 | 8 | |
| 9 | +#include <linux/rwsem.h> | |
| 9 | 10 | #include <linux/types.h> |
| 10 | 11 | |
| 11 | 12 | struct ivpu_device; |
| @@ -14,8 +15,9 @@ struct ivpu_pm_info { · 2 unmodified lines | ||
| 14 | 15 | struct ivpu_device *vdev; |
| 15 | 16 | struct delayed_work job_timeout_work; |
| 16 | 17 | struct work_struct recovery_work; |
| 17 | − atomic_t in_reset; | |
| 18 | + struct rw_semaphore reset_lock; | |
| 18 | 19 | atomic_t reset_counter; |
| 20 | + atomic_t reset_pending; | |
| 19 | 21 | bool is_warmboot; |
| 20 | 22 | u32 suspend_reschedule_counter; |
| 21 | 23 | }; |
| @@ -37,7 +39,7 @@ int __must_check ivpu_rpm_get(struct ivpu_device *vdev); · 15 unmodified lines | ||
| 37 | 39 | int __must_check ivpu_rpm_get_if_active(struct ivpu_device *vdev); |
| 38 | 40 | void ivpu_rpm_put(struct ivpu_device *vdev); |
| 39 | 41 | |
| 40 | −void ivpu_pm_schedule_recovery(struct ivpu_device *vdev); | |
| 42 | +void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason); | |
| 41 | 43 | void ivpu_start_job_timeout_detection(struct ivpu_device *vdev); |
| 42 | 44 | void ivpu_stop_job_timeout_detection(struct ivpu_device *vdev); |
| 43 | 45 | |
| @@ -48,6 +48,7 @@ enum { · 47 unmodified lines | ||
| 48 | 48 | enum board_ids { |
| 49 | 49 | /* board IDs by feature in alphabetical order */ |
| 50 | 50 | board_ahci, |
| 51 | + board_ahci_43bit_dma, | |
| 51 | 52 | board_ahci_ign_iferr, |
| 52 | 53 | board_ahci_low_power, |
| 53 | 54 | board_ahci_no_debounce_delay, |
| @@ -128,6 +129,13 @@ static const struct ata_port_info ahci_port_info[] = { · 74 unmodified lines | ||
| 128 | 129 | .udma_mask = ATA_UDMA6, |
| 129 | 130 | .port_ops = &ahci_ops, |
| 130 | 131 | }, |
| 132 | + [board_ahci_43bit_dma] = { | |
| 133 | + AHCI_HFLAGS (AHCI_HFLAG_43BIT_ONLY), | |
| 134 | + .flags = AHCI_FLAG_COMMON, | |
| 135 | + .pio_mask = ATA_PIO4, | |
| 136 | + .udma_mask = ATA_UDMA6, | |
| 137 | + .port_ops = &ahci_ops, | |
| 138 | + }, | |
| 131 | 139 | [board_ahci_ign_iferr] = { |
| 132 | 140 | AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), |
| 133 | 141 | .flags = AHCI_FLAG_COMMON, |
| @@ -597,11 +605,11 @@ static const struct pci_device_id ahci_pci_tbl[] = { · 463 unmodified lines | ||
| 597 | 605 | { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */ |
| 598 | 606 | { PCI_VDEVICE(PROMISE, 0x3781), board_ahci }, /* FastTrak TX8660 ahci-mode */ |
| 599 | 607 | |
| 600 | − /* Asmedia */ | |
| 608 | + /* ASMedia */ | |
| 601 | 609 | { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci }, /* ASM1060 */ |
| 602 | 610 | { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci }, /* ASM1060 */ |
| 603 | − { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */ | |
| 604 | − { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ | |
| 611 | + { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci_43bit_dma }, /* ASM1061 */ | |
| 612 | + { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci_43bit_dma }, /* ASM1061/1062 */ | |
| 605 | 613 | { PCI_VDEVICE(ASMEDIA, 0x0621), board_ahci }, /* ASM1061R */ |
| 606 | 614 | { PCI_VDEVICE(ASMEDIA, 0x0622), board_ahci }, /* ASM1062R */ |
| 607 | 615 | { PCI_VDEVICE(ASMEDIA, 0x0624), board_ahci }, /* ASM1062+JMB575 */ |
| @@ -663,6 +671,11 @@ MODULE_PARM_DESC(mobile_lpm_policy, "Default LPM policy for mobile chipsets"); · 55 unmodified lines | ||
| 663 | 671 | static void ahci_pci_save_initial_config(struct pci_dev *pdev, |
| 664 | 672 | struct ahci_host_priv *hpriv) |
| 665 | 673 | { |
| 674 | + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && pdev->device == 0x1166) { | |
| 675 | + dev_info(&pdev->dev, "ASM1166 has only six ports\n"); | |
| 676 | + hpriv->saved_port_map = 0x3f; | |
| 677 | + } | |
| 678 | + | |
| 666 | 679 | if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) { |
| 667 | 680 | dev_info(&pdev->dev, "JMB361 has only one port\n"); |
| 668 | 681 | hpriv->saved_port_map = 1; |
| @@ -949,11 +962,20 @@ static int ahci_pci_device_resume(struct device *dev) · 280 unmodified lines | ||
| 949 | 962 | |
| 950 | 963 | #endif /* CONFIG_PM */ |
| 951 | 964 | |
| 952 | −static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) | |
| 965 | +static int ahci_configure_dma_masks(struct pci_dev *pdev, | |
| 966 | + struct ahci_host_priv *hpriv) | |
| 953 | 967 | { |
| 954 | − const int dma_bits = using_dac ? 64 : 32; | |
| 968 | + int dma_bits; | |
| 955 | 969 | int rc; |
| 956 | 970 | |
| 971 | + if (hpriv->cap & HOST_CAP_64) { | |
| 972 | + dma_bits = 64; | |
| 973 | + if (hpriv->flags & AHCI_HFLAG_43BIT_ONLY) | |
| 974 | + dma_bits = 43; | |
| 975 | + } else { | |
| 976 | + dma_bits = 32; | |
| 977 | + } | |
| 978 | + | |
| 957 | 979 | /* |
| 958 | 980 | * If the device fixup already set the dma_mask to some non-standard |
| 959 | 981 | * value, don't extend it here. This happens on STA2X11, for example. |
| @@ -1926,7 +1948,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) · 966 unmodified lines | ||
| 1926 | 1948 | ahci_gtf_filter_workaround(host); |
| 1927 | 1949 | |
| 1928 | 1950 | /* initialize adapter */ |
| 1929 | − rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); | |
| 1951 | + rc = ahci_configure_dma_masks(pdev, hpriv); | |
| 1930 | 1952 | if (rc) |
| 1931 | 1953 | return rc; |
| 1932 | 1954 | |
| @@ -247,6 +247,7 @@ enum { · 246 unmodified lines | ||
| 247 | 247 | AHCI_HFLAG_SUSPEND_PHYS = BIT(26), /* handle PHYs during |
| 248 | 248 | suspend/resume */ |
| 249 | 249 | AHCI_HFLAG_NO_SXS = BIT(28), /* SXS not supported */ |
| 250 | + AHCI_HFLAG_43BIT_ONLY = BIT(29), /* 43bit DMA addr limit */ | |
| 250 | 251 | |
| 251 | 252 | /* ap->flags bits */ |
| 252 | 253 | |
| @@ -784,7 +784,7 @@ bool sata_lpm_ignore_phy_events(struct ata_link *link) · 783 unmodified lines | ||
| 784 | 784 | EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events); |
| 785 | 785 | |
| 786 | 786 | static const char *ata_lpm_policy_names[] = { |
| 787 | − [ATA_LPM_UNKNOWN] = "max_performance", | |
| 787 | + [ATA_LPM_UNKNOWN] = "keep_firmware_settings", | |
| 788 | 788 | [ATA_LPM_MAX_POWER] = "max_performance", |
| 789 | 789 | [ATA_LPM_MED_POWER] = "medium_power", |
| 790 | 790 | [ATA_LPM_MED_POWER_WITH_DIPM] = "med_power_with_dipm", |
| @@ -333,6 +333,7 @@ aoeblk_gdalloc(void *vp) · 332 unmodified lines | ||
| 333 | 333 | struct gendisk *gd; |
| 334 | 334 | mempool_t *mp; |
| 335 | 335 | struct blk_mq_tag_set *set; |
| 336 | + sector_t ssize; | |
| 336 | 337 | ulong flags; |
| 337 | 338 | int late = 0; |
| 338 | 339 | int err; |
| @@ -396,7 +397,7 @@ aoeblk_gdalloc(void *vp) · 57 unmodified lines | ||
| 396 | 397 | gd->minors = AOE_PARTITIONS; |
| 397 | 398 | gd->fops = &aoe_bdops; |
| 398 | 399 | gd->private_data = d; |
| 399 | − set_capacity(gd, d->ssize); | |
| 400 | + ssize = d->ssize; | |
| 400 | 401 | snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d", |
| 401 | 402 | d->aoemajor, d->aoeminor); |
| 402 | 403 | |
| @@ -405,6 +406,8 @@ aoeblk_gdalloc(void *vp) · 2 unmodified lines | ||
| 405 | 406 | |
| 406 | 407 | spin_unlock_irqrestore(&d->lock, flags); |
| 407 | 408 | |
| 409 | + set_capacity(gd, ssize); | |
| 410 | + | |
| 408 | 411 | err = device_add_disk(NULL, gd, aoe_attr_groups); |
| 409 | 412 | if (err) |
| 410 | 413 | goto out_disk_cleanup; |
| @@ -1232,14 +1232,13 @@ static void amd_pstate_epp_update_limit(struct cpufreq_policy *policy) · 1231 unmodified lines | ||
| 1232 | 1232 | max_limit_perf = div_u64(policy->max * cpudata->highest_perf, cpudata->max_freq); |
| 1233 | 1233 | min_limit_perf = div_u64(policy->min * cpudata->highest_perf, cpudata->max_freq); |
| 1234 | 1234 | |
| 1235 | + WRITE_ONCE(cpudata->max_limit_perf, max_limit_perf); | |
| 1236 | + WRITE_ONCE(cpudata->min_limit_perf, min_limit_perf); | |
| 1237 | + | |
| 1235 | 1238 | max_perf = clamp_t(unsigned long, max_perf, cpudata->min_limit_perf, |
| 1236 | 1239 | cpudata->max_limit_perf); |
| 1237 | 1240 | min_perf = clamp_t(unsigned long, min_perf, cpudata->min_limit_perf, |
| 1238 | 1241 | cpudata->max_limit_perf); |
| 1239 | − | |
| 1240 | − WRITE_ONCE(cpudata->max_limit_perf, max_limit_perf); | |
| 1241 | − WRITE_ONCE(cpudata->min_limit_perf, min_limit_perf); | |
| 1242 | − | |
| 1243 | 1242 | value = READ_ONCE(cpudata->cppc_req_cached); |
| 1244 | 1243 | |
| 1245 | 1244 | if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) |
| @@ -529,6 +529,30 @@ static int intel_pstate_cppc_get_scaling(int cpu) · 528 unmodified lines | ||
| 529 | 529 | } |
| 530 | 530 | #endif /* CONFIG_ACPI_CPPC_LIB */ |
| 531 | 531 | |
| 532 | +static int intel_pstate_freq_to_hwp_rel(struct cpudata *cpu, int freq, | |
| 533 | + unsigned int relation) | |
| 534 | +{ | |
| 535 | + if (freq == cpu->pstate.turbo_freq) | |
| 536 | + return cpu->pstate.turbo_pstate; | |
| 537 | + | |
| 538 | + if (freq == cpu->pstate.max_freq) | |
| 539 | + return cpu->pstate.max_pstate; | |
| 540 | + | |
| 541 | + switch (relation) { | |
| 542 | + case CPUFREQ_RELATION_H: | |
| 543 | + return freq / cpu->pstate.scaling; | |
| 544 | + case CPUFREQ_RELATION_C: | |
| 545 | + return DIV_ROUND_CLOSEST(freq, cpu->pstate.scaling); | |
| 546 | + } | |
| 547 | + | |
| 548 | + return DIV_ROUND_UP(freq, cpu->pstate.scaling); | |
| 549 | +} | |
| 550 | + | |
| 551 | +static int intel_pstate_freq_to_hwp(struct cpudata *cpu, int freq) | |
| 552 | +{ | |
| 553 | + return intel_pstate_freq_to_hwp_rel(cpu, freq, CPUFREQ_RELATION_L); | |
| 554 | +} | |
| 555 | + | |
| 532 | 556 | /** |
| 533 | 557 | * intel_pstate_hybrid_hwp_adjust - Calibrate HWP performance levels. |
| 534 | 558 | * @cpu: Target CPU. |
| @@ -546,6 +570,7 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu) · 11 unmodified lines | ||
| 546 | 570 | int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling; |
| 547 | 571 | int perf_ctl_turbo = pstate_funcs.get_turbo(cpu->cpu); |
| 548 | 572 | int scaling = cpu->pstate.scaling; |
| 573 | + int freq; | |
| 549 | 574 | |
| 550 | 575 | pr_debug("CPU%d: perf_ctl_max_phys = %d\n", cpu->cpu, perf_ctl_max_phys); |
| 551 | 576 | pr_debug("CPU%d: perf_ctl_turbo = %d\n", cpu->cpu, perf_ctl_turbo); |
| @@ -559,16 +584,16 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu) · 7 unmodified lines | ||
| 559 | 584 | cpu->pstate.max_freq = rounddown(cpu->pstate.max_pstate * scaling, |
| 560 | 585 | perf_ctl_scaling); |
| 561 | 586 | |
| 562 | − cpu->pstate.max_pstate_physical = | |
| 563 | − DIV_ROUND_UP(perf_ctl_max_phys * perf_ctl_scaling, | |
| 564 | − scaling); | |
| 587 | + freq = perf_ctl_max_phys * perf_ctl_scaling; | |
| 588 | + cpu->pstate.max_pstate_physical = intel_pstate_freq_to_hwp(cpu, freq); | |
| 565 | 589 | |
| 566 | − cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling; | |
| 590 | + freq = cpu->pstate.min_pstate * perf_ctl_scaling; | |
| 591 | + cpu->pstate.min_freq = freq; | |
| 567 | 592 | /* |
| 568 | 593 | * Cast the min P-state value retrieved via pstate_funcs.get_min() to |
| 569 | 594 | * the effective range of HWP performance levels. |
| 570 | 595 | */ |
| 571 | − cpu->pstate.min_pstate = DIV_ROUND_UP(cpu->pstate.min_freq, scaling); | |
| 596 | + cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, freq); | |
| 572 | 597 | } |
| 573 | 598 | |
| 574 | 599 | static inline void update_turbo_state(void) |
| @@ -2528,13 +2553,12 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu, · 1953 unmodified lines | ||
| 2528 | 2553 | * abstract values to represent performance rather than pure ratios. |
| 2529 | 2554 | */ |
| 2530 | 2555 | if (hwp_active && cpu->pstate.scaling != perf_ctl_scaling) { |
| 2531 | − int scaling = cpu->pstate.scaling; | |
| 2532 | 2556 | int freq; |
| 2533 | 2557 | |
| 2534 | 2558 | freq = max_policy_perf * perf_ctl_scaling; |
| 2535 | − max_policy_perf = DIV_ROUND_UP(freq, scaling); | |
| 2559 | + max_policy_perf = intel_pstate_freq_to_hwp(cpu, freq); | |
| 2536 | 2560 | freq = min_policy_perf * perf_ctl_scaling; |
| 2537 | − min_policy_perf = DIV_ROUND_UP(freq, scaling); | |
| 2561 | + min_policy_perf = intel_pstate_freq_to_hwp(cpu, freq); | |
| 2538 | 2562 | } |
| 2539 | 2563 | |
| 2540 | 2564 | pr_debug("cpu:%d min_policy_perf:%d max_policy_perf:%d\n", |
| @@ -2908,18 +2932,7 @@ static int intel_cpufreq_target(struct cpufreq_policy *policy, · 367 unmodified lines | ||
| 2908 | 2932 | |
| 2909 | 2933 | cpufreq_freq_transition_begin(policy, &freqs); |
| 2910 | 2934 | |
| 2911 | − switch (relation) { | |
| 2912 | − case CPUFREQ_RELATION_L: | |
| 2913 | − target_pstate = DIV_ROUND_UP(freqs.new, cpu->pstate.scaling); | |
| 2914 | − break; | |
| 2915 | − case CPUFREQ_RELATION_H: | |
| 2916 | − target_pstate = freqs.new / cpu->pstate.scaling; | |
| 2917 | − break; | |
| 2918 | − default: | |
| 2919 | − target_pstate = DIV_ROUND_CLOSEST(freqs.new, cpu->pstate.scaling); | |
| 2920 | − break; | |
| 2921 | − } | |
| 2922 | − | |
| 2935 | + target_pstate = intel_pstate_freq_to_hwp_rel(cpu, freqs.new, relation); | |
| 2923 | 2936 | target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, false); |
| 2924 | 2937 | |
| 2925 | 2938 | freqs.new = target_pstate * cpu->pstate.scaling; |
| @@ -2937,7 +2950,7 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy, · 11 unmodified lines | ||
| 2937 | 2950 | |
| 2938 | 2951 | update_turbo_state(); |
| 2939 | 2952 | |
| 2940 | − target_pstate = DIV_ROUND_UP(target_freq, cpu->pstate.scaling); | |
| 2953 | + target_pstate = intel_pstate_freq_to_hwp(cpu, target_freq); | |
| 2941 | 2954 | |
| 2942 | 2955 | target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, true); |
| 2943 | 2956 | |
| @@ -4545,6 +4545,7 @@ struct caam_hash_alg { · 4544 unmodified lines | ||
| 4545 | 4545 | struct list_head entry; |
| 4546 | 4546 | struct device *dev; |
| 4547 | 4547 | int alg_type; |
| 4548 | + bool is_hmac; | |
| 4548 | 4549 | struct ahash_alg ahash_alg; |
| 4549 | 4550 | }; |
| 4550 | 4551 | |
| @@ -4571,7 +4572,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) · 20 unmodified lines | ||
| 4571 | 4572 | |
| 4572 | 4573 | ctx->dev = caam_hash->dev; |
| 4573 | 4574 | |
| 4574 | − if (alg->setkey) { | |
| 4575 | + if (caam_hash->is_hmac) { | |
| 4575 | 4576 | ctx->adata.key_dma = dma_map_single_attrs(ctx->dev, ctx->key, |
| 4576 | 4577 | ARRAY_SIZE(ctx->key), |
| 4577 | 4578 | DMA_TO_DEVICE, |
| @@ -4611,7 +4612,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) · 33 unmodified lines | ||
| 4611 | 4612 | * For keyed hash algorithms shared descriptors |
| 4612 | 4613 | * will be created later in setkey() callback |
| 4613 | 4614 | */ |
| 4614 | − return alg->setkey ? 0 : ahash_set_sh_desc(ahash); | |
| 4615 | + return caam_hash->is_hmac ? 0 : ahash_set_sh_desc(ahash); | |
| 4615 | 4616 | } |
| 4616 | 4617 | |
| 4617 | 4618 | static void caam_hash_cra_exit(struct crypto_tfm *tfm) |
| @@ -4646,12 +4647,14 @@ static struct caam_hash_alg *caam_hash_alloc(struct device *dev, · 28 unmodified lines | ||
| 4646 | 4647 | template->hmac_name); |
| 4647 | 4648 | snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", |
| 4648 | 4649 | template->hmac_driver_name); |
| 4650 | + t_alg->is_hmac = true; | |
| 4649 | 4651 | } else { |
| 4650 | 4652 | snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", |
| 4651 | 4653 | template->name); |
| 4652 | 4654 | snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", |
| 4653 | 4655 | template->driver_name); |
| 4654 | 4656 | t_alg->ahash_alg.setkey = NULL; |
| 4657 | + t_alg->is_hmac = false; | |
| 4655 | 4658 | } |
| 4656 | 4659 | alg->cra_module = THIS_MODULE; |
| 4657 | 4660 | alg->cra_init = caam_hash_cra_init; |
| @@ -1753,6 +1753,7 @@ static struct caam_hash_template driver_hash[] = { · 1752 unmodified lines | ||
| 1753 | 1753 | struct caam_hash_alg { |
| 1754 | 1754 | struct list_head entry; |
| 1755 | 1755 | int alg_type; |
| 1756 | + bool is_hmac; | |
| 1756 | 1757 | struct ahash_engine_alg ahash_alg; |
| 1757 | 1758 | }; |
| 1758 | 1759 | |
| @@ -1804,7 +1805,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) · 45 unmodified lines | ||
| 1804 | 1805 | } else { |
| 1805 | 1806 | if (priv->era >= 6) { |
| 1806 | 1807 | ctx->dir = DMA_BIDIRECTIONAL; |
| 1807 | − ctx->key_dir = alg->setkey ? DMA_TO_DEVICE : DMA_NONE; | |
| 1808 | + ctx->key_dir = caam_hash->is_hmac ? DMA_TO_DEVICE : DMA_NONE; | |
| 1808 | 1809 | } else { |
| 1809 | 1810 | ctx->dir = DMA_TO_DEVICE; |
| 1810 | 1811 | ctx->key_dir = DMA_NONE; |
| @@ -1862,7 +1863,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) · 51 unmodified lines | ||
| 1862 | 1863 | * For keyed hash algorithms shared descriptors |
| 1863 | 1864 | * will be created later in setkey() callback |
| 1864 | 1865 | */ |
| 1865 | − return alg->setkey ? 0 : ahash_set_sh_desc(ahash); | |
| 1866 | + return caam_hash->is_hmac ? 0 : ahash_set_sh_desc(ahash); | |
| 1866 | 1867 | } |
| 1867 | 1868 | |
| 1868 | 1869 | static void caam_hash_cra_exit(struct crypto_tfm *tfm) |
| @@ -1915,12 +1916,14 @@ caam_hash_alloc(struct caam_hash_template *template, · 46 unmodified lines | ||
| 1915 | 1916 | template->hmac_name); |
| 1916 | 1917 | snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", |
| 1917 | 1918 | template->hmac_driver_name); |
| 1919 | + t_alg->is_hmac = true; | |
| 1918 | 1920 | } else { |
| 1919 | 1921 | snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", |
| 1920 | 1922 | template->name); |
| 1921 | 1923 | snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", |
| 1922 | 1924 | template->driver_name); |
| 1923 | 1925 | halg->setkey = NULL; |
| 1926 | + t_alg->is_hmac = false; | |
| 1924 | 1927 | } |
| 1925 | 1928 | alg->cra_module = THIS_MODULE; |
| 1926 | 1929 | alg->cra_init = caam_hash_cra_init; |
| @@ -463,6 +463,7 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data, u32 dev_id) · 462 unmodified lines | ||
| 463 | 463 | hw_data->fw_name = ADF_402XX_FW; |
| 464 | 464 | hw_data->fw_mmp_name = ADF_402XX_MMP; |
| 465 | 465 | hw_data->uof_get_name = uof_get_name_402xx; |
| 466 | + hw_data->get_ena_thd_mask = get_ena_thd_mask; | |
| 466 | 467 | break; |
| 467 | 468 | case ADF_401XX_PCI_DEVICE_ID: |
| 468 | 469 | hw_data->fw_name = ADF_4XXX_FW; |
| @@ -525,7 +525,7 @@ static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size) · 524 unmodified lines | ||
| 525 | 525 | struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); |
| 526 | 526 | struct cxl_region_params *p = &cxlr->params; |
| 527 | 527 | struct resource *res; |
| 528 | − u32 remainder = 0; | |
| 528 | + u64 remainder = 0; | |
| 529 | 529 | |
| 530 | 530 | lockdep_assert_held_write(&cxl_region_rwsem); |
| 531 | 531 | |
| @@ -545,7 +545,7 @@ static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size) · 13 unmodified lines | ||
| 545 | 545 | (cxlr->mode == CXL_DECODER_PMEM && uuid_is_null(&p->uuid))) |
| 546 | 546 | return -ENXIO; |
| 547 | 547 | |
| 548 | − div_u64_rem(size, SZ_256M * p->interleave_ways, &remainder); | |
| 548 | + div64_u64_rem(size, (u64)SZ_256M * p->interleave_ways, &remainder); | |
| 549 | 549 | if (remainder) |
| 550 | 550 | return -EINVAL; |
| 551 | 551 | |
| @@ -382,7 +382,7 @@ static int cxl_pci_mbox_send(struct cxl_memdev_state *mds, · 381 unmodified lines | ||
| 382 | 382 | return rc; |
| 383 | 383 | } |
| 384 | 384 | |
| 385 | −static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds) | |
| 385 | +static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds, bool irq_avail) | |
| 386 | 386 | { |
| 387 | 387 | struct cxl_dev_state *cxlds = &mds->cxlds; |
| 388 | 388 | const int cap = readl(cxlds->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET); |
| @@ -441,7 +441,7 @@ static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds) · 52 unmodified lines | ||
| 441 | 441 | INIT_DELAYED_WORK(&mds->security.poll_dwork, cxl_mbox_sanitize_work); |
| 442 | 442 | |
| 443 | 443 | /* background command interrupts are optional */ |
| 444 | − if (!(cap & CXLDEV_MBOX_CAP_BG_CMD_IRQ)) | |
| 444 | + if (!(cap & CXLDEV_MBOX_CAP_BG_CMD_IRQ) || !irq_avail) | |
| 445 | 445 | return 0; |
| 446 | 446 | |
| 447 | 447 | msgnum = FIELD_GET(CXLDEV_MBOX_CAP_IRQ_MSGNUM_MASK, cap); |
| @@ -588,7 +588,7 @@ static int cxl_mem_alloc_event_buf(struct cxl_memdev_state *mds) · 140 unmodified lines | ||
| 588 | 588 | return devm_add_action_or_reset(mds->cxlds.dev, free_event_buf, buf); |
| 589 | 589 | } |
| 590 | 590 | |
| 591 | −static int cxl_alloc_irq_vectors(struct pci_dev *pdev) | |
| 591 | +static bool cxl_alloc_irq_vectors(struct pci_dev *pdev) | |
| 592 | 592 | { |
| 593 | 593 | int nvecs; |
| 594 | 594 | |
| @@ -605,9 +605,9 @@ static int cxl_alloc_irq_vectors(struct pci_dev *pdev) · 10 unmodified lines | ||
| 605 | 605 | PCI_IRQ_MSIX | PCI_IRQ_MSI); |
| 606 | 606 | if (nvecs < 1) { |
| 607 | 607 | dev_dbg(&pdev->dev, "Failed to alloc irq vectors: %d\n", nvecs); |
| 608 | − return -ENXIO; | |
| 608 | + return false; | |
| 609 | 609 | } |
| 610 | − return 0; | |
| 610 | + return true; | |
| 611 | 611 | } |
| 612 | 612 | |
| 613 | 613 | static irqreturn_t cxl_event_thread(int irq, void *id) |
| @@ -743,7 +743,7 @@ static bool cxl_event_int_is_fw(u8 setting) · 129 unmodified lines | ||
| 743 | 743 | } |
| 744 | 744 | |
| 745 | 745 | static int cxl_event_config(struct pci_host_bridge *host_bridge, |
| 746 | − struct cxl_memdev_state *mds) | |
| 746 | + struct cxl_memdev_state *mds, bool irq_avail) | |
| 747 | 747 | { |
| 748 | 748 | struct cxl_event_interrupt_policy policy; |
| 749 | 749 | int rc; |
| @@ -755,6 +755,11 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge, · 5 unmodified lines | ||
| 755 | 755 | if (!host_bridge->native_cxl_error) |
| 756 | 756 | return 0; |
| 757 | 757 | |
| 758 | + if (!irq_avail) { | |
| 759 | + dev_info(mds->cxlds.dev, "No interrupt support, disable event processing.\n"); | |
| 760 | + return 0; | |
| 761 | + } | |
| 762 | + | |
| 758 | 763 | rc = cxl_mem_alloc_event_buf(mds); |
| 759 | 764 | if (rc) |
| 760 | 765 | return rc; |
| @@ -789,6 +794,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 28 unmodified lines | ||
| 789 | 794 | struct cxl_register_map map; |
| 790 | 795 | struct cxl_memdev *cxlmd; |
| 791 | 796 | int i, rc, pmu_count; |
| 797 | + bool irq_avail; | |
| 792 | 798 | |
| 793 | 799 | /* |
| 794 | 800 | * Double check the anonymous union trickery in struct cxl_regs |
| @@ -846,11 +852,9 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 51 unmodified lines | ||
| 846 | 852 | else |
| 847 | 853 | dev_warn(&pdev->dev, "Media not active (%d)\n", rc); |
| 848 | 854 | |
| 849 | − rc = cxl_alloc_irq_vectors(pdev); | |
| 850 | − if (rc) | |
| 851 | − return rc; | |
| 855 | + irq_avail = cxl_alloc_irq_vectors(pdev); | |
| 852 | 856 | |
| 853 | − rc = cxl_pci_setup_mailbox(mds); | |
| 857 | + rc = cxl_pci_setup_mailbox(mds, irq_avail); | |
| 854 | 858 | if (rc) |
| 855 | 859 | return rc; |
| 856 | 860 | |
| @@ -909,7 +913,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 52 unmodified lines | ||
| 909 | 913 | } |
| 910 | 914 | } |
| 911 | 915 | |
| 912 | − rc = cxl_event_config(host_bridge, mds); | |
| 916 | + rc = cxl_event_config(host_bridge, mds, irq_avail); | |
| 913 | 917 | if (rc) |
| 914 | 918 | return rc; |
| 915 | 919 | |
| @@ -118,10 +118,9 @@ static int textual_leaf_to_string(const u32 *block, char *buf, size_t size) · 117 unmodified lines | ||
| 118 | 118 | * @buf: where to put the string |
| 119 | 119 | * @size: size of @buf, in bytes |
| 120 | 120 | * |
| 121 | − * The string is taken from a minimal ASCII text descriptor leaf after | |
| 122 | − * the immediate entry with @key. The string is zero-terminated. | |
| 123 | − * An overlong string is silently truncated such that it and the | |
| 124 | − * zero byte fit into @size. | |
| 121 | + * The string is taken from a minimal ASCII text descriptor leaf just after the entry with the | |
| 122 | + * @key. The string is zero-terminated. An overlong string is silently truncated such that it | |
| 123 | + * and the zero byte fit into @size. | |
| 125 | 124 | * |
| 126 | 125 | * Returns strlen(buf) or a negative error code. |
| 127 | 126 | */ |
| @@ -368,8 +367,17 @@ static ssize_t show_text_leaf(struct device *dev, · 240 unmodified lines | ||
| 368 | 367 | for (i = 0; i < ARRAY_SIZE(directories) && !!directories[i]; ++i) { |
| 369 | 368 | int result = fw_csr_string(directories[i], attr->key, buf, bufsize); |
| 370 | 369 | // Detected. |
| 371 | − if (result >= 0) | |
| 370 | + if (result >= 0) { | |
| 372 | 371 | ret = result; |
| 372 | + } else if (i == 0 && attr->key == CSR_VENDOR) { | |
| 373 | + // Sony DVMC-DA1 has configuration ROM such that the descriptor leaf entry | |
| 374 | + // in the root directory follows to the directory entry for vendor ID | |
| 375 | + // instead of the immediate value for vendor ID. | |
| 376 | + result = fw_csr_string(directories[i], CSR_DIRECTORY | attr->key, buf, | |
| 377 | + bufsize); | |
| 378 | + if (result >= 0) | |
| 379 | + ret = result; | |
| 380 | + } | |
| 373 | 381 | } |
| 374 | 382 | |
| 375 | 383 | if (ret >= 0) { |
| @@ -107,12 +107,12 @@ struct ffa_drv_info { · 106 unmodified lines | ||
| 107 | 107 | struct work_struct notif_pcpu_work; |
| 108 | 108 | struct work_struct irq_work; |
| 109 | 109 | struct xarray partition_info; |
| 110 | − unsigned int partition_count; | |
| 111 | 110 | DECLARE_HASHTABLE(notifier_hash, ilog2(FFA_MAX_NOTIFICATIONS)); |
| 112 | 111 | struct mutex notify_lock; /* lock to protect notifier hashtable */ |
| 113 | 112 | }; |
| 114 | 113 | |
| 115 | 114 | static struct ffa_drv_info *drv_info; |
| 115 | +static void ffa_partitions_cleanup(void); | |
| 116 | 116 | |
| 117 | 117 | /* |
| 118 | 118 | * The driver must be able to support all the versions from the earliest |
| @@ -733,6 +733,11 @@ static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu) · 614 unmodified lines | ||
| 733 | 733 | void *cb_data; |
| 734 | 734 | |
| 735 | 735 | partition = xa_load(&drv_info->partition_info, part_id); |
| 736 | + if (!partition) { | |
| 737 | + pr_err("%s: Invalid partition ID 0x%x\n", __func__, part_id); | |
| 738 | + return; | |
| 739 | + } | |
| 740 | + | |
| 736 | 741 | read_lock(&partition->rw_lock); |
| 737 | 742 | callback = partition->callback; |
| 738 | 743 | cb_data = partition->cb_data; |
| @@ -915,6 +920,11 @@ static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback, · 176 unmodified lines | ||
| 915 | 920 | return -EOPNOTSUPP; |
| 916 | 921 | |
| 917 | 922 | partition = xa_load(&drv_info->partition_info, part_id); |
| 923 | + if (!partition) { | |
| 924 | + pr_err("%s: Invalid partition ID 0x%x\n", __func__, part_id); | |
| 925 | + return -EINVAL; | |
| 926 | + } | |
| 927 | + | |
| 918 | 928 | write_lock(&partition->rw_lock); |
| 919 | 929 | |
| 920 | 930 | cb_valid = !!partition->callback; |
| @@ -1186,9 +1196,9 @@ void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid) · 265 unmodified lines | ||
| 1186 | 1196 | kfree(pbuf); |
| 1187 | 1197 | } |
| 1188 | 1198 | |
| 1189 | −static void ffa_setup_partitions(void) | |
| 1199 | +static int ffa_setup_partitions(void) | |
| 1190 | 1200 | { |
| 1191 | − int count, idx; | |
| 1201 | + int count, idx, ret; | |
| 1192 | 1202 | uuid_t uuid; |
| 1193 | 1203 | struct ffa_device *ffa_dev; |
| 1194 | 1204 | struct ffa_dev_part_info *info; |
| @@ -1197,7 +1207,7 @@ static void ffa_setup_partitions(void) · 2 unmodified lines | ||
| 1197 | 1207 | count = ffa_partition_probe(&uuid_null, &pbuf); |
| 1198 | 1208 | if (count <= 0) { |
| 1199 | 1209 | pr_info("%s: No partitions found, error %d\n", __func__, count); |
| 1200 | − return; | |
| 1210 | + return -EINVAL; | |
| 1201 | 1211 | } |
| 1202 | 1212 | |
| 1203 | 1213 | xa_init(&drv_info->partition_info); |
| @@ -1226,40 +1236,53 @@ static void ffa_setup_partitions(void) · 22 unmodified lines | ||
| 1226 | 1236 | ffa_device_unregister(ffa_dev); |
| 1227 | 1237 | continue; |
| 1228 | 1238 | } |
| 1229 | − xa_store(&drv_info->partition_info, tpbuf->id, info, GFP_KERNEL); | |
| 1239 | + rwlock_init(&info->rw_lock); | |
| 1240 | + ret = xa_insert(&drv_info->partition_info, tpbuf->id, | |
| 1241 | + info, GFP_KERNEL); | |
| 1242 | + if (ret) { | |
| 1243 | + pr_err("%s: failed to save partition ID 0x%x - ret:%d\n", | |
| 1244 | + __func__, tpbuf->id, ret); | |
| 1245 | + ffa_device_unregister(ffa_dev); | |
| 1246 | + kfree(info); | |
| 1247 | + } | |
| 1230 | 1248 | } |
| 1231 | − drv_info->partition_count = count; | |
| 1232 | 1249 | |
| 1233 | 1250 | kfree(pbuf); |
| 1234 | 1251 | |
| 1235 | 1252 | /* Allocate for the host */ |
| 1236 | 1253 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
| 1237 | − if (!info) | |
| 1238 | − return; | |
| 1239 | − xa_store(&drv_info->partition_info, drv_info->vm_id, info, GFP_KERNEL); | |
| 1240 | − drv_info->partition_count++; | |
| 1254 | + if (!info) { | |
| 1255 | + pr_err("%s: failed to alloc Host partition ID 0x%x. Abort.\n", | |
| 1256 | + __func__, drv_info->vm_id); | |
| 1257 | + /* Already registered devices are freed on bus_exit */ | |
| 1258 | + ffa_partitions_cleanup(); | |
| 1259 | + return -ENOMEM; | |
| 1260 | + } | |
| 1261 | + | |
| 1262 | + rwlock_init(&info->rw_lock); | |
| 1263 | + ret = xa_insert(&drv_info->partition_info, drv_info->vm_id, | |
| 1264 | + info, GFP_KERNEL); | |
| 1265 | + if (ret) { | |
| 1266 | + pr_err("%s: failed to save Host partition ID 0x%x - ret:%d. Abort.\n", | |
| 1267 | + __func__, drv_info->vm_id, ret); | |
| 1268 | + kfree(info); | |
| 1269 | + /* Already registered devices are freed on bus_exit */ | |
| 1270 | + ffa_partitions_cleanup(); | |
| 1271 | + } | |
| 1272 | + | |
| 1273 | + return ret; | |
| 1241 | 1274 | } |
| 1242 | 1275 | |
| 1243 | 1276 | static void ffa_partitions_cleanup(void) |
| 1244 | 1277 | { |
| 1245 | − struct ffa_dev_part_info **info; | |
| 1246 | − int idx, count = drv_info->partition_count; | |
| 1247 | − | |
| 1248 | − if (!count) | |
| 1249 | − return; | |
| 1250 | − | |
| 1251 | − info = kcalloc(count, sizeof(*info), GFP_KERNEL); | |
| 1252 | − if (!info) | |
| 1253 | − return; | |
| 1254 | − | |
| 1255 | − xa_extract(&drv_info->partition_info, (void **)info, 0, VM_ID_MASK, | |
| 1256 | − count, XA_PRESENT); | |
| 1278 | + struct ffa_dev_part_info *info; | |
| 1279 | + unsigned long idx; | |
| 1257 | 1280 | |
| 1258 | − for (idx = 0; idx < count; idx++) | |
| 1259 | − kfree(info[idx]); | |
| 1260 | − kfree(info); | |
| 1281 | + xa_for_each(&drv_info->partition_info, idx, info) { | |
| 1282 | + xa_erase(&drv_info->partition_info, idx); | |
| 1283 | + kfree(info); | |
| 1284 | + } | |
| 1261 | 1285 | |
| 1262 | − drv_info->partition_count = 0; | |
| 1263 | 1286 | xa_destroy(&drv_info->partition_info); |
| 1264 | 1287 | } |
| 1265 | 1288 | |
| @@ -1508,7 +1531,11 @@ static int __init ffa_init(void) · 242 unmodified lines | ||
| 1508 | 1531 | |
| 1509 | 1532 | ffa_notifications_setup(); |
| 1510 | 1533 | |
| 1511 | − ffa_setup_partitions(); | |
| 1534 | + ret = ffa_setup_partitions(); | |
| 1535 | + if (ret) { | |
| 1536 | + pr_err("failed to setup partitions\n"); | |
| 1537 | + goto cleanup_notifs; | |
| 1538 | + } | |
| 1512 | 1539 | |
| 1513 | 1540 | ret = ffa_sched_recv_cb_update(drv_info->vm_id, ffa_self_notif_handle, |
| 1514 | 1541 | drv_info, true); |
| @@ -1516,6 +1543,9 @@ static int __init ffa_init(void) · 1 unmodified line | ||
| 1516 | 1543 | pr_info("Failed to register driver sched callback %d\n", ret); |
| 1517 | 1544 | |
| 1518 | 1545 | return 0; |
| 1546 | + | |
| 1547 | +cleanup_notifs: | |
| 1548 | + ffa_notifications_cleanup(); | |
| 1519 | 1549 | free_pages: |
| 1520 | 1550 | if (drv_info->tx_buffer) |
| 1521 | 1551 | free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); |
| @@ -1535,7 +1565,6 @@ static void __exit ffa_exit(void) · 13 unmodified lines | ||
| 1535 | 1565 | ffa_rxtx_unmap(drv_info->vm_id); |
| 1536 | 1566 | free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); |
| 1537 | 1567 | free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE); |
| 1538 | − xa_destroy(&drv_info->partition_info); | |
| 1539 | 1568 | kfree(drv_info); |
| 1540 | 1569 | arm_ffa_bus_exit(); |
| 1541 | 1570 | } |
| @@ -13,7 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | #include "notify.h" |
| 14 | 14 | |
| 15 | 15 | /* Updated only after ALL the mandatory features for that version are merged */ |
| 16 | −#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001 | |
| 16 | +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 | |
| 17 | 17 | |
| 18 | 18 | enum scmi_clock_protocol_cmd { |
| 19 | 19 | CLOCK_ATTRIBUTES = 0x3, |
| @@ -954,8 +954,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph) · 934 unmodified lines | ||
| 954 | 954 | scmi_clock_describe_rates_get(ph, clkid, clk); |
| 955 | 955 | } |
| 956 | 956 | |
| 957 | − if (PROTOCOL_REV_MAJOR(version) >= 0x2 && | |
| 958 | − PROTOCOL_REV_MINOR(version) >= 0x1) { | |
| 957 | + if (PROTOCOL_REV_MAJOR(version) >= 0x3) { | |
| 959 | 958 | cinfo->clock_config_set = scmi_clock_config_set_v2; |
| 960 | 959 | cinfo->clock_config_get = scmi_clock_config_get_v2; |
| 961 | 960 | } else { |
| @@ -314,6 +314,7 @@ void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, · 313 unmodified lines | ||
| 314 | 314 | void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem); |
| 315 | 315 | bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, |
| 316 | 316 | struct scmi_xfer *xfer); |
| 317 | +bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem); | |
| 317 | 318 | |
| 318 | 319 | /* declarations for message passing transports */ |
| 319 | 320 | struct scmi_msg_payld; |
| @@ -45,6 +45,20 @@ static void rx_callback(struct mbox_client *cl, void *m) · 44 unmodified lines | ||
| 45 | 45 | { |
| 46 | 46 | struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl); |
| 47 | 47 | |
| 48 | + /* | |
| 49 | + * An A2P IRQ is NOT valid when received while the platform still has | |
| 50 | + * the ownership of the channel, because the platform at first releases | |
| 51 | + * the SMT channel and then sends the completion interrupt. | |
| 52 | + * | |
| 53 | + * This addresses a possible race condition in which a spurious IRQ from | |
| 54 | + * a previous timed-out reply which arrived late could be wrongly | |
| 55 | + * associated with the next pending transaction. | |
| 56 | + */ | |
| 57 | + if (cl->knows_txdone && !shmem_channel_free(smbox->shmem)) { | |
| 58 | + dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n"); | |
| 59 | + return; | |
| 60 | + } | |
| 61 | + | |
| 48 | 62 | scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem), NULL); |
| 49 | 63 | } |
| 50 | 64 | |
| @@ -350,8 +350,8 @@ process_response_opp(struct scmi_opp *opp, unsigned int loop_idx, · 349 unmodified lines | ||
| 350 | 350 | } |
| 351 | 351 | |
| 352 | 352 | static inline void |
| 353 | −process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp, | |
| 354 | − unsigned int loop_idx, | |
| 353 | +process_response_opp_v4(struct device *dev, struct perf_dom_info *dom, | |
| 354 | + struct scmi_opp *opp, unsigned int loop_idx, | |
| 355 | 355 | const struct scmi_msg_resp_perf_describe_levels_v4 *r) |
| 356 | 356 | { |
| 357 | 357 | opp->perf = le32_to_cpu(r->opp[loop_idx].perf_val); |
| @@ -362,10 +362,23 @@ process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp, · 4 unmodified lines | ||
| 362 | 362 | /* Note that PERF v4 reports always five 32-bit words */ |
| 363 | 363 | opp->indicative_freq = le32_to_cpu(r->opp[loop_idx].indicative_freq); |
| 364 | 364 | if (dom->level_indexing_mode) { |
| 365 | + int ret; | |
| 366 | + | |
| 365 | 367 | opp->level_index = le32_to_cpu(r->opp[loop_idx].level_index); |
| 366 | 368 | |
| 367 | − xa_store(&dom->opps_by_idx, opp->level_index, opp, GFP_KERNEL); | |
| 368 | − xa_store(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL); | |
| 369 | + ret = xa_insert(&dom->opps_by_idx, opp->level_index, opp, | |
| 370 | + GFP_KERNEL); | |
| 371 | + if (ret) | |
| 372 | + dev_warn(dev, | |
| 373 | + "Failed to add opps_by_idx at %d - ret:%d\n", | |
| 374 | + opp->level_index, ret); | |
| 375 | + | |
| 376 | + ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL); | |
| 377 | + if (ret) | |
| 378 | + dev_warn(dev, | |
| 379 | + "Failed to add opps_by_lvl at %d - ret:%d\n", | |
| 380 | + opp->perf, ret); | |
| 381 | + | |
| 369 | 382 | hash_add(dom->opps_by_freq, &opp->hash, opp->indicative_freq); |
| 370 | 383 | } |
| 371 | 384 | } |
| @@ -382,7 +395,7 @@ iter_perf_levels_process_response(const struct scmi_protocol_handle *ph, · 10 unmodified lines | ||
| 382 | 395 | if (PROTOCOL_REV_MAJOR(p->version) <= 0x3) |
| 383 | 396 | process_response_opp(opp, st->loop_idx, response); |
| 384 | 397 | else |
| 385 | − process_response_opp_v4(p->perf_dom, opp, st->loop_idx, | |
| 398 | + process_response_opp_v4(ph->dev, p->perf_dom, opp, st->loop_idx, | |
| 386 | 399 | response); |
| 387 | 400 | p->perf_dom->opp_count++; |
| 388 | 401 | |
| @@ -1111,7 +1111,6 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw, · 1110 unmodified lines | ||
| 1111 | 1111 | int i; |
| 1112 | 1112 | |
| 1113 | 1113 | for (i = 0; i < num_chans; i++) { |
| 1114 | − void *xret; | |
| 1115 | 1114 | struct scmi_raw_queue *q; |
| 1116 | 1115 | |
| 1117 | 1116 | q = scmi_raw_queue_init(raw); |
| @@ -1120,13 +1119,12 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw, · 2 unmodified lines | ||
| 1120 | 1119 | goto err_xa; |
| 1121 | 1120 | } |
| 1122 | 1121 | |
| 1123 | − xret = xa_store(&raw->chans_q, channels[i], q, | |
| 1122 | + ret = xa_insert(&raw->chans_q, channels[i], q, | |
| 1124 | 1123 | GFP_KERNEL); |
| 1125 | − if (xa_err(xret)) { | |
| 1124 | + if (ret) { | |
| 1126 | 1125 | dev_err(dev, |
| 1127 | 1126 | "Fail to allocate Raw queue 0x%02X\n", |
| 1128 | 1127 | channels[i]); |
| 1129 | − ret = xa_err(xret); | |
| 1130 | 1128 | goto err_xa; |
| 1131 | 1129 | } |
| 1132 | 1130 | } |
| @@ -1322,6 +1320,12 @@ void scmi_raw_message_report(void *r, struct scmi_xfer *xfer, · 189 unmodified lines | ||
| 1322 | 1320 | dev = raw->handle->dev; |
| 1323 | 1321 | q = scmi_raw_queue_select(raw, idx, |
| 1324 | 1322 | SCMI_XFER_IS_CHAN_SET(xfer) ? chan_id : 0); |
| 1323 | + if (!q) { | |
| 1324 | + dev_warn(dev, | |
| 1325 | + "RAW[%d] - NO queue for chan 0x%X. Dropping report.\n", | |
| 1326 | + idx, chan_id); | |
| 1327 | + return; | |
| 1328 | + } | |
| 1325 | 1329 | |
| 1326 | 1330 | /* |
| 1327 | 1331 | * Grab the msg_q_lock upfront to avoid a possible race between |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/processor.h> |
| 11 | 11 | #include <linux/types.h> |
| 12 | 12 | |
| 13 | −#include <asm-generic/bug.h> | |
| 13 | +#include <linux/bug.h> | |
| 14 | 14 | |
| 15 | 15 | #include "common.h" |
| 16 | 16 | |
| @@ -122,3 +122,9 @@ bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, · 105 unmodified lines | ||
| 122 | 122 | (SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR | |
| 123 | 123 | SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); |
| 124 | 124 | } |
| 125 | + | |
| 126 | +bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem) | |
| 127 | +{ | |
| 128 | + return (ioread32(&shmem->channel_status) & | |
| 129 | + SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); | |
| 130 | +} | |
| @@ -128,4 +128,4 @@ unlock_mutex: · 127 unmodified lines | ||
| 128 | 128 | } |
| 129 | 129 | |
| 130 | 130 | /* must execute after PCI subsystem for EFI quirks */ |
| 131 | −subsys_initcall_sync(sysfb_init); | |
| 131 | +device_initcall(sysfb_init); | |
| @@ -330,20 +330,27 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) · 329 unmodified lines | ||
| 330 | 330 | switch (flow_type) { |
| 331 | 331 | case IRQ_TYPE_LEVEL_HIGH: |
| 332 | 332 | sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1); |
| 333 | + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1); | |
| 333 | 334 | break; |
| 334 | 335 | case IRQ_TYPE_LEVEL_LOW: |
| 335 | 336 | sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0); |
| 337 | + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1); | |
| 336 | 338 | break; |
| 337 | 339 | case IRQ_TYPE_EDGE_RISING: |
| 338 | 340 | case IRQ_TYPE_EDGE_FALLING: |
| 339 | 341 | case IRQ_TYPE_EDGE_BOTH: |
| 340 | 342 | state = sprd_eic_get(chip, offset); |
| 341 | − if (state) | |
| 343 | + if (state) { | |
| 342 | 344 | sprd_eic_update(chip, offset, |
| 343 | 345 | SPRD_EIC_DBNC_IEV, 0); |
| 344 | − else | |
| 346 | + sprd_eic_update(chip, offset, | |
| 347 | + SPRD_EIC_DBNC_IC, 1); | |
| 348 | + } else { | |
| 345 | 349 | sprd_eic_update(chip, offset, |
| 346 | 350 | SPRD_EIC_DBNC_IEV, 1); |
| 351 | + sprd_eic_update(chip, offset, | |
| 352 | + SPRD_EIC_DBNC_IC, 1); | |
| 353 | + } | |
| 347 | 354 | break; |
| 348 | 355 | default: |
| 349 | 356 | return -ENOTSUPP; |
| @@ -355,20 +362,27 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) · 5 unmodified lines | ||
| 355 | 362 | switch (flow_type) { |
| 356 | 363 | case IRQ_TYPE_LEVEL_HIGH: |
| 357 | 364 | sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0); |
| 365 | + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1); | |
| 358 | 366 | break; |
| 359 | 367 | case IRQ_TYPE_LEVEL_LOW: |
| 360 | 368 | sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1); |
| 369 | + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1); | |
| 361 | 370 | break; |
| 362 | 371 | case IRQ_TYPE_EDGE_RISING: |
| 363 | 372 | case IRQ_TYPE_EDGE_FALLING: |
| 364 | 373 | case IRQ_TYPE_EDGE_BOTH: |
| 365 | 374 | state = sprd_eic_get(chip, offset); |
| 366 | − if (state) | |
| 375 | + if (state) { | |
| 367 | 376 | sprd_eic_update(chip, offset, |
| 368 | 377 | SPRD_EIC_LATCH_INTPOL, 0); |
| 369 | − else | |
| 378 | + sprd_eic_update(chip, offset, | |
| 379 | + SPRD_EIC_LATCH_INTCLR, 1); | |
| 380 | + } else { | |
| 370 | 381 | sprd_eic_update(chip, offset, |
| 371 | 382 | SPRD_EIC_LATCH_INTPOL, 1); |
| 383 | + sprd_eic_update(chip, offset, | |
| 384 | + SPRD_EIC_LATCH_INTCLR, 1); | |
| 385 | + } | |
| 372 | 386 | break; |
| 373 | 387 | default: |
| 374 | 388 | return -ENOTSUPP; |
| @@ -382,29 +396,34 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) · 7 unmodified lines | ||
| 382 | 396 | sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); |
| 383 | 397 | sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0); |
| 384 | 398 | sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1); |
| 399 | + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); | |
| 385 | 400 | irq_set_handler_locked(data, handle_edge_irq); |
| 386 | 401 | break; |
| 387 | 402 | case IRQ_TYPE_EDGE_FALLING: |
| 388 | 403 | sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); |
| 389 | 404 | sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0); |
| 390 | 405 | sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0); |
| 406 | + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); | |
| 391 | 407 | irq_set_handler_locked(data, handle_edge_irq); |
| 392 | 408 | break; |
| 393 | 409 | case IRQ_TYPE_EDGE_BOTH: |
| 394 | 410 | sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0); |
| 395 | 411 | sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 1); |
| 412 | + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); | |
| 396 | 413 | irq_set_handler_locked(data, handle_edge_irq); |
| 397 | 414 | break; |
| 398 | 415 | case IRQ_TYPE_LEVEL_HIGH: |
| 399 | 416 | sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); |
| 400 | 417 | sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1); |
| 401 | 418 | sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1); |
| 419 | + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); | |
| 402 | 420 | irq_set_handler_locked(data, handle_level_irq); |
| 403 | 421 | break; |
| 404 | 422 | case IRQ_TYPE_LEVEL_LOW: |
| 405 | 423 | sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); |
| 406 | 424 | sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1); |
| 407 | 425 | sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0); |
| 426 | + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); | |
| 408 | 427 | irq_set_handler_locked(data, handle_level_irq); |
| 409 | 428 | break; |
| 410 | 429 | default: |
| @@ -417,29 +436,34 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) · 6 unmodified lines | ||
| 417 | 436 | sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); |
| 418 | 437 | sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0); |
| 419 | 438 | sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1); |
| 439 | + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); | |
| 420 | 440 | irq_set_handler_locked(data, handle_edge_irq); |
| 421 | 441 | break; |
| 422 | 442 | case IRQ_TYPE_EDGE_FALLING: |
| 423 | 443 | sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); |
| 424 | 444 | sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0); |
| 425 | 445 | sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0); |
| 446 | + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); | |
| 426 | 447 | irq_set_handler_locked(data, handle_edge_irq); |
| 427 | 448 | break; |
| 428 | 449 | case IRQ_TYPE_EDGE_BOTH: |
| 429 | 450 | sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0); |
| 430 | 451 | sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 1); |
| 452 | + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); | |
| 431 | 453 | irq_set_handler_locked(data, handle_edge_irq); |
| 432 | 454 | break; |
| 433 | 455 | case IRQ_TYPE_LEVEL_HIGH: |
| 434 | 456 | sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); |
| 435 | 457 | sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1); |
| 436 | 458 | sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1); |
| 459 | + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); | |
| 437 | 460 | irq_set_handler_locked(data, handle_level_irq); |
| 438 | 461 | break; |
| 439 | 462 | case IRQ_TYPE_LEVEL_LOW: |
| 440 | 463 | sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); |
| 441 | 464 | sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1); |
| 442 | 465 | sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0); |
| 466 | + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); | |
| 443 | 467 | irq_set_handler_locked(data, handle_level_irq); |
| 444 | 468 | break; |
| 445 | 469 | default: |
| @@ -1651,6 +1651,20 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = { · 1650 unmodified lines | ||
| 1651 | 1651 | .ignore_interrupt = "INT33FC:00@3", |
| 1652 | 1652 | }, |
| 1653 | 1653 | }, |
| 1654 | + { | |
| 1655 | + /* | |
| 1656 | + * Spurious wakeups from TP_ATTN# pin | |
| 1657 | + * Found in BIOS 0.35 | |
| 1658 | + * https://gitlab.freedesktop.org/drm/amd/-/issues/3073 | |
| 1659 | + */ | |
| 1660 | + .matches = { | |
| 1661 | + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), | |
| 1662 | + DMI_MATCH(DMI_PRODUCT_NAME, "G1619-04"), | |
| 1663 | + }, | |
| 1664 | + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { | |
| 1665 | + .ignore_wake = "PNP0C50:00@8", | |
| 1666 | + }, | |
| 1667 | + }, | |
| 1654 | 1668 | {} /* Terminating entry */ |
| 1655 | 1669 | }; |
| 1656 | 1670 | |
| @@ -121,6 +121,7 @@ int amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev) · 120 unmodified lines | ||
| 121 | 121 | struct amdgpu_bo_param bp; |
| 122 | 122 | dma_addr_t dma_addr; |
| 123 | 123 | struct page *p; |
| 124 | + unsigned long x; | |
| 124 | 125 | int ret; |
| 125 | 126 | |
| 126 | 127 | if (adev->gart.bo != NULL) |
| @@ -130,6 +131,10 @@ int amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev) · 3 unmodified lines | ||
| 130 | 131 | if (!p) |
| 131 | 132 | return -ENOMEM; |
| 132 | 133 | |
| 134 | + /* assign pages to this device */ | |
| 135 | + for (x = 0; x < (1UL << order); x++) | |
| 136 | + p[x].mapping = adev->mman.bdev.dev_mapping; | |
| 137 | + | |
| 133 | 138 | /* If the hardware does not support UTCL2 snooping of the CPU caches |
| 134 | 139 | * then set_memory_wc() could be used as a workaround to mark the pages |
| 135 | 140 | * as write combine memory. |
| @@ -223,6 +228,7 @@ void amdgpu_gart_table_ram_free(struct amdgpu_device *adev) · 87 unmodified lines | ||
| 223 | 228 | unsigned int order = get_order(adev->gart.table_size); |
| 224 | 229 | struct sg_table *sg = adev->gart.bo->tbo.sg; |
| 225 | 230 | struct page *p; |
| 231 | + unsigned long x; | |
| 226 | 232 | int ret; |
| 227 | 233 | |
| 228 | 234 | ret = amdgpu_bo_reserve(adev->gart.bo, false); |
| @@ -234,6 +240,8 @@ void amdgpu_gart_table_ram_free(struct amdgpu_device *adev) · 5 unmodified lines | ||
| 234 | 240 | sg_free_table(sg); |
| 235 | 241 | kfree(sg); |
| 236 | 242 | p = virt_to_page(adev->gart.ptr); |
| 243 | + for (x = 0; x < (1UL << order); x++) | |
| 244 | + p[x].mapping = NULL; | |
| 237 | 245 | __free_pages(p, order); |
| 238 | 246 | |
| 239 | 247 | adev->gart.ptr = NULL; |
| @@ -221,8 +221,23 @@ static struct attribute *amdgpu_vram_mgr_attributes[] = { · 220 unmodified lines | ||
| 221 | 221 | NULL |
| 222 | 222 | }; |
| 223 | 223 | |
| 224 | +static umode_t amdgpu_vram_attrs_is_visible(struct kobject *kobj, | |
| 225 | + struct attribute *attr, int i) | |
| 226 | +{ | |
| 227 | + struct device *dev = kobj_to_dev(kobj); | |
| 228 | + struct drm_device *ddev = dev_get_drvdata(dev); | |
| 229 | + struct amdgpu_device *adev = drm_to_adev(ddev); | |
| 230 | + | |
| 231 | + if (attr == &dev_attr_mem_info_vram_vendor.attr && | |
| 232 | + !adev->gmc.vram_vendor) | |
| 233 | + return 0; | |
| 234 | + | |
| 235 | + return attr->mode; | |
| 236 | +} | |
| 237 | + | |
| 224 | 238 | const struct attribute_group amdgpu_vram_mgr_attr_group = { |
| 225 | − .attrs = amdgpu_vram_mgr_attributes | |
| 239 | + .attrs = amdgpu_vram_mgr_attributes, | |
| 240 | + .is_visible = amdgpu_vram_attrs_is_visible | |
| 226 | 241 | }; |
| 227 | 242 | |
| 228 | 243 | /** |
| @@ -6589,7 +6589,7 @@ static int gfx_v10_0_compute_mqd_init(struct amdgpu_device *adev, void *m, · 6588 unmodified lines | ||
| 6589 | 6589 | #ifdef __BIG_ENDIAN |
| 6590 | 6590 | tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, ENDIAN_SWAP, 1); |
| 6591 | 6591 | #endif |
| 6592 | − tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 0); | |
| 6592 | + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1); | |
| 6593 | 6593 | tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH, |
| 6594 | 6594 | prop->allow_tunneling); |
| 6595 | 6595 | tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1); |
| @@ -3846,7 +3846,7 @@ static int gfx_v11_0_compute_mqd_init(struct amdgpu_device *adev, void *m, · 3845 unmodified lines | ||
| 3846 | 3846 | (order_base_2(prop->queue_size / 4) - 1)); |
| 3847 | 3847 | tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, RPTR_BLOCK_SIZE, |
| 3848 | 3848 | (order_base_2(AMDGPU_GPU_PAGE_SIZE / 4) - 1)); |
| 3849 | − tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 0); | |
| 3849 | + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1); | |
| 3850 | 3850 | tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH, |
| 3851 | 3851 | prop->allow_tunneling); |
| 3852 | 3852 | tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1); |
| @@ -1950,7 +1950,8 @@ static void gmc_v9_4_3_init_vram_info(struct amdgpu_device *adev) · 1949 unmodified lines | ||
| 1950 | 1950 | static const u32 regBIF_BIOS_SCRATCH_4 = 0x50; |
| 1951 | 1951 | u32 vram_info; |
| 1952 | 1952 | |
| 1953 | − if (!amdgpu_sriov_vf(adev)) { | |
| 1953 | + /* Only for dGPU, vendor informaton is reliable */ | |
| 1954 | + if (!amdgpu_sriov_vf(adev) && !(adev->flags & AMD_IS_APU)) { | |
| 1954 | 1955 | vram_info = RREG32(regBIF_BIOS_SCRATCH_4); |
| 1955 | 1956 | adev->gmc.vram_vendor = vram_info & 0xF; |
| 1956 | 1957 | } |
| @@ -170,6 +170,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, · 169 unmodified lines | ||
| 170 | 170 | m->cp_hqd_pq_control = 5 << CP_HQD_PQ_CONTROL__RPTR_BLOCK_SIZE__SHIFT; |
| 171 | 171 | m->cp_hqd_pq_control |= |
| 172 | 172 | ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1; |
| 173 | + m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__UNORD_DISPATCH_MASK; | |
| 173 | 174 | pr_debug("cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control); |
| 174 | 175 | |
| 175 | 176 | m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); |
| @@ -224,6 +224,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, · 223 unmodified lines | ||
| 224 | 224 | m->cp_hqd_pq_control = 5 << CP_HQD_PQ_CONTROL__RPTR_BLOCK_SIZE__SHIFT; |
| 225 | 225 | m->cp_hqd_pq_control |= |
| 226 | 226 | ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1; |
| 227 | + m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__UNORD_DISPATCH_MASK; | |
| 227 | 228 | pr_debug("cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control); |
| 228 | 229 | |
| 229 | 230 | m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); |
| @@ -272,6 +272,7 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc, · 271 unmodified lines | ||
| 272 | 272 | { |
| 273 | 273 | u32 v_blank_start, v_blank_end, h_position, v_position; |
| 274 | 274 | struct amdgpu_crtc *acrtc = NULL; |
| 275 | + struct dc *dc = adev->dm.dc; | |
| 275 | 276 | |
| 276 | 277 | if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc)) |
| 277 | 278 | return -EINVAL; |
| @@ -284,6 +285,9 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc, · 6 unmodified lines | ||
| 284 | 285 | return 0; |
| 285 | 286 | } |
| 286 | 287 | |
| 288 | + if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed) | |
| 289 | + dc_allow_idle_optimizations(dc, false); | |
| 290 | + | |
| 287 | 291 | /* |
| 288 | 292 | * TODO rework base driver to use values directly. |
| 289 | 293 | * for now parse it back into reg-format |
| @@ -1715,7 +1719,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) · 1425 unmodified lines | ||
| 1715 | 1719 | init_data.nbio_reg_offsets = adev->reg_offset[NBIO_HWIP][0]; |
| 1716 | 1720 | init_data.clk_reg_offsets = adev->reg_offset[CLK_HWIP][0]; |
| 1717 | 1721 | |
| 1718 | − init_data.flags.disable_ips = DMUB_IPS_DISABLE_ALL; | |
| 1722 | + if (amdgpu_dc_debug_mask & DC_DISABLE_IPS) | |
| 1723 | + init_data.flags.disable_ips = DMUB_IPS_DISABLE_ALL; | |
| 1724 | + | |
| 1725 | + init_data.flags.disable_ips_in_vpb = 1; | |
| 1719 | 1726 | |
| 1720 | 1727 | /* Enable DWB for tested platforms only */ |
| 1721 | 1728 | if (amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 0, 0)) |
| @@ -8976,16 +8983,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) · 7254 unmodified lines | ||
| 8976 | 8983 | |
| 8977 | 8984 | trace_amdgpu_dm_atomic_commit_tail_begin(state); |
| 8978 | 8985 | |
| 8979 | − if (dm->dc->caps.ips_support) { | |
| 8980 | − for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) { | |
| 8981 | − if (new_con_state->crtc && | |
| 8982 | − new_con_state->crtc->state->active && | |
| 8983 | − drm_atomic_crtc_needs_modeset(new_con_state->crtc->state)) { | |
| 8984 | − dc_dmub_srv_apply_idle_power_optimizations(dm->dc, false); | |
| 8985 | − break; | |
| 8986 | − } | |
| 8987 | − } | |
| 8988 | − } | |
| 8986 | + if (dm->dc->caps.ips_support && dm->dc->idle_optimizations_allowed) | |
| 8987 | + dc_allow_idle_optimizations(dm->dc, false); | |
| 8989 | 8988 | |
| 8990 | 8989 | drm_atomic_helper_update_legacy_modeset_state(dev, state); |
| 8991 | 8990 | drm_dp_mst_atomic_wait_for_dependencies(state); |
| @@ -711,7 +711,7 @@ static inline int dm_irq_state(struct amdgpu_device *adev, · 710 unmodified lines | ||
| 711 | 711 | { |
| 712 | 712 | bool st; |
| 713 | 713 | enum dc_irq_source irq_source; |
| 714 | − | |
| 714 | + struct dc *dc = adev->dm.dc; | |
| 715 | 715 | struct amdgpu_crtc *acrtc = adev->mode_info.crtcs[crtc_id]; |
| 716 | 716 | |
| 717 | 717 | if (!acrtc) { |
| @@ -729,6 +729,9 @@ static inline int dm_irq_state(struct amdgpu_device *adev, · 11 unmodified lines | ||
| 729 | 729 | |
| 730 | 730 | st = (state == AMDGPU_IRQ_STATE_ENABLE); |
| 731 | 731 | |
| 732 | + if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed) | |
| 733 | + dc_allow_idle_optimizations(dc, false); | |
| 734 | + | |
| 732 | 735 | dc_interrupt_set(adev->dm.dc, irq_source, st); |
| 733 | 736 | return 0; |
| 734 | 737 | } |
| @@ -434,6 +434,7 @@ struct dc_config { · 433 unmodified lines | ||
| 434 | 434 | bool EnableMinDispClkODM; |
| 435 | 435 | bool enable_auto_dpm_test_logs; |
| 436 | 436 | unsigned int disable_ips; |
| 437 | + unsigned int disable_ips_in_vpb; | |
| 437 | 438 | }; |
| 438 | 439 | |
| 439 | 440 | enum visual_confirm { |
| @@ -1034,6 +1034,7 @@ enum replay_FW_Message_type { · 1033 unmodified lines | ||
| 1034 | 1034 | Replay_Msg_Not_Support = -1, |
| 1035 | 1035 | Replay_Set_Timing_Sync_Supported, |
| 1036 | 1036 | Replay_Set_Residency_Frameupdate_Timer, |
| 1037 | + Replay_Set_Pseudo_VTotal, | |
| 1037 | 1038 | }; |
| 1038 | 1039 | |
| 1039 | 1040 | union replay_error_status { |
| @@ -1089,6 +1090,10 @@ struct replay_settings { · 49 unmodified lines | ||
| 1089 | 1090 | uint16_t coasting_vtotal_table[PR_COASTING_TYPE_NUM]; |
| 1090 | 1091 | /* Maximum link off frame count */ |
| 1091 | 1092 | enum replay_link_off_frame_count_level link_off_frame_count_level; |
| 1093 | + /* Replay pseudo vtotal for abm + ips on full screen video which can improve ips residency */ | |
| 1094 | + uint16_t abm_with_ips_on_full_screen_video_pseudo_vtotal; | |
| 1095 | + /* Replay last pseudo vtotal set to DMUB */ | |
| 1096 | + uint16_t last_pseudo_vtotal; | |
| 1092 | 1097 | }; |
| 1093 | 1098 | |
| 1094 | 1099 | /* To split out "global" and "per-panel" config settings. |
| @@ -680,7 +680,7 @@ void dcn35_power_down_on_boot(struct dc *dc) · 679 unmodified lines | ||
| 680 | 680 | bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable) |
| 681 | 681 | { |
| 682 | 682 | struct dc_link *edp_links[MAX_NUM_EDP]; |
| 683 | − int edp_num; | |
| 683 | + int i, edp_num; | |
| 684 | 684 | if (dc->debug.dmcub_emulation) |
| 685 | 685 | return true; |
| 686 | 686 | |
| @@ -688,6 +688,13 @@ bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable) · 1 unmodified line | ||
| 688 | 688 | dc_get_edp_links(dc, edp_links, &edp_num); |
| 689 | 689 | if (edp_num == 0 || edp_num > 1) |
| 690 | 690 | return false; |
| 691 | + | |
| 692 | + for (i = 0; i < dc->current_state->stream_count; ++i) { | |
| 693 | + struct dc_stream_state *stream = dc->current_state->streams[i]; | |
| 694 | + | |
| 695 | + if (!stream->dpms_off && !dc_is_embedded_signal(stream->signal)) | |
| 696 | + return false; | |
| 697 | + } | |
| 691 | 698 | } |
| 692 | 699 | |
| 693 | 700 | // TODO: review other cases when idle optimization is allowed |
| @@ -205,7 +205,7 @@ enum dc_status core_link_read_dpcd( · 204 unmodified lines | ||
| 205 | 205 | uint32_t extended_size; |
| 206 | 206 | /* size of the remaining partitioned address space */ |
| 207 | 207 | uint32_t size_left_to_read; |
| 208 | − enum dc_status status; | |
| 208 | + enum dc_status status = DC_ERROR_UNEXPECTED; | |
| 209 | 209 | /* size of the next partition to be read from */ |
| 210 | 210 | uint32_t partition_size; |
| 211 | 211 | uint32_t data_index = 0; |
| @@ -234,7 +234,7 @@ enum dc_status core_link_write_dpcd( · 22 unmodified lines | ||
| 234 | 234 | { |
| 235 | 235 | uint32_t partition_size; |
| 236 | 236 | uint32_t data_index = 0; |
| 237 | − enum dc_status status; | |
| 237 | + enum dc_status status = DC_ERROR_UNEXPECTED; | |
| 238 | 238 | |
| 239 | 239 | while (size) { |
| 240 | 240 | partition_size = dpcd_get_next_partition_size(address, size); |
| @@ -2832,6 +2832,7 @@ struct dmub_rb_cmd_psr_set_power_opt { · 2831 unmodified lines | ||
| 2832 | 2832 | #define REPLAY_RESIDENCY_MODE_MASK (0x1 << REPLAY_RESIDENCY_MODE_SHIFT) |
| 2833 | 2833 | # define REPLAY_RESIDENCY_MODE_PHY (0x0 << REPLAY_RESIDENCY_MODE_SHIFT) |
| 2834 | 2834 | # define REPLAY_RESIDENCY_MODE_ALPM (0x1 << REPLAY_RESIDENCY_MODE_SHIFT) |
| 2835 | +# define REPLAY_RESIDENCY_MODE_IPS 0x10 | |
| 2835 | 2836 | |
| 2836 | 2837 | #define REPLAY_RESIDENCY_ENABLE_MASK (0x1 << REPLAY_RESIDENCY_ENABLE_SHIFT) |
| 2837 | 2838 | # define REPLAY_RESIDENCY_DISABLE (0x0 << REPLAY_RESIDENCY_ENABLE_SHIFT) |
| @@ -2894,6 +2895,10 @@ enum dmub_cmd_replay_type { · 56 unmodified lines | ||
| 2894 | 2895 | * Set Residency Frameupdate Timer. |
| 2895 | 2896 | */ |
| 2896 | 2897 | DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER = 6, |
| 2898 | + /** | |
| 2899 | + * Set pseudo vtotal | |
| 2900 | + */ | |
| 2901 | + DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL = 7, | |
| 2897 | 2902 | }; |
| 2898 | 2903 | |
| 2899 | 2904 | /** |
| @@ -3076,6 +3081,26 @@ struct dmub_cmd_replay_set_timing_sync_data { · 176 unmodified lines | ||
| 3076 | 3081 | uint8_t pad[2]; |
| 3077 | 3082 | }; |
| 3078 | 3083 | |
| 3084 | +/** | |
| 3085 | + * Data passed from driver to FW in a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command. | |
| 3086 | + */ | |
| 3087 | +struct dmub_cmd_replay_set_pseudo_vtotal { | |
| 3088 | + /** | |
| 3089 | + * Panel Instance. | |
| 3090 | + * Panel isntance to identify which replay_state to use | |
| 3091 | + * Currently the support is only for 0 or 1 | |
| 3092 | + */ | |
| 3093 | + uint8_t panel_inst; | |
| 3094 | + /** | |
| 3095 | + * Source Vtotal that Replay + IPS + ABM full screen video src vtotal | |
| 3096 | + */ | |
| 3097 | + uint16_t vtotal; | |
| 3098 | + /** | |
| 3099 | + * Explicit padding to 4 byte boundary. | |
| 3100 | + */ | |
| 3101 | + uint8_t pad; | |
| 3102 | +}; | |
| 3103 | + | |
| 3079 | 3104 | /** |
| 3080 | 3105 | * Definition of a DMUB_CMD__SET_REPLAY_POWER_OPT command. |
| 3081 | 3106 | */ |
| @@ -3156,6 +3181,20 @@ struct dmub_rb_cmd_replay_set_timing_sync { · 74 unmodified lines | ||
| 3156 | 3181 | struct dmub_cmd_replay_set_timing_sync_data replay_set_timing_sync_data; |
| 3157 | 3182 | }; |
| 3158 | 3183 | |
| 3184 | +/** | |
| 3185 | + * Definition of a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command. | |
| 3186 | + */ | |
| 3187 | +struct dmub_rb_cmd_replay_set_pseudo_vtotal { | |
| 3188 | + /** | |
| 3189 | + * Command header. | |
| 3190 | + */ | |
| 3191 | + struct dmub_cmd_header header; | |
| 3192 | + /** | |
| 3193 | + * Definition of DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command. | |
| 3194 | + */ | |
| 3195 | + struct dmub_cmd_replay_set_pseudo_vtotal data; | |
| 3196 | +}; | |
| 3197 | + | |
| 3159 | 3198 | /** |
| 3160 | 3199 | * Data passed from driver to FW in DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command. |
| 3161 | 3200 | */ |
| @@ -3207,6 +3246,10 @@ union dmub_replay_cmd_set { · 45 unmodified lines | ||
| 3207 | 3246 | * Definition of DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command data. |
| 3208 | 3247 | */ |
| 3209 | 3248 | struct dmub_cmd_replay_frameupdate_timer_data timer_data; |
| 3249 | + /** | |
| 3250 | + * Definition of DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command data. | |
| 3251 | + */ | |
| 3252 | + struct dmub_cmd_replay_set_pseudo_vtotal pseudo_vtotal_data; | |
| 3210 | 3253 | }; |
| 3211 | 3254 | |
| 3212 | 3255 | /** |
| @@ -4358,6 +4401,10 @@ union dmub_rb_cmd { · 1145 unmodified lines | ||
| 4358 | 4401 | * Definition of a DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command. |
| 4359 | 4402 | */ |
| 4360 | 4403 | struct dmub_rb_cmd_replay_set_frameupdate_timer replay_set_frameupdate_timer; |
| 4404 | + /** | |
| 4405 | + * Definition of a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command. | |
| 4406 | + */ | |
| 4407 | + struct dmub_rb_cmd_replay_set_pseudo_vtotal replay_set_pseudo_vtotal; | |
| 4361 | 4408 | }; |
| 4362 | 4409 | |
| 4363 | 4410 | /** |
| @@ -980,6 +980,11 @@ void set_replay_coasting_vtotal(struct dc_link *link, · 979 unmodified lines | ||
| 980 | 980 | link->replay_settings.coasting_vtotal_table[type] = vtotal; |
| 981 | 981 | } |
| 982 | 982 | |
| 983 | +void set_replay_ips_full_screen_video_src_vtotal(struct dc_link *link, uint16_t vtotal) | |
| 984 | +{ | |
| 985 | + link->replay_settings.abm_with_ips_on_full_screen_video_pseudo_vtotal = vtotal; | |
| 986 | +} | |
| 987 | + | |
| 983 | 988 | void calculate_replay_link_off_frame_count(struct dc_link *link, |
| 984 | 989 | uint16_t vtotal, uint16_t htotal) |
| 985 | 990 | { |
| @@ -57,6 +57,7 @@ void init_replay_config(struct dc_link *link, struct replay_config *pr_config); · 56 unmodified lines | ||
| 57 | 57 | void set_replay_coasting_vtotal(struct dc_link *link, |
| 58 | 58 | enum replay_coasting_vtotal_type type, |
| 59 | 59 | uint16_t vtotal); |
| 60 | +void set_replay_ips_full_screen_video_src_vtotal(struct dc_link *link, uint16_t vtotal); | |
| 60 | 61 | void calculate_replay_link_off_frame_count(struct dc_link *link, |
| 61 | 62 | uint16_t vtotal, uint16_t htotal); |
| 62 | 63 | |
| @@ -258,6 +258,7 @@ enum DC_DEBUG_MASK { · 257 unmodified lines | ||
| 258 | 258 | DC_ENABLE_DML2 = 0x100, |
| 259 | 259 | DC_DISABLE_PSR_SU = 0x200, |
| 260 | 260 | DC_DISABLE_REPLAY = 0x400, |
| 261 | + DC_DISABLE_IPS = 0x800, | |
| 261 | 262 | }; |
| 262 | 263 | |
| 263 | 264 | enum amd_dpm_forced_level; |
| @@ -138,7 +138,7 @@ static inline size_t amdgpu_reginst_size(uint16_t num_inst, size_t inst_size, · 137 unmodified lines | ||
| 138 | 138 | } |
| 139 | 139 | |
| 140 | 140 | #define amdgpu_asic_get_reg_state_supported(adev) \ |
| 141 | − ((adev)->asic_funcs->get_reg_state ? 1 : 0) | |
| 141 | + (((adev)->asic_funcs && (adev)->asic_funcs->get_reg_state) ? 1 : 0) | |
| 142 | 142 | |
| 143 | 143 | #define amdgpu_asic_get_reg_state(adev, state, buf, size) \ |
| 144 | 144 | ((adev)->asic_funcs->get_reg_state ? \ |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | |
| 25 | 25 | #include <linux/firmware.h> |
| 26 | 26 | #include <linux/pci.h> |
| 27 | +#include <linux/power_supply.h> | |
| 27 | 28 | #include <linux/reboot.h> |
| 28 | 29 | |
| 29 | 30 | #include "amdgpu.h" |
| @@ -817,16 +818,8 @@ static int smu_late_init(void *handle) · 787 unmodified lines | ||
| 817 | 818 | * handle the switch automatically. Driver involvement |
| 818 | 819 | * is unnecessary. |
| 819 | 820 | */ |
| 820 | − if (!smu->dc_controlled_by_gpio) { | |
| 821 | − ret = smu_set_power_source(smu, | |
| 822 | − adev->pm.ac_power ? SMU_POWER_SOURCE_AC : | |
| 823 | − SMU_POWER_SOURCE_DC); | |
| 824 | − if (ret) { | |
| 825 | − dev_err(adev->dev, "Failed to switch to %s mode!\n", | |
| 826 | − adev->pm.ac_power ? "AC" : "DC"); | |
| 827 | − return ret; | |
| 828 | − } | |
| 829 | − } | |
| 821 | + adev->pm.ac_power = power_supply_is_system_supplied() > 0; | |
| 822 | + smu_set_ac_dc(smu); | |
| 830 | 823 | |
| 831 | 824 | if ((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 1)) || |
| 832 | 825 | (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 3))) |
| @@ -2710,6 +2703,7 @@ int smu_get_power_limit(void *handle, · 1877 unmodified lines | ||
| 2710 | 2703 | case SMU_PPT_LIMIT_CURRENT: |
| 2711 | 2704 | switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { |
| 2712 | 2705 | case IP_VERSION(13, 0, 2): |
| 2706 | + case IP_VERSION(13, 0, 6): | |
| 2713 | 2707 | case IP_VERSION(11, 0, 7): |
| 2714 | 2708 | case IP_VERSION(11, 0, 11): |
| 2715 | 2709 | case IP_VERSION(11, 0, 12): |
| @@ -1442,10 +1442,12 @@ static int smu_v11_0_irq_process(struct amdgpu_device *adev, · 1441 unmodified lines | ||
| 1442 | 1442 | case 0x3: |
| 1443 | 1443 | dev_dbg(adev->dev, "Switched to AC mode!\n"); |
| 1444 | 1444 | schedule_work(&smu->interrupt_work); |
| 1445 | + adev->pm.ac_power = true; | |
| 1445 | 1446 | break; |
| 1446 | 1447 | case 0x4: |
| 1447 | 1448 | dev_dbg(adev->dev, "Switched to DC mode!\n"); |
| 1448 | 1449 | schedule_work(&smu->interrupt_work); |
| 1450 | + adev->pm.ac_power = false; | |
| 1449 | 1451 | break; |
| 1450 | 1452 | case 0x7: |
| 1451 | 1453 | /* |
| @@ -1379,10 +1379,12 @@ static int smu_v13_0_irq_process(struct amdgpu_device *adev, · 1378 unmodified lines | ||
| 1379 | 1379 | case 0x3: |
| 1380 | 1380 | dev_dbg(adev->dev, "Switched to AC mode!\n"); |
| 1381 | 1381 | smu_v13_0_ack_ac_dc_interrupt(smu); |
| 1382 | + adev->pm.ac_power = true; | |
| 1382 | 1383 | break; |
| 1383 | 1384 | case 0x4: |
| 1384 | 1385 | dev_dbg(adev->dev, "Switched to DC mode!\n"); |
| 1385 | 1386 | smu_v13_0_ack_ac_dc_interrupt(smu); |
| 1387 | + adev->pm.ac_power = false; | |
| 1386 | 1388 | break; |
| 1387 | 1389 | case 0x7: |
| 1388 | 1390 | /* |
| @@ -2357,6 +2357,7 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu, · 2356 unmodified lines | ||
| 2357 | 2357 | PPTable_t *pptable = table_context->driver_pptable; |
| 2358 | 2358 | SkuTable_t *skutable = &pptable->SkuTable; |
| 2359 | 2359 | uint32_t power_limit, od_percent_upper, od_percent_lower; |
| 2360 | + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; | |
| 2360 | 2361 | |
| 2361 | 2362 | if (smu_v13_0_get_current_power_limit(smu, &power_limit)) |
| 2362 | 2363 | power_limit = smu->adev->pm.ac_power ? |
| @@ -2380,7 +2381,7 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu, · 17 unmodified lines | ||
| 2380 | 2381 | od_percent_upper, od_percent_lower, power_limit); |
| 2381 | 2382 | |
| 2382 | 2383 | if (max_power_limit) { |
| 2383 | − *max_power_limit = power_limit * (100 + od_percent_upper); | |
| 2384 | + *max_power_limit = msg_limit * (100 + od_percent_upper); | |
| 2384 | 2385 | *max_power_limit /= 100; |
| 2385 | 2386 | } |
| 2386 | 2387 | |
| @@ -2959,6 +2960,55 @@ static bool smu_v13_0_0_wbrf_support_check(struct smu_context *smu) · 572 unmodified lines | ||
| 2959 | 2960 | } |
| 2960 | 2961 | } |
| 2961 | 2962 | |
| 2963 | +static int smu_v13_0_0_set_power_limit(struct smu_context *smu, | |
| 2964 | + enum smu_ppt_limit_type limit_type, | |
| 2965 | + uint32_t limit) | |
| 2966 | +{ | |
| 2967 | + PPTable_t *pptable = smu->smu_table.driver_pptable; | |
| 2968 | + SkuTable_t *skutable = &pptable->SkuTable; | |
| 2969 | + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; | |
| 2970 | + struct smu_table_context *table_context = &smu->smu_table; | |
| 2971 | + OverDriveTableExternal_t *od_table = | |
| 2972 | + (OverDriveTableExternal_t *)table_context->overdrive_table; | |
| 2973 | + int ret = 0; | |
| 2974 | + | |
| 2975 | + if (limit_type != SMU_DEFAULT_PPT_LIMIT) | |
| 2976 | + return -EINVAL; | |
| 2977 | + | |
| 2978 | + if (limit <= msg_limit) { | |
| 2979 | + if (smu->current_power_limit > msg_limit) { | |
| 2980 | + od_table->OverDriveTable.Ppt = 0; | |
| 2981 | + od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT; | |
| 2982 | + | |
| 2983 | + ret = smu_v13_0_0_upload_overdrive_table(smu, od_table); | |
| 2984 | + if (ret) { | |
| 2985 | + dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); | |
| 2986 | + return ret; | |
| 2987 | + } | |
| 2988 | + } | |
| 2989 | + return smu_v13_0_set_power_limit(smu, limit_type, limit); | |
| 2990 | + } else if (smu->od_enabled) { | |
| 2991 | + ret = smu_v13_0_set_power_limit(smu, limit_type, msg_limit); | |
| 2992 | + if (ret) | |
| 2993 | + return ret; | |
| 2994 | + | |
| 2995 | + od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100; | |
| 2996 | + od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT; | |
| 2997 | + | |
| 2998 | + ret = smu_v13_0_0_upload_overdrive_table(smu, od_table); | |
| 2999 | + if (ret) { | |
| 3000 | + dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); | |
| 3001 | + return ret; | |
| 3002 | + } | |
| 3003 | + | |
| 3004 | + smu->current_power_limit = limit; | |
| 3005 | + } else { | |
| 3006 | + return -EINVAL; | |
| 3007 | + } | |
| 3008 | + | |
| 3009 | + return 0; | |
| 3010 | +} | |
| 3011 | + | |
| 2962 | 3012 | static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { |
| 2963 | 3013 | .get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask, |
| 2964 | 3014 | .set_default_dpm_table = smu_v13_0_0_set_default_dpm_table, |
| @@ -3013,7 +3063,7 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { · 48 unmodified lines | ||
| 3013 | 3063 | .set_fan_control_mode = smu_v13_0_set_fan_control_mode, |
| 3014 | 3064 | .enable_mgpu_fan_boost = smu_v13_0_0_enable_mgpu_fan_boost, |
| 3015 | 3065 | .get_power_limit = smu_v13_0_0_get_power_limit, |
| 3016 | − .set_power_limit = smu_v13_0_set_power_limit, | |
| 3066 | + .set_power_limit = smu_v13_0_0_set_power_limit, | |
| 3017 | 3067 | .set_power_source = smu_v13_0_set_power_source, |
| 3018 | 3068 | .get_power_profile_mode = smu_v13_0_0_get_power_profile_mode, |
| 3019 | 3069 | .set_power_profile_mode = smu_v13_0_0_set_power_profile_mode, |
| @@ -160,8 +160,8 @@ static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COU · 159 unmodified lines | ||
| 160 | 160 | MSG_MAP(GfxDriverResetRecovery, PPSMC_MSG_GfxDriverResetRecovery, 0), |
| 161 | 161 | MSG_MAP(GetMinGfxclkFrequency, PPSMC_MSG_GetMinGfxDpmFreq, 1), |
| 162 | 162 | MSG_MAP(GetMaxGfxclkFrequency, PPSMC_MSG_GetMaxGfxDpmFreq, 1), |
| 163 | − MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxClk, 0), | |
| 164 | − MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 0), | |
| 163 | + MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxClk, 1), | |
| 164 | + MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1), | |
| 165 | 165 | MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareForDriverUnload, 0), |
| 166 | 166 | MSG_MAP(GetCTFLimit, PPSMC_MSG_GetCTFLimit, 0), |
| 167 | 167 | MSG_MAP(GetThermalLimit, PPSMC_MSG_ReadThrottlerLimit, 0), |
| @@ -2321,6 +2321,7 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu, · 2320 unmodified lines | ||
| 2321 | 2321 | PPTable_t *pptable = table_context->driver_pptable; |
| 2322 | 2322 | SkuTable_t *skutable = &pptable->SkuTable; |
| 2323 | 2323 | uint32_t power_limit, od_percent_upper, od_percent_lower; |
| 2324 | + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; | |
| 2324 | 2325 | |
| 2325 | 2326 | if (smu_v13_0_get_current_power_limit(smu, &power_limit)) |
| 2326 | 2327 | power_limit = smu->adev->pm.ac_power ? |
| @@ -2344,7 +2345,7 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu, · 17 unmodified lines | ||
| 2344 | 2345 | od_percent_upper, od_percent_lower, power_limit); |
| 2345 | 2346 | |
| 2346 | 2347 | if (max_power_limit) { |
| 2347 | − *max_power_limit = power_limit * (100 + od_percent_upper); | |
| 2348 | + *max_power_limit = msg_limit * (100 + od_percent_upper); | |
| 2348 | 2349 | *max_power_limit /= 100; |
| 2349 | 2350 | } |
| 2350 | 2351 | |
| @@ -2545,6 +2546,55 @@ static bool smu_v13_0_7_wbrf_support_check(struct smu_context *smu) · 194 unmodified lines | ||
| 2545 | 2546 | return smu->smc_fw_version > 0x00524600; |
| 2546 | 2547 | } |
| 2547 | 2548 | |
| 2549 | +static int smu_v13_0_7_set_power_limit(struct smu_context *smu, | |
| 2550 | + enum smu_ppt_limit_type limit_type, | |
| 2551 | + uint32_t limit) | |
| 2552 | +{ | |
| 2553 | + PPTable_t *pptable = smu->smu_table.driver_pptable; | |
| 2554 | + SkuTable_t *skutable = &pptable->SkuTable; | |
| 2555 | + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; | |
| 2556 | + struct smu_table_context *table_context = &smu->smu_table; | |
| 2557 | + OverDriveTableExternal_t *od_table = | |
| 2558 | + (OverDriveTableExternal_t *)table_context->overdrive_table; | |
| 2559 | + int ret = 0; | |
| 2560 | + | |
| 2561 | + if (limit_type != SMU_DEFAULT_PPT_LIMIT) | |
| 2562 | + return -EINVAL; | |
| 2563 | + | |
| 2564 | + if (limit <= msg_limit) { | |
| 2565 | + if (smu->current_power_limit > msg_limit) { | |
| 2566 | + od_table->OverDriveTable.Ppt = 0; | |
| 2567 | + od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT; | |
| 2568 | + | |
| 2569 | + ret = smu_v13_0_7_upload_overdrive_table(smu, od_table); | |
| 2570 | + if (ret) { | |
| 2571 | + dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); | |
| 2572 | + return ret; | |
| 2573 | + } | |
| 2574 | + } | |
| 2575 | + return smu_v13_0_set_power_limit(smu, limit_type, limit); | |
| 2576 | + } else if (smu->od_enabled) { | |
| 2577 | + ret = smu_v13_0_set_power_limit(smu, limit_type, msg_limit); | |
| 2578 | + if (ret) | |
| 2579 | + return ret; | |
| 2580 | + | |
| 2581 | + od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100; | |
| 2582 | + od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT; | |
| 2583 | + | |
| 2584 | + ret = smu_v13_0_7_upload_overdrive_table(smu, od_table); | |
| 2585 | + if (ret) { | |
| 2586 | + dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); | |
| 2587 | + return ret; | |
| 2588 | + } | |
| 2589 | + | |
| 2590 | + smu->current_power_limit = limit; | |
| 2591 | + } else { | |
| 2592 | + return -EINVAL; | |
| 2593 | + } | |
| 2594 | + | |
| 2595 | + return 0; | |
| 2596 | +} | |
| 2597 | + | |
| 2548 | 2598 | static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { |
| 2549 | 2599 | .get_allowed_feature_mask = smu_v13_0_7_get_allowed_feature_mask, |
| 2550 | 2600 | .set_default_dpm_table = smu_v13_0_7_set_default_dpm_table, |
| @@ -2596,7 +2646,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { · 45 unmodified lines | ||
| 2596 | 2646 | .set_fan_control_mode = smu_v13_0_set_fan_control_mode, |
| 2597 | 2647 | .enable_mgpu_fan_boost = smu_v13_0_7_enable_mgpu_fan_boost, |
| 2598 | 2648 | .get_power_limit = smu_v13_0_7_get_power_limit, |
| 2599 | − .set_power_limit = smu_v13_0_set_power_limit, | |
| 2649 | + .set_power_limit = smu_v13_0_7_set_power_limit, | |
| 2600 | 2650 | .set_power_source = smu_v13_0_set_power_source, |
| 2601 | 2651 | .get_power_profile_mode = smu_v13_0_7_get_power_profile_mode, |
| 2602 | 2652 | .set_power_profile_mode = smu_v13_0_7_set_power_profile_mode, |
| @@ -1762,6 +1762,7 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux, · 1761 unmodified lines | ||
| 1762 | 1762 | u8 request = msg->request & ~DP_AUX_I2C_MOT; |
| 1763 | 1763 | int ret = 0; |
| 1764 | 1764 | |
| 1765 | + mutex_lock(&ctx->aux_lock); | |
| 1765 | 1766 | pm_runtime_get_sync(dev); |
| 1766 | 1767 | msg->reply = 0; |
| 1767 | 1768 | switch (request) { |
| @@ -1778,6 +1779,7 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux, · 10 unmodified lines | ||
| 1778 | 1779 | msg->size, msg->buffer); |
| 1779 | 1780 | pm_runtime_mark_last_busy(dev); |
| 1780 | 1781 | pm_runtime_put_autosuspend(dev); |
| 1782 | + mutex_unlock(&ctx->aux_lock); | |
| 1781 | 1783 | |
| 1782 | 1784 | return ret; |
| 1783 | 1785 | } |
| @@ -2474,7 +2476,9 @@ static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge, · 690 unmodified lines | ||
| 2474 | 2476 | ctx->connector = NULL; |
| 2475 | 2477 | anx7625_dp_stop(ctx); |
| 2476 | 2478 | |
| 2477 | − pm_runtime_put_sync(dev); | |
| 2479 | + mutex_lock(&ctx->aux_lock); | |
| 2480 | + pm_runtime_put_sync_suspend(dev); | |
| 2481 | + mutex_unlock(&ctx->aux_lock); | |
| 2478 | 2482 | } |
| 2479 | 2483 | |
| 2480 | 2484 | static enum drm_connector_status |
| @@ -2668,6 +2672,7 @@ static int anx7625_i2c_probe(struct i2c_client *client) · 187 unmodified lines | ||
| 2668 | 2672 | |
| 2669 | 2673 | mutex_init(&platform->lock); |
| 2670 | 2674 | mutex_init(&platform->hdcp_wq_lock); |
| 2675 | + mutex_init(&platform->aux_lock); | |
| 2671 | 2676 | |
| 2672 | 2677 | INIT_DELAYED_WORK(&platform->hdcp_work, hdcp_check_work_func); |
| 2673 | 2678 | platform->hdcp_workqueue = create_workqueue("hdcp workqueue"); |
| @@ -475,6 +475,8 @@ struct anx7625_data { · 474 unmodified lines | ||
| 475 | 475 | struct workqueue_struct *hdcp_workqueue; |
| 476 | 476 | /* Lock for hdcp work queue */ |
| 477 | 477 | struct mutex hdcp_wq_lock; |
| 478 | + /* Lock for aux transfer and disable */ | |
| 479 | + struct mutex aux_lock; | |
| 478 | 480 | char edid_block; |
| 479 | 481 | struct display_timing dt; |
| 480 | 482 | u8 display_timing_valid; |
| @@ -107,6 +107,7 @@ struct ps8640 { · 106 unmodified lines | ||
| 107 | 107 | struct device_link *link; |
| 108 | 108 | bool pre_enabled; |
| 109 | 109 | bool need_post_hpd_delay; |
| 110 | + struct mutex aux_lock; | |
| 110 | 111 | }; |
| 111 | 112 | |
| 112 | 113 | static const struct regmap_config ps8640_regmap_config[] = { |
| @@ -345,11 +346,20 @@ static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux, · 232 unmodified lines | ||
| 345 | 346 | struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev; |
| 346 | 347 | int ret; |
| 347 | 348 | |
| 349 | + mutex_lock(&ps_bridge->aux_lock); | |
| 348 | 350 | pm_runtime_get_sync(dev); |
| 351 | + ret = _ps8640_wait_hpd_asserted(ps_bridge, 200 * 1000); | |
| 352 | + if (ret) { | |
| 353 | + pm_runtime_put_sync_suspend(dev); | |
| 354 | + goto exit; | |
| 355 | + } | |
| 349 | 356 | ret = ps8640_aux_transfer_msg(aux, msg); |
| 350 | 357 | pm_runtime_mark_last_busy(dev); |
| 351 | 358 | pm_runtime_put_autosuspend(dev); |
| 352 | 359 | |
| 360 | +exit: | |
| 361 | + mutex_unlock(&ps_bridge->aux_lock); | |
| 362 | + | |
| 353 | 363 | return ret; |
| 354 | 364 | } |
| 355 | 365 | |
| @@ -470,7 +480,18 @@ static void ps8640_atomic_post_disable(struct drm_bridge *bridge, · 114 unmodified lines | ||
| 470 | 480 | ps_bridge->pre_enabled = false; |
| 471 | 481 | |
| 472 | 482 | ps8640_bridge_vdo_control(ps_bridge, DISABLE); |
| 483 | + | |
| 484 | + /* | |
| 485 | + * The bridge seems to expect everything to be power cycled at the | |
| 486 | + * disable process, so grab a lock here to make sure | |
| 487 | + * ps8640_aux_transfer() is not holding a runtime PM reference and | |
| 488 | + * preventing the bridge from suspend. | |
| 489 | + */ | |
| 490 | + mutex_lock(&ps_bridge->aux_lock); | |
| 491 | + | |
| 473 | 492 | pm_runtime_put_sync_suspend(&ps_bridge->page[PAGE0_DP_CNTL]->dev); |
| 493 | + | |
| 494 | + mutex_unlock(&ps_bridge->aux_lock); | |
| 474 | 495 | } |
| 475 | 496 | |
| 476 | 497 | static int ps8640_bridge_attach(struct drm_bridge *bridge, |
| @@ -619,6 +640,8 @@ static int ps8640_probe(struct i2c_client *client) · 142 unmodified lines | ||
| 619 | 640 | if (!ps_bridge) |
| 620 | 641 | return -ENOMEM; |
| 621 | 642 | |
| 643 | + mutex_init(&ps_bridge->aux_lock); | |
| 644 | + | |
| 622 | 645 | ps_bridge->supplies[0].supply = "vdd12"; |
| 623 | 646 | ps_bridge->supplies[1].supply = "vdd33"; |
| 624 | 647 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies), |
| @@ -969,10 +969,6 @@ static int samsung_dsim_init_link(struct samsung_dsim *dsi) · 968 unmodified lines | ||
| 969 | 969 | reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); |
| 970 | 970 | reg &= ~DSIM_STOP_STATE_CNT_MASK; |
| 971 | 971 | reg |= DSIM_STOP_STATE_CNT(driver_data->reg_values[STOP_STATE_CNT]); |
| 972 | − | |
| 973 | − if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) | |
| 974 | − reg |= DSIM_FORCE_STOP_STATE; | |
| 975 | − | |
| 976 | 972 | samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); |
| 977 | 973 | |
| 978 | 974 | reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff); |
| @@ -1431,18 +1427,6 @@ static void samsung_dsim_disable_irq(struct samsung_dsim *dsi) · 452 unmodified lines | ||
| 1431 | 1427 | disable_irq(dsi->irq); |
| 1432 | 1428 | } |
| 1433 | 1429 | |
| 1434 | −static void samsung_dsim_set_stop_state(struct samsung_dsim *dsi, bool enable) | |
| 1435 | −{ | |
| 1436 | − u32 reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); | |
| 1437 | − | |
| 1438 | − if (enable) | |
| 1439 | − reg |= DSIM_FORCE_STOP_STATE; | |
| 1440 | − else | |
| 1441 | − reg &= ~DSIM_FORCE_STOP_STATE; | |
| 1442 | − | |
| 1443 | − samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); | |
| 1444 | −} | |
| 1445 | − | |
| 1446 | 1430 | static int samsung_dsim_init(struct samsung_dsim *dsi) |
| 1447 | 1431 | { |
| 1448 | 1432 | const struct samsung_dsim_driver_data *driver_data = dsi->driver_data; |
| @@ -1492,9 +1476,6 @@ static void samsung_dsim_atomic_pre_enable(struct drm_bridge *bridge, · 43 unmodified lines | ||
| 1492 | 1476 | ret = samsung_dsim_init(dsi); |
| 1493 | 1477 | if (ret) |
| 1494 | 1478 | return; |
| 1495 | − | |
| 1496 | − samsung_dsim_set_display_mode(dsi); | |
| 1497 | − samsung_dsim_set_display_enable(dsi, true); | |
| 1498 | 1479 | } |
| 1499 | 1480 | } |
| 1500 | 1481 | |
| @@ -1503,12 +1484,8 @@ static void samsung_dsim_atomic_enable(struct drm_bridge *bridge, · 2 unmodified lines | ||
| 1503 | 1484 | { |
| 1504 | 1485 | struct samsung_dsim *dsi = bridge_to_dsi(bridge); |
| 1505 | 1486 | |
| 1506 | − if (samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) { | |
| 1507 | − samsung_dsim_set_display_mode(dsi); | |
| 1508 | − samsung_dsim_set_display_enable(dsi, true); | |
| 1509 | − } else { | |
| 1510 | − samsung_dsim_set_stop_state(dsi, false); | |
| 1511 | − } | |
| 1487 | + samsung_dsim_set_display_mode(dsi); | |
| 1488 | + samsung_dsim_set_display_enable(dsi, true); | |
| 1512 | 1489 | |
| 1513 | 1490 | dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; |
| 1514 | 1491 | } |
| @@ -1521,9 +1498,6 @@ static void samsung_dsim_atomic_disable(struct drm_bridge *bridge, · 6 unmodified lines | ||
| 1521 | 1498 | if (!(dsi->state & DSIM_STATE_ENABLED)) |
| 1522 | 1499 | return; |
| 1523 | 1500 | |
| 1524 | − if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) | |
| 1525 | − samsung_dsim_set_stop_state(dsi, true); | |
| 1526 | − | |
| 1527 | 1501 | dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE; |
| 1528 | 1502 | } |
| 1529 | 1503 | |
| @@ -1828,8 +1802,6 @@ static ssize_t samsung_dsim_host_transfer(struct mipi_dsi_host *host, · 298 unmodified lines | ||
| 1828 | 1802 | if (ret) |
| 1829 | 1803 | return ret; |
| 1830 | 1804 | |
| 1831 | − samsung_dsim_set_stop_state(dsi, false); | |
| 1832 | − | |
| 1833 | 1805 | ret = mipi_dsi_create_packet(&xfer.packet, msg); |
| 1834 | 1806 | if (ret < 0) |
| 1835 | 1807 | return ret; |
| @@ -1080,6 +1080,26 @@ static int sii902x_init(struct sii902x *sii902x) · 1079 unmodified lines | ||
| 1080 | 1080 | return ret; |
| 1081 | 1081 | } |
| 1082 | 1082 | |
| 1083 | + ret = sii902x_audio_codec_init(sii902x, dev); | |
| 1084 | + if (ret) | |
| 1085 | + return ret; | |
| 1086 | + | |
| 1087 | + i2c_set_clientdata(sii902x->i2c, sii902x); | |
| 1088 | + | |
| 1089 | + sii902x->i2cmux = i2c_mux_alloc(sii902x->i2c->adapter, dev, | |
| 1090 | + 1, 0, I2C_MUX_GATE, | |
| 1091 | + sii902x_i2c_bypass_select, | |
| 1092 | + sii902x_i2c_bypass_deselect); | |
| 1093 | + if (!sii902x->i2cmux) { | |
| 1094 | + ret = -ENOMEM; | |
| 1095 | + goto err_unreg_audio; | |
| 1096 | + } | |
| 1097 | + | |
| 1098 | + sii902x->i2cmux->priv = sii902x; | |
| 1099 | + ret = i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); | |
| 1100 | + if (ret) | |
| 1101 | + goto err_unreg_audio; | |
| 1102 | + | |
| 1083 | 1103 | sii902x->bridge.funcs = &sii902x_bridge_funcs; |
| 1084 | 1104 | sii902x->bridge.of_node = dev->of_node; |
| 1085 | 1105 | sii902x->bridge.timings = &default_sii902x_timings; |
| @@ -1090,19 +1110,13 @@ static int sii902x_init(struct sii902x *sii902x) · 4 unmodified lines | ||
| 1090 | 1110 | |
| 1091 | 1111 | drm_bridge_add(&sii902x->bridge); |
| 1092 | 1112 | |
| 1093 | − sii902x_audio_codec_init(sii902x, dev); | |
| 1094 | − | |
| 1095 | − i2c_set_clientdata(sii902x->i2c, sii902x); | |
| 1113 | + return 0; | |
| 1096 | 1114 | |
| 1097 | − sii902x->i2cmux = i2c_mux_alloc(sii902x->i2c->adapter, dev, | |
| 1098 | − 1, 0, I2C_MUX_GATE, | |
| 1099 | − sii902x_i2c_bypass_select, | |
| 1100 | − sii902x_i2c_bypass_deselect); | |
| 1101 | − if (!sii902x->i2cmux) | |
| 1102 | − return -ENOMEM; | |
| 1115 | +err_unreg_audio: | |
| 1116 | + if (!PTR_ERR_OR_ZERO(sii902x->audio.pdev)) | |
| 1117 | + platform_device_unregister(sii902x->audio.pdev); | |
| 1103 | 1118 | |
| 1104 | − sii902x->i2cmux->priv = sii902x; | |
| 1105 | − return i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); | |
| 1119 | + return ret; | |
| 1106 | 1120 | } |
| 1107 | 1121 | |
| 1108 | 1122 | static int sii902x_probe(struct i2c_client *client) |
| @@ -1170,12 +1184,14 @@ static int sii902x_probe(struct i2c_client *client) · 61 unmodified lines | ||
| 1170 | 1184 | } |
| 1171 | 1185 | |
| 1172 | 1186 | static void sii902x_remove(struct i2c_client *client) |
| 1173 | − | |
| 1174 | 1187 | { |
| 1175 | 1188 | struct sii902x *sii902x = i2c_get_clientdata(client); |
| 1176 | 1189 | |
| 1177 | − i2c_mux_del_adapters(sii902x->i2cmux); | |
| 1178 | 1190 | drm_bridge_remove(&sii902x->bridge); |
| 1191 | + i2c_mux_del_adapters(sii902x->i2cmux); | |
| 1192 | + | |
| 1193 | + if (!PTR_ERR_OR_ZERO(sii902x->audio.pdev)) | |
| 1194 | + platform_device_unregister(sii902x->audio.pdev); | |
| 1179 | 1195 | } |
| 1180 | 1196 | |
| 1181 | 1197 | static const struct of_device_id sii902x_dt_ids[] = { |
| @@ -5491,6 +5491,7 @@ EXPORT_SYMBOL(drm_dp_mst_atomic_enable_dsc); · 5490 unmodified lines | ||
| 5491 | 5491 | * - 0 if the new state is valid |
| 5492 | 5492 | * - %-ENOSPC, if the new state is invalid, because of BW limitation |
| 5493 | 5493 | * @failing_port is set to: |
| 5494 | + * | |
| 5494 | 5495 | * - The non-root port where a BW limit check failed |
| 5495 | 5496 | * with all the ports downstream of @failing_port passing |
| 5496 | 5497 | * the BW limit check. |
| @@ -5499,6 +5500,7 @@ EXPORT_SYMBOL(drm_dp_mst_atomic_enable_dsc); · 2 unmodified lines | ||
| 5499 | 5500 | * - %NULL if the BW limit check failed at the root port |
| 5500 | 5501 | * with all the ports downstream of the root port passing |
| 5501 | 5502 | * the BW limit check. |
| 5503 | + * | |
| 5502 | 5504 | * - %-EINVAL, if the new state is invalid, because the root port has |
| 5503 | 5505 | * too many payloads. |
| 5504 | 5506 | */ |
| @@ -319,9 +319,9 @@ static void decon_win_set_bldmod(struct decon_context *ctx, unsigned int win, · 318 unmodified lines | ||
| 319 | 319 | static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, |
| 320 | 320 | struct drm_framebuffer *fb) |
| 321 | 321 | { |
| 322 | − struct exynos_drm_plane plane = ctx->planes[win]; | |
| 322 | + struct exynos_drm_plane *plane = &ctx->planes[win]; | |
| 323 | 323 | struct exynos_drm_plane_state *state = |
| 324 | − to_exynos_plane_state(plane.base.state); | |
| 324 | + to_exynos_plane_state(plane->base.state); | |
| 325 | 325 | unsigned int alpha = state->base.alpha; |
| 326 | 326 | unsigned int pixel_alpha; |
| 327 | 327 | unsigned long val; |
| @@ -480,7 +480,7 @@ static void fimd_commit(struct exynos_drm_crtc *crtc) · 479 unmodified lines | ||
| 480 | 480 | struct fimd_context *ctx = crtc->ctx; |
| 481 | 481 | struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; |
| 482 | 482 | const struct fimd_driver_data *driver_data = ctx->driver_data; |
| 483 | − void *timing_base = ctx->regs + driver_data->timing_base; | |
| 483 | + void __iomem *timing_base = ctx->regs + driver_data->timing_base; | |
| 484 | 484 | u32 val; |
| 485 | 485 | |
| 486 | 486 | if (ctx->suspended) |
| @@ -661,9 +661,9 @@ static void fimd_win_set_bldmod(struct fimd_context *ctx, unsigned int win, · 174 unmodified lines | ||
| 661 | 661 | static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win, |
| 662 | 662 | struct drm_framebuffer *fb, int width) |
| 663 | 663 | { |
| 664 | − struct exynos_drm_plane plane = ctx->planes[win]; | |
| 664 | + struct exynos_drm_plane *plane = &ctx->planes[win]; | |
| 665 | 665 | struct exynos_drm_plane_state *state = |
| 666 | − to_exynos_plane_state(plane.base.state); | |
| 666 | + to_exynos_plane_state(plane->base.state); | |
| 667 | 667 | uint32_t pixel_format = fb->format->format; |
| 668 | 668 | unsigned int alpha = state->base.alpha; |
| 669 | 669 | u32 val = WINCONx_ENWIN; |
| @@ -1341,7 +1341,7 @@ static int __maybe_unused gsc_runtime_resume(struct device *dev) · 1340 unmodified lines | ||
| 1341 | 1341 | for (i = 0; i < ctx->num_clocks; i++) { |
| 1342 | 1342 | ret = clk_prepare_enable(ctx->clocks[i]); |
| 1343 | 1343 | if (ret) { |
| 1344 | − while (--i > 0) | |
| 1344 | + while (--i >= 0) | |
| 1345 | 1345 | clk_disable_unprepare(ctx->clocks[i]); |
| 1346 | 1346 | return ret; |
| 1347 | 1347 | } |
| @@ -17,7 +17,6 @@ subdir-ccflags-y += $(call cc-option, -Wunused-const-variable) · 16 unmodified lines | ||
| 17 | 17 | subdir-ccflags-y += $(call cc-option, -Wpacked-not-aligned) |
| 18 | 18 | subdir-ccflags-y += $(call cc-option, -Wformat-overflow) |
| 19 | 19 | subdir-ccflags-y += $(call cc-option, -Wformat-truncation) |
| 20 | −subdir-ccflags-y += $(call cc-option, -Wstringop-overflow) | |
| 21 | 20 | subdir-ccflags-y += $(call cc-option, -Wstringop-truncation) |
| 22 | 21 | # The following turn off the warnings enabled by -Wextra |
| 23 | 22 | ifeq ($(findstring 2, $(KBUILD_EXTRA_WARN)),) |
| @@ -1155,6 +1155,7 @@ static void gen11_dsi_powerup_panel(struct intel_encoder *encoder) · 1154 unmodified lines | ||
| 1155 | 1155 | } |
| 1156 | 1156 | |
| 1157 | 1157 | intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP); |
| 1158 | + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); | |
| 1158 | 1159 | |
| 1159 | 1160 | /* ensure all panel commands dispatched before enabling transcoder */ |
| 1160 | 1161 | wait_for_cmds_dispatched_to_panel(encoder); |
| @@ -1255,8 +1256,6 @@ static void gen11_dsi_enable(struct intel_atomic_state *state, · 94 unmodified lines | ||
| 1255 | 1256 | /* step6d: enable dsi transcoder */ |
| 1256 | 1257 | gen11_dsi_enable_transcoder(encoder); |
| 1257 | 1258 | |
| 1258 | − intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); | |
| 1259 | − | |
| 1260 | 1259 | /* step7: enable backlight */ |
| 1261 | 1260 | intel_backlight_enable(crtc_state, conn_state); |
| 1262 | 1261 | intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON); |
| @@ -1525,8 +1525,18 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, · 1524 unmodified lines | ||
| 1525 | 1525 | * can rely on frontbuffer tracking. |
| 1526 | 1526 | */ |
| 1527 | 1527 | mask = EDP_PSR_DEBUG_MASK_MEMUP | |
| 1528 | − EDP_PSR_DEBUG_MASK_HPD | | |
| 1529 | − EDP_PSR_DEBUG_MASK_LPSP; | |
| 1528 | + EDP_PSR_DEBUG_MASK_HPD; | |
| 1529 | + | |
| 1530 | + /* | |
| 1531 | + * For some unknown reason on HSW non-ULT (or at least on | |
| 1532 | + * Dell Latitude E6540) external displays start to flicker | |
| 1533 | + * when PSR is enabled on the eDP. SR/PC6 residency is much | |
| 1534 | + * higher than should be possible with an external display. | |
| 1535 | + * As a workaround leave LPSP unmasked to prevent PSR entry | |
| 1536 | + * when external displays are active. | |
| 1537 | + */ | |
| 1538 | + if (DISPLAY_VER(dev_priv) >= 8 || IS_HASWELL_ULT(dev_priv)) | |
| 1539 | + mask |= EDP_PSR_DEBUG_MASK_LPSP; | |
| 1530 | 1540 | |
| 1531 | 1541 | if (DISPLAY_VER(dev_priv) < 20) |
| 1532 | 1542 | mask |= EDP_PSR_DEBUG_MASK_MAX_SLEEP; |
| @@ -62,7 +62,7 @@ nouveau_fence_signal(struct nouveau_fence *fence) · 61 unmodified lines | ||
| 62 | 62 | if (test_bit(DMA_FENCE_FLAG_USER_BITS, &fence->base.flags)) { |
| 63 | 63 | struct nouveau_fence_chan *fctx = nouveau_fctx(fence); |
| 64 | 64 | |
| 65 | − if (atomic_dec_and_test(&fctx->notify_ref)) | |
| 65 | + if (!--fctx->notify_ref) | |
| 66 | 66 | drop = 1; |
| 67 | 67 | } |
| 68 | 68 | |
| @@ -103,7 +103,6 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error) · 34 unmodified lines | ||
| 103 | 103 | void |
| 104 | 104 | nouveau_fence_context_del(struct nouveau_fence_chan *fctx) |
| 105 | 105 | { |
| 106 | − cancel_work_sync(&fctx->allow_block_work); | |
| 107 | 106 | nouveau_fence_context_kill(fctx, 0); |
| 108 | 107 | nvif_event_dtor(&fctx->event); |
| 109 | 108 | fctx->dead = 1; |
| @@ -168,18 +167,6 @@ nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc · 58 unmodified lines | ||
| 168 | 167 | return ret; |
| 169 | 168 | } |
| 170 | 169 | |
| 171 | −static void | |
| 172 | −nouveau_fence_work_allow_block(struct work_struct *work) | |
| 173 | −{ | |
| 174 | − struct nouveau_fence_chan *fctx = container_of(work, struct nouveau_fence_chan, | |
| 175 | − allow_block_work); | |
| 176 | − | |
| 177 | − if (atomic_read(&fctx->notify_ref) == 0) | |
| 178 | − nvif_event_block(&fctx->event); | |
| 179 | − else | |
| 180 | − nvif_event_allow(&fctx->event); | |
| 181 | −} | |
| 182 | − | |
| 183 | 170 | void |
| 184 | 171 | nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx) |
| 185 | 172 | { |
| @@ -191,7 +178,6 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha · 5 unmodified lines | ||
| 191 | 178 | } args; |
| 192 | 179 | int ret; |
| 193 | 180 | |
| 194 | − INIT_WORK(&fctx->allow_block_work, nouveau_fence_work_allow_block); | |
| 195 | 181 | INIT_LIST_HEAD(&fctx->flip); |
| 196 | 182 | INIT_LIST_HEAD(&fctx->pending); |
| 197 | 183 | spin_lock_init(&fctx->lock); |
| @@ -535,19 +521,15 @@ static bool nouveau_fence_enable_signaling(struct dma_fence *f) · 337 unmodified lines | ||
| 535 | 521 | struct nouveau_fence *fence = from_fence(f); |
| 536 | 522 | struct nouveau_fence_chan *fctx = nouveau_fctx(fence); |
| 537 | 523 | bool ret; |
| 538 | − bool do_work; | |
| 539 | 524 | |
| 540 | − if (atomic_inc_return(&fctx->notify_ref) == 0) | |
| 541 | − do_work = true; | |
| 525 | + if (!fctx->notify_ref++) | |
| 526 | + nvif_event_allow(&fctx->event); | |
| 542 | 527 | |
| 543 | 528 | ret = nouveau_fence_no_signaling(f); |
| 544 | 529 | if (ret) |
| 545 | 530 | set_bit(DMA_FENCE_FLAG_USER_BITS, &fence->base.flags); |
| 546 | − else if (atomic_dec_and_test(&fctx->notify_ref)) | |
| 547 | − do_work = true; | |
| 548 | − | |
| 549 | − if (do_work) | |
| 550 | − schedule_work(&fctx->allow_block_work); | |
| 531 | + else if (!--fctx->notify_ref) | |
| 532 | + nvif_event_block(&fctx->event); | |
| 551 | 533 | |
| 552 | 534 | return ret; |
| 553 | 535 | } |
| @@ -3,7 +3,6 @@ · 2 unmodified lines | ||
| 3 | 3 | #define __NOUVEAU_FENCE_H__ |
| 4 | 4 | |
| 5 | 5 | #include <linux/dma-fence.h> |
| 6 | −#include <linux/workqueue.h> | |
| 7 | 6 | #include <nvif/event.h> |
| 8 | 7 | |
| 9 | 8 | struct nouveau_drm; |
| @@ -46,9 +45,7 @@ struct nouveau_fence_chan { · 36 unmodified lines | ||
| 46 | 45 | char name[32]; |
| 47 | 46 | |
| 48 | 47 | struct nvif_event event; |
| 49 | − struct work_struct allow_block_work; | |
| 50 | − atomic_t notify_ref; | |
| 51 | − int dead, killed; | |
| 48 | + int notify_ref, dead, killed; | |
| 52 | 49 | }; |
| 53 | 50 | |
| 54 | 51 | struct nouveau_fence_priv { |
| @@ -539,6 +539,8 @@ config DRM_PANEL_RAYDIUM_RM692E5 · 538 unmodified lines | ||
| 539 | 539 | depends on OF |
| 540 | 540 | depends on DRM_MIPI_DSI |
| 541 | 541 | depends on BACKLIGHT_CLASS_DEVICE |
| 542 | + select DRM_DISPLAY_DP_HELPER | |
| 543 | + select DRM_DISPLAY_HELPER | |
| 542 | 544 | help |
| 543 | 545 | Say Y here if you want to enable support for Raydium RM692E5-based |
| 544 | 546 | display panels, such as the one found in the Fairphone 5 smartphone. |
| @@ -309,7 +309,7 @@ static const struct s6d7aa0_panel_desc s6d7aa0_lsl080al02_desc = { · 308 unmodified lines | ||
| 309 | 309 | .off_func = s6d7aa0_lsl080al02_off, |
| 310 | 310 | .drm_mode = &s6d7aa0_lsl080al02_mode, |
| 311 | 311 | .mode_flags = MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_NO_HFP, |
| 312 | − .bus_flags = DRM_BUS_FLAG_DE_HIGH, | |
| 312 | + .bus_flags = 0, | |
| 313 | 313 | |
| 314 | 314 | .has_backlight = false, |
| 315 | 315 | .use_passwd3 = false, |
| @@ -3948,6 +3948,7 @@ static const struct panel_desc tianma_tm070jdhg30 = { · 3947 unmodified lines | ||
| 3948 | 3948 | }, |
| 3949 | 3949 | .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, |
| 3950 | 3950 | .connector_type = DRM_MODE_CONNECTOR_LVDS, |
| 3951 | + .bus_flags = DRM_BUS_FLAG_DE_HIGH, | |
| 3951 | 3952 | }; |
| 3952 | 3953 | |
| 3953 | 3954 | static const struct panel_desc tianma_tm070jvhg33 = { |
| @@ -3960,6 +3961,7 @@ static const struct panel_desc tianma_tm070jvhg33 = { · 6 unmodified lines | ||
| 3960 | 3961 | }, |
| 3961 | 3962 | .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, |
| 3962 | 3963 | .connector_type = DRM_MODE_CONNECTOR_LVDS, |
| 3964 | + .bus_flags = DRM_BUS_FLAG_DE_HIGH, | |
| 3963 | 3965 | }; |
| 3964 | 3966 | |
| 3965 | 3967 | static const struct display_timing tianma_tm070rvhg71_timing = { |
| @@ -1178,21 +1178,20 @@ static void drm_sched_run_job_work(struct work_struct *w) · 1177 unmodified lines | ||
| 1178 | 1178 | struct drm_sched_entity *entity; |
| 1179 | 1179 | struct dma_fence *fence; |
| 1180 | 1180 | struct drm_sched_fence *s_fence; |
| 1181 | − struct drm_sched_job *sched_job; | |
| 1181 | + struct drm_sched_job *sched_job = NULL; | |
| 1182 | 1182 | int r; |
| 1183 | 1183 | |
| 1184 | 1184 | if (READ_ONCE(sched->pause_submit)) |
| 1185 | 1185 | return; |
| 1186 | 1186 | |
| 1187 | − entity = drm_sched_select_entity(sched); | |
| 1187 | + /* Find entity with a ready job */ | |
| 1188 | + while (!sched_job && (entity = drm_sched_select_entity(sched))) { | |
| 1189 | + sched_job = drm_sched_entity_pop_job(entity); | |
| 1190 | + if (!sched_job) | |
| 1191 | + complete_all(&entity->entity_idle); | |
| 1192 | + } | |
| 1188 | 1193 | if (!entity) |
| 1189 | − return; | |
| 1190 | − | |
| 1191 | − sched_job = drm_sched_entity_pop_job(entity); | |
| 1192 | − if (!sched_job) { | |
| 1193 | − complete_all(&entity->entity_idle); | |
| 1194 | 1194 | return; /* No more work */ |
| 1195 | − } | |
| 1196 | 1195 | |
| 1197 | 1196 | s_fence = sched_job->s_fence; |
| 1198 | 1197 | |
| @@ -188,13 +188,13 @@ out: · 187 unmodified lines | ||
| 188 | 188 | |
| 189 | 189 | static void drm_test_mm_debug(struct kunit *test) |
| 190 | 190 | { |
| 191 | + struct drm_printer p = drm_debug_printer(test->name); | |
| 191 | 192 | struct drm_mm mm; |
| 192 | 193 | struct drm_mm_node nodes[2]; |
| 193 | 194 | |
| 194 | 195 | /* Create a small drm_mm with a couple of nodes and a few holes, and |
| 195 | 196 | * check that the debug iterator doesn't explode over a trivial drm_mm. |
| 196 | 197 | */ |
| 197 | − | |
| 198 | 198 | drm_mm_init(&mm, 0, 4096); |
| 199 | 199 | |
| 200 | 200 | memset(nodes, 0, sizeof(nodes)); |
| @@ -209,6 +209,9 @@ static void drm_test_mm_debug(struct kunit *test) · 8 unmodified lines | ||
| 209 | 209 | KUNIT_ASSERT_FALSE_MSG(test, drm_mm_reserve_node(&mm, &nodes[1]), |
| 210 | 210 | "failed to reserve node[0] {start=%lld, size=%lld)\n", |
| 211 | 211 | nodes[0].start, nodes[0].size); |
| 212 | + | |
| 213 | + drm_mm_print(&mm, &p); | |
| 214 | + KUNIT_SUCCEED(test); | |
| 212 | 215 | } |
| 213 | 216 | |
| 214 | 217 | static bool expect_insert(struct kunit *test, struct drm_mm *mm, |
| @@ -95,11 +95,17 @@ static int ttm_global_init(void) · 94 unmodified lines | ||
| 95 | 95 | ttm_pool_mgr_init(num_pages); |
| 96 | 96 | ttm_tt_mgr_init(num_pages, num_dma32); |
| 97 | 97 | |
| 98 | − glob->dummy_read_page = alloc_page(__GFP_ZERO | GFP_DMA32); | |
| 98 | + glob->dummy_read_page = alloc_page(__GFP_ZERO | GFP_DMA32 | | |
| 99 | + __GFP_NOWARN); | |
| 99 | 100 | |
| 101 | + /* Retry without GFP_DMA32 for platforms DMA32 is not available */ | |
| 100 | 102 | if (unlikely(glob->dummy_read_page == NULL)) { |
| 101 | − ret = -ENOMEM; | |
| 102 | − goto out; | |
| 103 | + glob->dummy_read_page = alloc_page(__GFP_ZERO); | |
| 104 | + if (unlikely(glob->dummy_read_page == NULL)) { | |
| 105 | + ret = -ENOMEM; | |
| 106 | + goto out; | |
| 107 | + } | |
| 108 | + pr_warn("Using GFP_DMA32 fallback for dummy_read_page\n"); | |
| 103 | 109 | } |
| 104 | 110 | |
| 105 | 111 | INIT_LIST_HEAD(&glob->device_list); |
| @@ -147,6 +147,13 @@ v3d_job_allocate(void **container, size_t size) · 146 unmodified lines | ||
| 147 | 147 | return 0; |
| 148 | 148 | } |
| 149 | 149 | |
| 150 | +static void | |
| 151 | +v3d_job_deallocate(void **container) | |
| 152 | +{ | |
| 153 | + kfree(*container); | |
| 154 | + *container = NULL; | |
| 155 | +} | |
| 156 | + | |
| 150 | 157 | static int |
| 151 | 158 | v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, |
| 152 | 159 | struct v3d_job *job, void (*free)(struct kref *ref), |
| @@ -273,8 +280,10 @@ v3d_setup_csd_jobs_and_bos(struct drm_file *file_priv, · 120 unmodified lines | ||
| 273 | 280 | |
| 274 | 281 | ret = v3d_job_init(v3d, file_priv, &(*job)->base, |
| 275 | 282 | v3d_job_free, args->in_sync, se, V3D_CSD); |
| 276 | − if (ret) | |
| 283 | + if (ret) { | |
| 284 | + v3d_job_deallocate((void *)job); | |
| 277 | 285 | return ret; |
| 286 | + } | |
| 278 | 287 | |
| 279 | 288 | ret = v3d_job_allocate((void *)clean_job, sizeof(**clean_job)); |
| 280 | 289 | if (ret) |
| @@ -282,8 +291,10 @@ v3d_setup_csd_jobs_and_bos(struct drm_file *file_priv, · 1 unmodified line | ||
| 282 | 291 | |
| 283 | 292 | ret = v3d_job_init(v3d, file_priv, *clean_job, |
| 284 | 293 | v3d_job_free, 0, NULL, V3D_CACHE_CLEAN); |
| 285 | − if (ret) | |
| 294 | + if (ret) { | |
| 295 | + v3d_job_deallocate((void *)clean_job); | |
| 286 | 296 | return ret; |
| 297 | + } | |
| 287 | 298 | |
| 288 | 299 | (*job)->args = *args; |
| 289 | 300 | |
| @@ -860,8 +871,10 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, · 570 unmodified lines | ||
| 860 | 871 | |
| 861 | 872 | ret = v3d_job_init(v3d, file_priv, &render->base, |
| 862 | 873 | v3d_render_job_free, args->in_sync_rcl, &se, V3D_RENDER); |
| 863 | − if (ret) | |
| 874 | + if (ret) { | |
| 875 | + v3d_job_deallocate((void *)&render); | |
| 864 | 876 | goto fail; |
| 877 | + } | |
| 865 | 878 | |
| 866 | 879 | render->start = args->rcl_start; |
| 867 | 880 | render->end = args->rcl_end; |
| @@ -874,8 +887,10 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, · 6 unmodified lines | ||
| 874 | 887 | |
| 875 | 888 | ret = v3d_job_init(v3d, file_priv, &bin->base, |
| 876 | 889 | v3d_job_free, args->in_sync_bcl, &se, V3D_BIN); |
| 877 | − if (ret) | |
| 890 | + if (ret) { | |
| 891 | + v3d_job_deallocate((void *)&bin); | |
| 878 | 892 | goto fail; |
| 893 | + } | |
| 879 | 894 | |
| 880 | 895 | bin->start = args->bcl_start; |
| 881 | 896 | bin->end = args->bcl_end; |
| @@ -892,8 +907,10 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, · 10 unmodified lines | ||
| 892 | 907 | |
| 893 | 908 | ret = v3d_job_init(v3d, file_priv, clean_job, |
| 894 | 909 | v3d_job_free, 0, NULL, V3D_CACHE_CLEAN); |
| 895 | − if (ret) | |
| 910 | + if (ret) { | |
| 911 | + v3d_job_deallocate((void *)&clean_job); | |
| 896 | 912 | goto fail; |
| 913 | + } | |
| 897 | 914 | |
| 898 | 915 | last_job = clean_job; |
| 899 | 916 | } else { |
| @@ -1015,8 +1032,10 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, · 115 unmodified lines | ||
| 1015 | 1032 | |
| 1016 | 1033 | ret = v3d_job_init(v3d, file_priv, &job->base, |
| 1017 | 1034 | v3d_job_free, args->in_sync, &se, V3D_TFU); |
| 1018 | − if (ret) | |
| 1035 | + if (ret) { | |
| 1036 | + v3d_job_deallocate((void *)&job); | |
| 1019 | 1037 | goto fail; |
| 1038 | + } | |
| 1020 | 1039 | |
| 1021 | 1040 | job->base.bo = kcalloc(ARRAY_SIZE(args->bo_handles), |
| 1022 | 1041 | sizeof(*job->base.bo), GFP_KERNEL); |
| @@ -1233,8 +1252,10 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, · 210 unmodified lines | ||
| 1233 | 1252 | |
| 1234 | 1253 | ret = v3d_job_init(v3d, file_priv, &cpu_job->base, |
| 1235 | 1254 | v3d_job_free, 0, &se, V3D_CPU); |
| 1236 | − if (ret) | |
| 1255 | + if (ret) { | |
| 1256 | + v3d_job_deallocate((void *)&cpu_job); | |
| 1237 | 1257 | goto fail; |
| 1258 | + } | |
| 1238 | 1259 | |
| 1239 | 1260 | clean_job = cpu_job->indirect_csd.clean_job; |
| 1240 | 1261 | csd_job = cpu_job->indirect_csd.job; |
| @@ -35,12 +35,10 @@ static inline int i915_gem_object_read_from_page(struct xe_bo *bo, · 34 unmodified lines | ||
| 35 | 35 | u32 ofs, u64 *ptr, u32 size) |
| 36 | 36 | { |
| 37 | 37 | struct ttm_bo_kmap_obj map; |
| 38 | − void *virtual; | |
| 38 | + void *src; | |
| 39 | 39 | bool is_iomem; |
| 40 | 40 | int ret; |
| 41 | 41 | |
| 42 | − XE_WARN_ON(size != 8); | |
| 43 | − | |
| 44 | 42 | ret = xe_bo_lock(bo, true); |
| 45 | 43 | if (ret) |
| 46 | 44 | return ret; |
| @@ -50,11 +48,12 @@ static inline int i915_gem_object_read_from_page(struct xe_bo *bo, · 3 unmodified lines | ||
| 50 | 48 | goto out_unlock; |
| 51 | 49 | |
| 52 | 50 | ofs &= ~PAGE_MASK; |
| 53 | − virtual = ttm_kmap_obj_virtual(&map, &is_iomem); | |
| 51 | + src = ttm_kmap_obj_virtual(&map, &is_iomem); | |
| 52 | + src += ofs; | |
| 54 | 53 | if (is_iomem) |
| 55 | − *ptr = readq((void __iomem *)(virtual + ofs)); | |
| 54 | + memcpy_fromio(ptr, (void __iomem *)src, size); | |
| 56 | 55 | else |
| 57 | − *ptr = *(u64 *)(virtual + ofs); | |
| 56 | + memcpy(ptr, src, size); | |
| 58 | 57 | |
| 59 | 58 | ttm_bo_kunmap(&map); |
| 60 | 59 | out_unlock: |
| @@ -74,9 +74,6 @@ static const struct platform_test_case cases[] = { · 73 unmodified lines | ||
| 74 | 74 | SUBPLATFORM_CASE(DG2, G11, B1), |
| 75 | 75 | SUBPLATFORM_CASE(DG2, G12, A0), |
| 76 | 76 | SUBPLATFORM_CASE(DG2, G12, A1), |
| 77 | − PLATFORM_CASE(PVC, B0), | |
| 78 | − PLATFORM_CASE(PVC, B1), | |
| 79 | − PLATFORM_CASE(PVC, C0), | |
| 80 | 77 | GMDID_CASE(METEORLAKE, 1270, A0, 1300, A0), |
| 81 | 78 | GMDID_CASE(METEORLAKE, 1271, A0, 1300, A0), |
| 82 | 79 | GMDID_CASE(LUNARLAKE, 2004, A0, 2000, A0), |
| @@ -613,7 +613,7 @@ void xe_device_wmb(struct xe_device *xe) · 612 unmodified lines | ||
| 613 | 613 | u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size) |
| 614 | 614 | { |
| 615 | 615 | return xe_device_has_flat_ccs(xe) ? |
| 616 | − DIV_ROUND_UP(size, NUM_BYTES_PER_CCS_BYTE(xe)) : 0; | |
| 616 | + DIV_ROUND_UP_ULL(size, NUM_BYTES_PER_CCS_BYTE(xe)) : 0; | |
| 617 | 617 | } |
| 618 | 618 | |
| 619 | 619 | bool xe_device_mem_access_ongoing(struct xe_device *xe) |
| @@ -175,7 +175,7 @@ static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf, · 174 unmodified lines | ||
| 175 | 175 | return 0; |
| 176 | 176 | } |
| 177 | 177 | |
| 178 | −const struct dma_buf_ops xe_dmabuf_ops = { | |
| 178 | +static const struct dma_buf_ops xe_dmabuf_ops = { | |
| 179 | 179 | .attach = xe_dma_buf_attach, |
| 180 | 180 | .detach = xe_dma_buf_detach, |
| 181 | 181 | .pin = xe_dma_buf_pin, |
| @@ -419,7 +419,7 @@ static int xe_hwmon_pcode_read_i1(struct xe_gt *gt, u32 *uval) · 418 unmodified lines | ||
| 419 | 419 | |
| 420 | 420 | return xe_pcode_read(gt, PCODE_MBOX(PCODE_POWER_SETUP, |
| 421 | 421 | POWER_SETUP_SUBCOMMAND_READ_I1, 0), |
| 422 | − uval, 0); | |
| 422 | + uval, NULL); | |
| 423 | 423 | } |
| 424 | 424 | |
| 425 | 425 | static int xe_hwmon_pcode_write_i1(struct xe_gt *gt, u32 uval) |
| @@ -472,7 +472,7 @@ static void emit_pte(struct xe_migrate *m, · 471 unmodified lines | ||
| 472 | 472 | /* Indirect access needs compression enabled uncached PAT index */ |
| 473 | 473 | if (GRAPHICS_VERx100(xe) >= 2000) |
| 474 | 474 | pat_index = is_comp_pte ? xe->pat.idx[XE_CACHE_NONE_COMPRESSION] : |
| 475 | − xe->pat.idx[XE_CACHE_NONE]; | |
| 475 | + xe->pat.idx[XE_CACHE_WB]; | |
| 476 | 476 | else |
| 477 | 477 | pat_index = xe->pat.idx[XE_CACHE_WB]; |
| 478 | 478 | |
| @@ -760,14 +760,14 @@ struct dma_fence *xe_migrate_copy(struct xe_migrate *m, · 281 unmodified lines | ||
| 760 | 760 | if (src_is_vram && xe_migrate_allow_identity(src_L0, &src_it)) |
| 761 | 761 | xe_res_next(&src_it, src_L0); |
| 762 | 762 | else |
| 763 | − emit_pte(m, bb, src_L0_pt, src_is_vram, true, &src_it, src_L0, | |
| 764 | − src); | |
| 763 | + emit_pte(m, bb, src_L0_pt, src_is_vram, copy_system_ccs, | |
| 764 | + &src_it, src_L0, src); | |
| 765 | 765 | |
| 766 | 766 | if (dst_is_vram && xe_migrate_allow_identity(src_L0, &dst_it)) |
| 767 | 767 | xe_res_next(&dst_it, src_L0); |
| 768 | 768 | else |
| 769 | − emit_pte(m, bb, dst_L0_pt, dst_is_vram, true, &dst_it, src_L0, | |
| 770 | − dst); | |
| 769 | + emit_pte(m, bb, dst_L0_pt, dst_is_vram, copy_system_ccs, | |
| 770 | + &dst_it, src_L0, dst); | |
| 771 | 771 | |
| 772 | 772 | if (copy_system_ccs) |
| 773 | 773 | emit_pte(m, bb, ccs_pt, false, false, &ccs_it, ccs_size, src); |
| @@ -1009,8 +1009,8 @@ struct dma_fence *xe_migrate_clear(struct xe_migrate *m, · 235 unmodified lines | ||
| 1009 | 1009 | if (clear_vram && xe_migrate_allow_identity(clear_L0, &src_it)) |
| 1010 | 1010 | xe_res_next(&src_it, clear_L0); |
| 1011 | 1011 | else |
| 1012 | − emit_pte(m, bb, clear_L0_pt, clear_vram, true, &src_it, clear_L0, | |
| 1013 | − dst); | |
| 1012 | + emit_pte(m, bb, clear_L0_pt, clear_vram, clear_system_ccs, | |
| 1013 | + &src_it, clear_L0, dst); | |
| 1014 | 1014 | |
| 1015 | 1015 | bb->cs[bb->len++] = MI_BATCH_BUFFER_END; |
| 1016 | 1016 | update_idx = bb->len; |
| @@ -272,8 +272,8 @@ int xe_mmio_probe_vram(struct xe_device *xe) · 271 unmodified lines | ||
| 272 | 272 | drm_info(&xe->drm, "VRAM[%u, %u]: Actual physical size %pa, usable size exclude stolen %pa, CPU accessible size %pa\n", id, |
| 273 | 273 | tile->id, &tile->mem.vram.actual_physical_size, &tile->mem.vram.usable_size, &tile->mem.vram.io_size); |
| 274 | 274 | drm_info(&xe->drm, "VRAM[%u, %u]: DPA range: [%pa-%llx], io range: [%pa-%llx]\n", id, tile->id, |
| 275 | − &tile->mem.vram.dpa_base, tile->mem.vram.dpa_base + tile->mem.vram.actual_physical_size, | |
| 276 | − &tile->mem.vram.io_start, tile->mem.vram.io_start + tile->mem.vram.io_size); | |
| 275 | + &tile->mem.vram.dpa_base, tile->mem.vram.dpa_base + (u64)tile->mem.vram.actual_physical_size, | |
| 276 | + &tile->mem.vram.io_start, tile->mem.vram.io_start + (u64)tile->mem.vram.io_size); | |
| 277 | 277 | |
| 278 | 278 | /* calculate total size using tile size to get the correct HW sizing */ |
| 279 | 279 | total_size += tile_size; |
| @@ -1855,10 +1855,8 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data, · 1854 unmodified lines | ||
| 1855 | 1855 | mutex_lock(&xef->vm.lock); |
| 1856 | 1856 | err = xa_alloc(&xef->vm.xa, &id, vm, xa_limit_32b, GFP_KERNEL); |
| 1857 | 1857 | mutex_unlock(&xef->vm.lock); |
| 1858 | − if (err) { | |
| 1859 | − xe_vm_close_and_put(vm); | |
| 1860 | − return err; | |
| 1861 | − } | |
| 1858 | + if (err) | |
| 1859 | + goto err_close_and_put; | |
| 1862 | 1860 | |
| 1863 | 1861 | if (xe->info.has_asid) { |
| 1864 | 1862 | mutex_lock(&xe->usm.lock); |
| @@ -1866,11 +1864,9 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data, · 1 unmodified line | ||
| 1866 | 1864 | XA_LIMIT(1, XE_MAX_ASID - 1), |
| 1867 | 1865 | &xe->usm.next_asid, GFP_KERNEL); |
| 1868 | 1866 | mutex_unlock(&xe->usm.lock); |
| 1869 | − if (err < 0) { | |
| 1870 | − xe_vm_close_and_put(vm); | |
| 1871 | − return err; | |
| 1872 | − } | |
| 1873 | − err = 0; | |
| 1867 | + if (err < 0) | |
| 1868 | + goto err_free_id; | |
| 1869 | + | |
| 1874 | 1870 | vm->usm.asid = asid; |
| 1875 | 1871 | } |
| 1876 | 1872 | |
| @@ -1888,6 +1884,15 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data, · 11 unmodified lines | ||
| 1888 | 1884 | #endif |
| 1889 | 1885 | |
| 1890 | 1886 | return 0; |
| 1887 | + | |
| 1888 | +err_free_id: | |
| 1889 | + mutex_lock(&xef->vm.lock); | |
| 1890 | + xa_erase(&xef->vm.xa, id); | |
| 1891 | + mutex_unlock(&xef->vm.lock); | |
| 1892 | +err_close_and_put: | |
| 1893 | + xe_vm_close_and_put(vm); | |
| 1894 | + | |
| 1895 | + return err; | |
| 1891 | 1896 | } |
| 1892 | 1897 | |
| 1893 | 1898 | int xe_vm_destroy_ioctl(struct drm_device *dev, void *data, |
| @@ -143,6 +143,9 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *s · 142 unmodified lines | ||
| 143 | 143 | } |
| 144 | 144 | EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup); |
| 145 | 145 | |
| 146 | +/* Disables missing prototype warnings */ | |
| 147 | +__bpf_kfunc_start_defs(); | |
| 148 | + | |
| 146 | 149 | /** |
| 147 | 150 | * hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx |
| 148 | 151 | * |
| @@ -152,7 +155,7 @@ EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup); · 3 unmodified lines | ||
| 152 | 155 | * |
| 153 | 156 | * @returns %NULL on error, an %__u8 memory pointer on success |
| 154 | 157 | */ |
| 155 | −noinline __u8 * | |
| 158 | +__bpf_kfunc __u8 * | |
| 156 | 159 | hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size) |
| 157 | 160 | { |
| 158 | 161 | struct hid_bpf_ctx_kern *ctx_kern; |
| @@ -167,6 +170,7 @@ hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr · 8 unmodified lines | ||
| 167 | 170 | |
| 168 | 171 | return ctx_kern->data + offset; |
| 169 | 172 | } |
| 173 | +__bpf_kfunc_end_defs(); | |
| 170 | 174 | |
| 171 | 175 | /* |
| 172 | 176 | * The following set contains all functions we agree BPF programs |
| @@ -241,6 +245,42 @@ int hid_bpf_reconnect(struct hid_device *hdev) · 68 unmodified lines | ||
| 241 | 245 | return 0; |
| 242 | 246 | } |
| 243 | 247 | |
| 248 | +static int do_hid_bpf_attach_prog(struct hid_device *hdev, int prog_fd, struct bpf_prog *prog, | |
| 249 | + __u32 flags) | |
| 250 | +{ | |
| 251 | + int fd, err, prog_type; | |
| 252 | + | |
| 253 | + prog_type = hid_bpf_get_prog_attach_type(prog); | |
| 254 | + if (prog_type < 0) | |
| 255 | + return prog_type; | |
| 256 | + | |
| 257 | + if (prog_type >= HID_BPF_PROG_TYPE_MAX) | |
| 258 | + return -EINVAL; | |
| 259 | + | |
| 260 | + if (prog_type == HID_BPF_PROG_TYPE_DEVICE_EVENT) { | |
| 261 | + err = hid_bpf_allocate_event_data(hdev); | |
| 262 | + if (err) | |
| 263 | + return err; | |
| 264 | + } | |
| 265 | + | |
| 266 | + fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fd, prog, flags); | |
| 267 | + if (fd < 0) | |
| 268 | + return fd; | |
| 269 | + | |
| 270 | + if (prog_type == HID_BPF_PROG_TYPE_RDESC_FIXUP) { | |
| 271 | + err = hid_bpf_reconnect(hdev); | |
| 272 | + if (err) { | |
| 273 | + close_fd(fd); | |
| 274 | + return err; | |
| 275 | + } | |
| 276 | + } | |
| 277 | + | |
| 278 | + return fd; | |
| 279 | +} | |
| 280 | + | |
| 281 | +/* Disables missing prototype warnings */ | |
| 282 | +__bpf_kfunc_start_defs(); | |
| 283 | + | |
| 244 | 284 | /** |
| 245 | 285 | * hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device |
| 246 | 286 | * |
| @@ -253,22 +293,17 @@ int hid_bpf_reconnect(struct hid_device *hdev) · 6 unmodified lines | ||
| 253 | 293 | * is pinned to the BPF file system). |
| 254 | 294 | */ |
| 255 | 295 | /* called from syscall */ |
| 256 | −noinline int | |
| 296 | +__bpf_kfunc int | |
| 257 | 297 | hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags) |
| 258 | 298 | { |
| 259 | 299 | struct hid_device *hdev; |
| 300 | + struct bpf_prog *prog; | |
| 260 | 301 | struct device *dev; |
| 261 | − int fd, err, prog_type = hid_bpf_get_prog_attach_type(prog_fd); | |
| 302 | + int err, fd; | |
| 262 | 303 | |
| 263 | 304 | if (!hid_bpf_ops) |
| 264 | 305 | return -EINVAL; |
| 265 | 306 | |
| 266 | − if (prog_type < 0) | |
| 267 | − return prog_type; | |
| 268 | − | |
| 269 | − if (prog_type >= HID_BPF_PROG_TYPE_MAX) | |
| 270 | − return -EINVAL; | |
| 271 | − | |
| 272 | 307 | if ((flags & ~HID_BPF_FLAG_MASK)) |
| 273 | 308 | return -EINVAL; |
| 274 | 309 | |
| @@ -278,25 +313,29 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags) · 3 unmodified lines | ||
| 278 | 313 | |
| 279 | 314 | hdev = to_hid_device(dev); |
| 280 | 315 | |
| 281 | − if (prog_type == HID_BPF_PROG_TYPE_DEVICE_EVENT) { | |
| 282 | − err = hid_bpf_allocate_event_data(hdev); | |
| 283 | − if (err) | |
| 284 | − return err; | |
| 316 | + /* | |
| 317 | + * take a ref on the prog itself, it will be released | |
| 318 | + * on errors or when it'll be detached | |
| 319 | + */ | |
| 320 | + prog = bpf_prog_get(prog_fd); | |
| 321 | + if (IS_ERR(prog)) { | |
| 322 | + err = PTR_ERR(prog); | |
| 323 | + goto out_dev_put; | |
| 285 | 324 | } |
| 286 | 325 | |
| 287 | − fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fd, flags); | |
| 288 | − if (fd < 0) | |
| 289 | − return fd; | |
| 290 | − | |
| 291 | − if (prog_type == HID_BPF_PROG_TYPE_RDESC_FIXUP) { | |
| 292 | − err = hid_bpf_reconnect(hdev); | |
| 293 | − if (err) { | |
| 294 | − close_fd(fd); | |
| 295 | − return err; | |
| 296 | − } | |
| 326 | + fd = do_hid_bpf_attach_prog(hdev, prog_fd, prog, flags); | |
| 327 | + if (fd < 0) { | |
| 328 | + err = fd; | |
| 329 | + goto out_prog_put; | |
| 297 | 330 | } |
| 298 | 331 | |
| 299 | 332 | return fd; |
| 333 | + | |
| 334 | + out_prog_put: | |
| 335 | + bpf_prog_put(prog); | |
| 336 | + out_dev_put: | |
| 337 | + put_device(dev); | |
| 338 | + return err; | |
| 300 | 339 | } |
| 301 | 340 | |
| 302 | 341 | /** |
| @@ -306,7 +345,7 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags) · 3 unmodified lines | ||
| 306 | 345 | * |
| 307 | 346 | * @returns A pointer to &struct hid_bpf_ctx on success, %NULL on error. |
| 308 | 347 | */ |
| 309 | −noinline struct hid_bpf_ctx * | |
| 348 | +__bpf_kfunc struct hid_bpf_ctx * | |
| 310 | 349 | hid_bpf_allocate_context(unsigned int hid_id) |
| 311 | 350 | { |
| 312 | 351 | struct hid_device *hdev; |
| @@ -323,8 +362,10 @@ hid_bpf_allocate_context(unsigned int hid_id) · 10 unmodified lines | ||
| 323 | 362 | hdev = to_hid_device(dev); |
| 324 | 363 | |
| 325 | 364 | ctx_kern = kzalloc(sizeof(*ctx_kern), GFP_KERNEL); |
| 326 | − if (!ctx_kern) | |
| 365 | + if (!ctx_kern) { | |
| 366 | + put_device(dev); | |
| 327 | 367 | return NULL; |
| 368 | + } | |
| 328 | 369 | |
| 329 | 370 | ctx_kern->ctx.hid = hdev; |
| 330 | 371 | |
| @@ -337,14 +378,19 @@ hid_bpf_allocate_context(unsigned int hid_id) · 6 unmodified lines | ||
| 337 | 378 | * @ctx: the HID-BPF context to release |
| 338 | 379 | * |
| 339 | 380 | */ |
| 340 | −noinline void | |
| 381 | +__bpf_kfunc void | |
| 341 | 382 | hid_bpf_release_context(struct hid_bpf_ctx *ctx) |
| 342 | 383 | { |
| 343 | 384 | struct hid_bpf_ctx_kern *ctx_kern; |
| 385 | + struct hid_device *hid; | |
| 344 | 386 | |
| 345 | 387 | ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx); |
| 388 | + hid = (struct hid_device *)ctx_kern->ctx.hid; /* ignore const */ | |
| 346 | 389 | |
| 347 | 390 | kfree(ctx_kern); |
| 391 | + | |
| 392 | + /* get_device() is called by bus_find_device() */ | |
| 393 | + put_device(&hid->dev); | |
| 348 | 394 | } |
| 349 | 395 | |
| 350 | 396 | /** |
| @@ -358,7 +404,7 @@ hid_bpf_release_context(struct hid_bpf_ctx *ctx) · 7 unmodified lines | ||
| 358 | 404 | * |
| 359 | 405 | * @returns %0 on success, a negative error code otherwise. |
| 360 | 406 | */ |
| 361 | −noinline int | |
| 407 | +__bpf_kfunc int | |
| 362 | 408 | hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, |
| 363 | 409 | enum hid_report_type rtype, enum hid_class_request reqtype) |
| 364 | 410 | { |
| @@ -426,6 +472,7 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, · 61 unmodified lines | ||
| 426 | 472 | kfree(dma_data); |
| 427 | 473 | return ret; |
| 428 | 474 | } |
| 475 | +__bpf_kfunc_end_defs(); | |
| 429 | 476 | |
| 430 | 477 | /* our HID-BPF entrypoints */ |
| 431 | 478 | BTF_SET8_START(hid_bpf_fmodret_ids) |
| @@ -12,9 +12,9 @@ struct hid_bpf_ctx_kern { · 11 unmodified lines | ||
| 12 | 12 | |
| 13 | 13 | int hid_bpf_preload_skel(void); |
| 14 | 14 | void hid_bpf_free_links_and_skel(void); |
| 15 | −int hid_bpf_get_prog_attach_type(int prog_fd); | |
| 15 | +int hid_bpf_get_prog_attach_type(struct bpf_prog *prog); | |
| 16 | 16 | int __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type, int prog_fd, |
| 17 | − __u32 flags); | |
| 17 | + struct bpf_prog *prog, __u32 flags); | |
| 18 | 18 | void __hid_bpf_destroy_device(struct hid_device *hdev); |
| 19 | 19 | int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type, |
| 20 | 20 | struct hid_bpf_ctx_kern *ctx_kern); |
| @@ -196,6 +196,7 @@ static void __hid_bpf_do_release_prog(int map_fd, unsigned int idx) · 195 unmodified lines | ||
| 196 | 196 | static void hid_bpf_release_progs(struct work_struct *work) |
| 197 | 197 | { |
| 198 | 198 | int i, j, n, map_fd = -1; |
| 199 | + bool hdev_destroyed; | |
| 199 | 200 | |
| 200 | 201 | if (!jmp_table.map) |
| 201 | 202 | return; |
| @@ -220,6 +221,12 @@ static void hid_bpf_release_progs(struct work_struct *work) · 18 unmodified lines | ||
| 220 | 221 | if (entry->hdev) { |
| 221 | 222 | hdev = entry->hdev; |
| 222 | 223 | type = entry->type; |
| 224 | + /* | |
| 225 | + * hdev is still valid, even if we are called after hid_destroy_device(): | |
| 226 | + * when hid_bpf_attach() gets called, it takes a ref on the dev through | |
| 227 | + * bus_find_device() | |
| 228 | + */ | |
| 229 | + hdev_destroyed = hdev->bpf.destroyed; | |
| 223 | 230 | |
| 224 | 231 | hid_bpf_populate_hdev(hdev, type); |
| 225 | 232 | |
| @@ -232,12 +239,19 @@ static void hid_bpf_release_progs(struct work_struct *work) · 6 unmodified lines | ||
| 232 | 239 | if (test_bit(next->idx, jmp_table.enabled)) |
| 233 | 240 | continue; |
| 234 | 241 | |
| 235 | − if (next->hdev == hdev && next->type == type) | |
| 242 | + if (next->hdev == hdev && next->type == type) { | |
| 243 | + /* | |
| 244 | + * clear the hdev reference and decrement the device ref | |
| 245 | + * that was taken during bus_find_device() while calling | |
| 246 | + * hid_bpf_attach() | |
| 247 | + */ | |
| 236 | 248 | next->hdev = NULL; |
| 249 | + put_device(&hdev->dev); | |
| 250 | + } | |
| 237 | 251 | } |
| 238 | 252 | |
| 239 | − /* if type was rdesc fixup, reconnect device */ | |
| 240 | − if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP) | |
| 253 | + /* if type was rdesc fixup and the device is not gone, reconnect device */ | |
| 254 | + if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP && !hdev_destroyed) | |
| 241 | 255 | hid_bpf_reconnect(hdev); |
| 242 | 256 | } |
| 243 | 257 | } |
| @@ -333,15 +347,10 @@ static int hid_bpf_insert_prog(int prog_fd, struct bpf_prog *prog) · 89 unmodified lines | ||
| 333 | 347 | return err; |
| 334 | 348 | } |
| 335 | 349 | |
| 336 | −int hid_bpf_get_prog_attach_type(int prog_fd) | |
| 350 | +int hid_bpf_get_prog_attach_type(struct bpf_prog *prog) | |
| 337 | 351 | { |
| 338 | − struct bpf_prog *prog = NULL; | |
| 339 | − int i; | |
| 340 | 352 | int prog_type = HID_BPF_PROG_TYPE_UNDEF; |
| 341 | − | |
| 342 | − prog = bpf_prog_get(prog_fd); | |
| 343 | − if (IS_ERR(prog)) | |
| 344 | − return PTR_ERR(prog); | |
| 353 | + int i; | |
| 345 | 354 | |
| 346 | 355 | for (i = 0; i < HID_BPF_PROG_TYPE_MAX; i++) { |
| 347 | 356 | if (hid_bpf_btf_ids[i] == prog->aux->attach_btf_id) { |
| @@ -350,8 +359,6 @@ int hid_bpf_get_prog_attach_type(int prog_fd) · 2 unmodified lines | ||
| 350 | 359 | } |
| 351 | 360 | } |
| 352 | 361 | |
| 353 | − bpf_prog_put(prog); | |
| 354 | − | |
| 355 | 362 | return prog_type; |
| 356 | 363 | } |
| 357 | 364 | |
| @@ -388,19 +395,13 @@ static const struct bpf_link_ops hid_bpf_link_lops = { · 30 unmodified lines | ||
| 388 | 395 | /* called from syscall */ |
| 389 | 396 | noinline int |
| 390 | 397 | __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type, |
| 391 | − int prog_fd, __u32 flags) | |
| 398 | + int prog_fd, struct bpf_prog *prog, __u32 flags) | |
| 392 | 399 | { |
| 393 | 400 | struct bpf_link_primer link_primer; |
| 394 | 401 | struct hid_bpf_link *link; |
| 395 | − struct bpf_prog *prog = NULL; | |
| 396 | 402 | struct hid_bpf_prog_entry *prog_entry; |
| 397 | 403 | int cnt, err = -EINVAL, prog_table_idx = -1; |
| 398 | 404 | |
| 399 | − /* take a ref on the prog itself */ | |
| 400 | − prog = bpf_prog_get(prog_fd); | |
| 401 | − if (IS_ERR(prog)) | |
| 402 | − return PTR_ERR(prog); | |
| 403 | − | |
| 404 | 405 | mutex_lock(&hid_bpf_attach_lock); |
| 405 | 406 | |
| 406 | 407 | link = kzalloc(sizeof(*link), GFP_USER); |
| @@ -467,7 +468,6 @@ __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type, · 60 unmodified lines | ||
| 467 | 468 | err_unlock: |
| 468 | 469 | mutex_unlock(&hid_bpf_attach_lock); |
| 469 | 470 | |
| 470 | − bpf_prog_put(prog); | |
| 471 | 471 | kfree(link); |
| 472 | 472 | |
| 473 | 473 | return err; |
| @@ -298,6 +298,9 @@ · 297 unmodified lines | ||
| 298 | 298 | |
| 299 | 299 | #define USB_VENDOR_ID_CIDC 0x1677 |
| 300 | 300 | |
| 301 | +#define I2C_VENDOR_ID_CIRQUE 0x0488 | |
| 302 | +#define I2C_PRODUCT_ID_CIRQUE_1063 0x1063 | |
| 303 | + | |
| 301 | 304 | #define USB_VENDOR_ID_CJTOUCH 0x24b8 |
| 302 | 305 | #define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020 0x0020 |
| 303 | 306 | #define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040 0x0040 |
| @@ -4610,6 +4610,8 @@ static const struct hid_device_id hidpp_devices[] = { · 4609 unmodified lines | ||
| 4610 | 4610 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC088) }, |
| 4611 | 4611 | { /* Logitech G Pro X Superlight Gaming Mouse over USB */ |
| 4612 | 4612 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC094) }, |
| 4613 | + { /* Logitech G Pro X Superlight 2 Gaming Mouse over USB */ | |
| 4614 | + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC09b) }, | |
| 4613 | 4615 | |
| 4614 | 4616 | { /* G935 Gaming Headset */ |
| 4615 | 4617 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0x0a87), |
| @@ -800,6 +800,8 @@ static inline int thunderstrike_led_create(struct thunderstrike *ts) · 799 unmodified lines | ||
| 800 | 800 | |
| 801 | 801 | led->name = devm_kasprintf(&ts->base.hdev->dev, GFP_KERNEL, |
| 802 | 802 | "thunderstrike%d:blue:led", ts->id); |
| 803 | + if (!led->name) | |
| 804 | + return -ENOMEM; | |
| 803 | 805 | led->max_brightness = 1; |
| 804 | 806 | led->flags = LED_CORE_SUSPENDRESUME | LED_RETAIN_AT_SHUTDOWN; |
| 805 | 807 | led->brightness_get = &thunderstrike_led_get_brightness; |
| @@ -831,6 +833,8 @@ static inline int thunderstrike_psy_create(struct shield_device *shield_dev) · 25 unmodified lines | ||
| 831 | 833 | shield_dev->battery_dev.desc.name = |
| 832 | 834 | devm_kasprintf(&ts->base.hdev->dev, GFP_KERNEL, |
| 833 | 835 | "thunderstrike_%d", ts->id); |
| 836 | + if (!shield_dev->battery_dev.desc.name) | |
| 837 | + return -ENOMEM; | |
| 834 | 838 | |
| 835 | 839 | shield_dev->battery_dev.psy = power_supply_register( |
| 836 | 840 | &hdev->dev, &shield_dev->battery_dev.desc, &psy_cfg); |
| @@ -1109,10 +1109,9 @@ static int steam_probe(struct hid_device *hdev, · 1108 unmodified lines | ||
| 1109 | 1109 | return hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
| 1110 | 1110 | |
| 1111 | 1111 | steam = devm_kzalloc(&hdev->dev, sizeof(*steam), GFP_KERNEL); |
| 1112 | − if (!steam) { | |
| 1113 | − ret = -ENOMEM; | |
| 1114 | − goto steam_alloc_fail; | |
| 1115 | − } | |
| 1112 | + if (!steam) | |
| 1113 | + return -ENOMEM; | |
| 1114 | + | |
| 1116 | 1115 | steam->hdev = hdev; |
| 1117 | 1116 | hid_set_drvdata(hdev, steam); |
| 1118 | 1117 | spin_lock_init(&steam->lock); |
| @@ -1129,14 +1128,14 @@ static int steam_probe(struct hid_device *hdev, · 10 unmodified lines | ||
| 1129 | 1128 | */ |
| 1130 | 1129 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDRAW); |
| 1131 | 1130 | if (ret) |
| 1132 | − goto hid_hw_start_fail; | |
| 1131 | + goto err_cancel_work; | |
| 1133 | 1132 | |
| 1134 | 1133 | ret = hid_hw_open(hdev); |
| 1135 | 1134 | if (ret) { |
| 1136 | 1135 | hid_err(hdev, |
| 1137 | 1136 | "%s:hid_hw_open\n", |
| 1138 | 1137 | __func__); |
| 1139 | − goto hid_hw_open_fail; | |
| 1138 | + goto err_hw_stop; | |
| 1140 | 1139 | } |
| 1141 | 1140 | |
| 1142 | 1141 | if (steam->quirks & STEAM_QUIRK_WIRELESS) { |
| @@ -1152,36 +1151,37 @@ static int steam_probe(struct hid_device *hdev, · 9 unmodified lines | ||
| 1152 | 1151 | hid_err(hdev, |
| 1153 | 1152 | "%s:steam_register failed with error %d\n", |
| 1154 | 1153 | __func__, ret); |
| 1155 | − goto input_register_fail; | |
| 1154 | + goto err_hw_close; | |
| 1156 | 1155 | } |
| 1157 | 1156 | } |
| 1158 | 1157 | |
| 1159 | 1158 | steam->client_hdev = steam_create_client_hid(hdev); |
| 1160 | 1159 | if (IS_ERR(steam->client_hdev)) { |
| 1161 | 1160 | ret = PTR_ERR(steam->client_hdev); |
| 1162 | − goto client_hdev_fail; | |
| 1161 | + goto err_stream_unregister; | |
| 1163 | 1162 | } |
| 1164 | 1163 | steam->client_hdev->driver_data = steam; |
| 1165 | 1164 | |
| 1166 | 1165 | ret = hid_add_device(steam->client_hdev); |
| 1167 | 1166 | if (ret) |
| 1168 | − goto client_hdev_add_fail; | |
| 1167 | + goto err_destroy; | |
| 1169 | 1168 | |
| 1170 | 1169 | return 0; |
| 1171 | 1170 | |
| 1172 | −client_hdev_add_fail: | |
| 1173 | − hid_hw_stop(hdev); | |
| 1174 | −client_hdev_fail: | |
| 1171 | +err_destroy: | |
| 1175 | 1172 | hid_destroy_device(steam->client_hdev); |
| 1176 | −input_register_fail: | |
| 1177 | −hid_hw_open_fail: | |
| 1178 | −hid_hw_start_fail: | |
| 1173 | +err_stream_unregister: | |
| 1174 | + if (steam->connected) | |
| 1175 | + steam_unregister(steam); | |
| 1176 | +err_hw_close: | |
| 1177 | + hid_hw_close(hdev); | |
| 1178 | +err_hw_stop: | |
| 1179 | + hid_hw_stop(hdev); | |
| 1180 | +err_cancel_work: | |
| 1179 | 1181 | cancel_work_sync(&steam->work_connect); |
| 1180 | 1182 | cancel_delayed_work_sync(&steam->mode_switch); |
| 1181 | 1183 | cancel_work_sync(&steam->rumble_work); |
| 1182 | −steam_alloc_fail: | |
| 1183 | − hid_err(hdev, "%s: failed with error %d\n", | |
| 1184 | − __func__, ret); | |
| 1184 | + | |
| 1185 | 1185 | return ret; |
| 1186 | 1186 | } |
| 1187 | 1187 | |
| @@ -357,8 +357,11 @@ static int hidraw_release(struct inode * inode, struct file * file) · 356 unmodified lines | ||
| 357 | 357 | down_write(&minors_rwsem); |
| 358 | 358 | |
| 359 | 359 | spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags); |
| 360 | − for (int i = list->tail; i < list->head; i++) | |
| 361 | − kfree(list->buffer[i].value); | |
| 360 | + while (list->tail != list->head) { | |
| 361 | + kfree(list->buffer[list->tail].value); | |
| 362 | + list->buffer[list->tail].value = NULL; | |
| 363 | + list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1); | |
| 364 | + } | |
| 362 | 365 | list_del(&list->node); |
| 363 | 366 | spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags); |
| 364 | 367 | kfree(list); |
| @@ -49,6 +49,7 @@ · 48 unmodified lines | ||
| 49 | 49 | #define I2C_HID_QUIRK_RESET_ON_RESUME BIT(2) |
| 50 | 50 | #define I2C_HID_QUIRK_BAD_INPUT_SIZE BIT(3) |
| 51 | 51 | #define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET BIT(4) |
| 52 | +#define I2C_HID_QUIRK_NO_SLEEP_ON_SUSPEND BIT(5) | |
| 52 | 53 | |
| 53 | 54 | /* Command opcodes */ |
| 54 | 55 | #define I2C_HID_OPCODE_RESET 0x01 |
| @@ -131,6 +132,8 @@ static const struct i2c_hid_quirks { · 76 unmodified lines | ||
| 131 | 132 | I2C_HID_QUIRK_RESET_ON_RESUME }, |
| 132 | 133 | { USB_VENDOR_ID_ITE, I2C_DEVICE_ID_ITE_LENOVO_LEGION_Y720, |
| 133 | 134 | I2C_HID_QUIRK_BAD_INPUT_SIZE }, |
| 135 | + { I2C_VENDOR_ID_CIRQUE, I2C_PRODUCT_ID_CIRQUE_1063, | |
| 136 | + I2C_HID_QUIRK_NO_SLEEP_ON_SUSPEND }, | |
| 134 | 137 | /* |
| 135 | 138 | * Sending the wakeup after reset actually break ELAN touchscreen controller |
| 136 | 139 | */ |
| @@ -956,7 +959,8 @@ static int i2c_hid_core_suspend(struct i2c_hid *ihid, bool force_poweroff) · 819 unmodified lines | ||
| 956 | 959 | return ret; |
| 957 | 960 | |
| 958 | 961 | /* Save some power */ |
| 959 | − i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP); | |
| 962 | + if (!(ihid->quirks & I2C_HID_QUIRK_NO_SLEEP_ON_SUSPEND)) | |
| 963 | + i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP); | |
| 960 | 964 | |
| 961 | 965 | disable_irq(client->irq); |
| 962 | 966 | |
| @@ -87,6 +87,7 @@ static int i2c_hid_of_probe(struct i2c_client *client) · 86 unmodified lines | ||
| 87 | 87 | if (!ihid_of) |
| 88 | 88 | return -ENOMEM; |
| 89 | 89 | |
| 90 | + ihid_of->client = client; | |
| 90 | 91 | ihid_of->ops.power_up = i2c_hid_of_power_up; |
| 91 | 92 | ihid_of->ops.power_down = i2c_hid_of_power_down; |
| 92 | 93 | |
| @@ -2262,7 +2262,7 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio) · 2261 unmodified lines | ||
| 2262 | 2262 | int sectors = r1_bio->sectors; |
| 2263 | 2263 | int read_disk = r1_bio->read_disk; |
| 2264 | 2264 | struct mddev *mddev = conf->mddev; |
| 2265 | − struct md_rdev *rdev = rcu_dereference(conf->mirrors[read_disk].rdev); | |
| 2265 | + struct md_rdev *rdev = conf->mirrors[read_disk].rdev; | |
| 2266 | 2266 | |
| 2267 | 2267 | if (exceed_read_errors(mddev, rdev)) { |
| 2268 | 2268 | r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED; |
| @@ -989,7 +989,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, · 988 unmodified lines | ||
| 989 | 989 | bool no_previous_buffers = !q_num_bufs; |
| 990 | 990 | int ret = 0; |
| 991 | 991 | |
| 992 | − if (q->num_buffers == q->max_num_buffers) { | |
| 992 | + if (q_num_bufs == q->max_num_buffers) { | |
| 993 | 993 | dprintk(q, 1, "maximum number of buffers already allocated\n"); |
| 994 | 994 | return -ENOBUFS; |
| 995 | 995 | } |
| @@ -671,8 +671,20 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) · 670 unmodified lines | ||
| 671 | 671 | } |
| 672 | 672 | EXPORT_SYMBOL(vb2_querybuf); |
| 673 | 673 | |
| 674 | −static void fill_buf_caps(struct vb2_queue *q, u32 *caps) | |
| 674 | +static void vb2_set_flags_and_caps(struct vb2_queue *q, u32 memory, | |
| 675 | + u32 *flags, u32 *caps, u32 *max_num_bufs) | |
| 675 | 676 | { |
| 677 | + if (!q->allow_cache_hints || memory != V4L2_MEMORY_MMAP) { | |
| 678 | + /* | |
| 679 | + * This needs to clear V4L2_MEMORY_FLAG_NON_COHERENT only, | |
| 680 | + * but in order to avoid bugs we zero out all bits. | |
| 681 | + */ | |
| 682 | + *flags = 0; | |
| 683 | + } else { | |
| 684 | + /* Clear all unknown flags. */ | |
| 685 | + *flags &= V4L2_MEMORY_FLAG_NON_COHERENT; | |
| 686 | + } | |
| 687 | + | |
| 676 | 688 | *caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS; |
| 677 | 689 | if (q->io_modes & VB2_MMAP) |
| 678 | 690 | *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP; |
| @@ -686,21 +698,9 @@ static void fill_buf_caps(struct vb2_queue *q, u32 *caps) · 7 unmodified lines | ||
| 686 | 698 | *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS; |
| 687 | 699 | if (q->supports_requests) |
| 688 | 700 | *caps |= V4L2_BUF_CAP_SUPPORTS_REQUESTS; |
| 689 | −} | |
| 690 | − | |
| 691 | −static void validate_memory_flags(struct vb2_queue *q, | |
| 692 | − int memory, | |
| 693 | − u32 *flags) | |
| 694 | −{ | |
| 695 | − if (!q->allow_cache_hints || memory != V4L2_MEMORY_MMAP) { | |
| 696 | − /* | |
| 697 | − * This needs to clear V4L2_MEMORY_FLAG_NON_COHERENT only, | |
| 698 | − * but in order to avoid bugs we zero out all bits. | |
| 699 | − */ | |
| 700 | − *flags = 0; | |
| 701 | − } else { | |
| 702 | − /* Clear all unknown flags. */ | |
| 703 | − *flags &= V4L2_MEMORY_FLAG_NON_COHERENT; | |
| 701 | + if (max_num_bufs) { | |
| 702 | + *max_num_bufs = q->max_num_buffers; | |
| 703 | + *caps |= V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS; | |
| 704 | 704 | } |
| 705 | 705 | } |
| 706 | 706 | |
| @@ -709,8 +709,8 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) · 2 unmodified lines | ||
| 709 | 709 | int ret = vb2_verify_memory_type(q, req->memory, req->type); |
| 710 | 710 | u32 flags = req->flags; |
| 711 | 711 | |
| 712 | − fill_buf_caps(q, &req->capabilities); | |
| 713 | − validate_memory_flags(q, req->memory, &flags); | |
| 712 | + vb2_set_flags_and_caps(q, req->memory, &flags, | |
| 713 | + &req->capabilities, NULL); | |
| 714 | 714 | req->flags = flags; |
| 715 | 715 | return ret ? ret : vb2_core_reqbufs(q, req->memory, |
| 716 | 716 | req->flags, &req->count); |
| @@ -751,11 +751,9 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) · 34 unmodified lines | ||
| 751 | 751 | int ret = vb2_verify_memory_type(q, create->memory, f->type); |
| 752 | 752 | unsigned i; |
| 753 | 753 | |
| 754 | − fill_buf_caps(q, &create->capabilities); | |
| 755 | − validate_memory_flags(q, create->memory, &create->flags); | |
| 756 | 754 | create->index = vb2_get_num_buffers(q); |
| 757 | − create->max_num_buffers = q->max_num_buffers; | |
| 758 | − create->capabilities |= V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS; | |
| 755 | + vb2_set_flags_and_caps(q, create->memory, &create->flags, | |
| 756 | + &create->capabilities, &create->max_num_buffers); | |
| 759 | 757 | if (create->count == 0) |
| 760 | 758 | return ret != -EBUSY ? ret : 0; |
| 761 | 759 | |
| @@ -1006,8 +1004,8 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv, · 244 unmodified lines | ||
| 1006 | 1004 | int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type); |
| 1007 | 1005 | u32 flags = p->flags; |
| 1008 | 1006 | |
| 1009 | − fill_buf_caps(vdev->queue, &p->capabilities); | |
| 1010 | − validate_memory_flags(vdev->queue, p->memory, &flags); | |
| 1007 | + vb2_set_flags_and_caps(vdev->queue, p->memory, &flags, | |
| 1008 | + &p->capabilities, NULL); | |
| 1011 | 1009 | p->flags = flags; |
| 1012 | 1010 | if (res) |
| 1013 | 1011 | return res; |
| @@ -1026,12 +1024,11 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv, · 12 unmodified lines | ||
| 1026 | 1024 | struct v4l2_create_buffers *p) |
| 1027 | 1025 | { |
| 1028 | 1026 | struct video_device *vdev = video_devdata(file); |
| 1029 | − int res = vb2_verify_memory_type(vdev->queue, p->memory, | |
| 1030 | − p->format.type); | |
| 1027 | + int res = vb2_verify_memory_type(vdev->queue, p->memory, p->format.type); | |
| 1031 | 1028 | |
| 1032 | − p->index = vdev->queue->num_buffers; | |
| 1033 | − fill_buf_caps(vdev->queue, &p->capabilities); | |
| 1034 | − validate_memory_flags(vdev->queue, p->memory, &p->flags); | |
| 1029 | + p->index = vb2_get_num_buffers(vdev->queue); | |
| 1030 | + vb2_set_flags_and_caps(vdev->queue, p->memory, &p->flags, | |
| 1031 | + &p->capabilities, &p->max_num_buffers); | |
| 1035 | 1032 | /* |
| 1036 | 1033 | * If count == 0, then just check if memory and type are valid. |
| 1037 | 1034 | * Any -EBUSY result from vb2_verify_memory_type can be mapped to 0. |
| @@ -272,7 +272,7 @@ static const struct wave5_match_data ti_wave521c_data = { · 271 unmodified lines | ||
| 272 | 272 | }; |
| 273 | 273 | |
| 274 | 274 | static const struct of_device_id wave5_dt_ids[] = { |
| 275 | − { .compatible = "ti,k3-j721s2-wave521c", .data = &ti_wave521c_data }, | |
| 275 | + { .compatible = "ti,j721s2-wave521c", .data = &ti_wave521c_data }, | |
| 276 | 276 | { /* sentinel */ } |
| 277 | 277 | }; |
| 278 | 278 | MODULE_DEVICE_TABLE(of, wave5_dt_ids); |
| @@ -2840,8 +2840,7 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port, · 2839 unmodified lines | ||
| 2840 | 2840 | /* MT753x MAC works in 1G full duplex mode for all up-clocked |
| 2841 | 2841 | * variants. |
| 2842 | 2842 | */ |
| 2843 | − if (interface == PHY_INTERFACE_MODE_INTERNAL || | |
| 2844 | − interface == PHY_INTERFACE_MODE_TRGMII || | |
| 2843 | + if (interface == PHY_INTERFACE_MODE_TRGMII || | |
| 2845 | 2844 | (phy_interface_mode_is_8023z(interface))) { |
| 2846 | 2845 | speed = SPEED_1000; |
| 2847 | 2846 | duplex = DUPLEX_FULL; |
| @@ -3659,7 +3659,7 @@ static int mv88e6xxx_mdio_read_c45(struct mii_bus *bus, int phy, int devad, · 3658 unmodified lines | ||
| 3659 | 3659 | int err; |
| 3660 | 3660 | |
| 3661 | 3661 | if (!chip->info->ops->phy_read_c45) |
| 3662 | − return -EOPNOTSUPP; | |
| 3662 | + return 0xffff; | |
| 3663 | 3663 | |
| 3664 | 3664 | mv88e6xxx_reg_lock(chip); |
| 3665 | 3665 | err = chip->info->ops->phy_read_c45(chip, bus, phy, devad, reg, &val); |
| @@ -2051,12 +2051,11 @@ qca8k_sw_probe(struct mdio_device *mdiodev) · 2050 unmodified lines | ||
| 2051 | 2051 | priv->info = of_device_get_match_data(priv->dev); |
| 2052 | 2052 | |
| 2053 | 2053 | priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", |
| 2054 | − GPIOD_ASIS); | |
| 2054 | + GPIOD_OUT_HIGH); | |
| 2055 | 2055 | if (IS_ERR(priv->reset_gpio)) |
| 2056 | 2056 | return PTR_ERR(priv->reset_gpio); |
| 2057 | 2057 | |
| 2058 | 2058 | if (priv->reset_gpio) { |
| 2059 | − gpiod_set_value_cansleep(priv->reset_gpio, 1); | |
| 2060 | 2059 | /* The active low duration must be greater than 10 ms |
| 2061 | 2060 | * and checkpatch.pl wants 20 ms. |
| 2062 | 2061 | */ |
| @@ -63,6 +63,15 @@ static int pdsc_process_notifyq(struct pdsc_qcq *qcq) · 62 unmodified lines | ||
| 63 | 63 | return nq_work; |
| 64 | 64 | } |
| 65 | 65 | |
| 66 | +static bool pdsc_adminq_inc_if_up(struct pdsc *pdsc) | |
| 67 | +{ | |
| 68 | + if (pdsc->state & BIT_ULL(PDSC_S_STOPPING_DRIVER) || | |
| 69 | + pdsc->state & BIT_ULL(PDSC_S_FW_DEAD)) | |
| 70 | + return false; | |
| 71 | + | |
| 72 | + return refcount_inc_not_zero(&pdsc->adminq_refcnt); | |
| 73 | +} | |
| 74 | + | |
| 66 | 75 | void pdsc_process_adminq(struct pdsc_qcq *qcq) |
| 67 | 76 | { |
| 68 | 77 | union pds_core_adminq_comp *comp; |
| @@ -75,9 +84,9 @@ void pdsc_process_adminq(struct pdsc_qcq *qcq) · 6 unmodified lines | ||
| 75 | 84 | int aq_work = 0; |
| 76 | 85 | int credits; |
| 77 | 86 | |
| 78 | − /* Don't process AdminQ when shutting down */ | |
| 79 | − if (pdsc->state & BIT_ULL(PDSC_S_STOPPING_DRIVER)) { | |
| 80 | − dev_err(pdsc->dev, "%s: called while PDSC_S_STOPPING_DRIVER\n", | |
| 87 | + /* Don't process AdminQ when it's not up */ | |
| 88 | + if (!pdsc_adminq_inc_if_up(pdsc)) { | |
| 89 | + dev_err(pdsc->dev, "%s: called while adminq is unavailable\n", | |
| 81 | 90 | __func__); |
| 82 | 91 | return; |
| 83 | 92 | } |
| @@ -124,6 +133,7 @@ credits: · 40 unmodified lines | ||
| 124 | 133 | pds_core_intr_credits(&pdsc->intr_ctrl[qcq->intx], |
| 125 | 134 | credits, |
| 126 | 135 | PDS_CORE_INTR_CRED_REARM); |
| 136 | + refcount_dec(&pdsc->adminq_refcnt); | |
| 127 | 137 | } |
| 128 | 138 | |
| 129 | 139 | void pdsc_work_thread(struct work_struct *work) |
| @@ -135,18 +145,20 @@ void pdsc_work_thread(struct work_struct *work) · 5 unmodified lines | ||
| 135 | 145 | |
| 136 | 146 | irqreturn_t pdsc_adminq_isr(int irq, void *data) |
| 137 | 147 | { |
| 138 | − struct pdsc_qcq *qcq = data; | |
| 139 | − struct pdsc *pdsc = qcq->pdsc; | |
| 148 | + struct pdsc *pdsc = data; | |
| 149 | + struct pdsc_qcq *qcq; | |
| 140 | 150 | |
| 141 | − /* Don't process AdminQ when shutting down */ | |
| 142 | − if (pdsc->state & BIT_ULL(PDSC_S_STOPPING_DRIVER)) { | |
| 143 | − dev_err(pdsc->dev, "%s: called while PDSC_S_STOPPING_DRIVER\n", | |
| 151 | + /* Don't process AdminQ when it's not up */ | |
| 152 | + if (!pdsc_adminq_inc_if_up(pdsc)) { | |
| 153 | + dev_err(pdsc->dev, "%s: called while adminq is unavailable\n", | |
| 144 | 154 | __func__); |
| 145 | 155 | return IRQ_HANDLED; |
| 146 | 156 | } |
| 147 | 157 | |
| 158 | + qcq = &pdsc->adminqcq; | |
| 148 | 159 | queue_work(pdsc->wq, &qcq->work); |
| 149 | 160 | pds_core_intr_mask(&pdsc->intr_ctrl[qcq->intx], PDS_CORE_INTR_MASK_CLEAR); |
| 161 | + refcount_dec(&pdsc->adminq_refcnt); | |
| 150 | 162 | |
| 151 | 163 | return IRQ_HANDLED; |
| 152 | 164 | } |
| @@ -179,10 +191,16 @@ static int __pdsc_adminq_post(struct pdsc *pdsc, · 26 unmodified lines | ||
| 179 | 191 | |
| 180 | 192 | /* Check that the FW is running */ |
| 181 | 193 | if (!pdsc_is_fw_running(pdsc)) { |
| 182 | − u8 fw_status = ioread8(&pdsc->info_regs->fw_status); | |
| 183 | − | |
| 184 | − dev_info(pdsc->dev, "%s: post failed - fw not running %#02x:\n", | |
| 185 | − __func__, fw_status); | |
| 194 | + if (pdsc->info_regs) { | |
| 195 | + u8 fw_status = | |
| 196 | + ioread8(&pdsc->info_regs->fw_status); | |
| 197 | + | |
| 198 | + dev_info(pdsc->dev, "%s: post failed - fw not running %#02x:\n", | |
| 199 | + __func__, fw_status); | |
| 200 | + } else { | |
| 201 | + dev_info(pdsc->dev, "%s: post failed - BARs not setup\n", | |
| 202 | + __func__); | |
| 203 | + } | |
| 186 | 204 | ret = -ENXIO; |
| 187 | 205 | |
| 188 | 206 | goto err_out_unlock; |
| @@ -230,6 +248,12 @@ int pdsc_adminq_post(struct pdsc *pdsc, · 41 unmodified lines | ||
| 230 | 248 | int err = 0; |
| 231 | 249 | int index; |
| 232 | 250 | |
| 251 | + if (!pdsc_adminq_inc_if_up(pdsc)) { | |
| 252 | + dev_dbg(pdsc->dev, "%s: preventing adminq cmd %u\n", | |
| 253 | + __func__, cmd->opcode); | |
| 254 | + return -ENXIO; | |
| 255 | + } | |
| 256 | + | |
| 233 | 257 | wc.qcq = &pdsc->adminqcq; |
| 234 | 258 | index = __pdsc_adminq_post(pdsc, &pdsc->adminqcq, cmd, comp, &wc); |
| 235 | 259 | if (index < 0) { |
| @@ -248,10 +272,16 @@ int pdsc_adminq_post(struct pdsc *pdsc, · 12 unmodified lines | ||
| 248 | 272 | break; |
| 249 | 273 | |
| 250 | 274 | if (!pdsc_is_fw_running(pdsc)) { |
| 251 | − u8 fw_status = ioread8(&pdsc->info_regs->fw_status); | |
| 252 | − | |
| 253 | − dev_dbg(pdsc->dev, "%s: post wait failed - fw not running %#02x:\n", | |
| 254 | − __func__, fw_status); | |
| 275 | + if (pdsc->info_regs) { | |
| 276 | + u8 fw_status = | |
| 277 | + ioread8(&pdsc->info_regs->fw_status); | |
| 278 | + | |
| 279 | + dev_dbg(pdsc->dev, "%s: post wait failed - fw not running %#02x:\n", | |
| 280 | + __func__, fw_status); | |
| 281 | + } else { | |
| 282 | + dev_dbg(pdsc->dev, "%s: post wait failed - BARs not setup\n", | |
| 283 | + __func__); | |
| 284 | + } | |
| 255 | 285 | err = -ENXIO; |
| 256 | 286 | break; |
| 257 | 287 | } |
| @@ -285,6 +315,8 @@ err_out: · 27 unmodified lines | ||
| 285 | 315 | queue_work(pdsc->wq, &pdsc->health_work); |
| 286 | 316 | } |
| 287 | 317 | |
| 318 | + refcount_dec(&pdsc->adminq_refcnt); | |
| 319 | + | |
| 288 | 320 | return err; |
| 289 | 321 | } |
| 290 | 322 | EXPORT_SYMBOL_GPL(pdsc_adminq_post); |
| @@ -125,7 +125,7 @@ static int pdsc_qcq_intr_alloc(struct pdsc *pdsc, struct pdsc_qcq *qcq) · 124 unmodified lines | ||
| 125 | 125 | |
| 126 | 126 | snprintf(name, sizeof(name), "%s-%d-%s", |
| 127 | 127 | PDS_CORE_DRV_NAME, pdsc->pdev->bus->number, qcq->q.name); |
| 128 | − index = pdsc_intr_alloc(pdsc, name, pdsc_adminq_isr, qcq); | |
| 128 | + index = pdsc_intr_alloc(pdsc, name, pdsc_adminq_isr, pdsc); | |
| 129 | 129 | if (index < 0) |
| 130 | 130 | return index; |
| 131 | 131 | qcq->intx = index; |
| @@ -404,10 +404,7 @@ int pdsc_setup(struct pdsc *pdsc, bool init) · 272 unmodified lines | ||
| 404 | 404 | int numdescs; |
| 405 | 405 | int err; |
| 406 | 406 | |
| 407 | − if (init) | |
| 408 | − err = pdsc_dev_init(pdsc); | |
| 409 | − else | |
| 410 | − err = pdsc_dev_reinit(pdsc); | |
| 407 | + err = pdsc_dev_init(pdsc); | |
| 411 | 408 | if (err) |
| 412 | 409 | return err; |
| 413 | 410 | |
| @@ -450,6 +447,7 @@ int pdsc_setup(struct pdsc *pdsc, bool init) · 36 unmodified lines | ||
| 450 | 447 | pdsc_debugfs_add_viftype(pdsc); |
| 451 | 448 | } |
| 452 | 449 | |
| 450 | + refcount_set(&pdsc->adminq_refcnt, 1); | |
| 453 | 451 | clear_bit(PDSC_S_FW_DEAD, &pdsc->state); |
| 454 | 452 | return 0; |
| 455 | 453 | |
| @@ -464,6 +462,8 @@ void pdsc_teardown(struct pdsc *pdsc, bool removing) · 8 unmodified lines | ||
| 464 | 462 | |
| 465 | 463 | if (!pdsc->pdev->is_virtfn) |
| 466 | 464 | pdsc_devcmd_reset(pdsc); |
| 465 | + if (pdsc->adminqcq.work.func) | |
| 466 | + cancel_work_sync(&pdsc->adminqcq.work); | |
| 467 | 467 | pdsc_qcq_free(pdsc, &pdsc->notifyqcq); |
| 468 | 468 | pdsc_qcq_free(pdsc, &pdsc->adminqcq); |
| 469 | 469 | |
| @@ -476,10 +476,9 @@ void pdsc_teardown(struct pdsc *pdsc, bool removing) · 6 unmodified lines | ||
| 476 | 476 | for (i = 0; i < pdsc->nintrs; i++) |
| 477 | 477 | pdsc_intr_free(pdsc, i); |
| 478 | 478 | |
| 479 | − if (removing) { | |
| 480 | − kfree(pdsc->intr_info); | |
| 481 | − pdsc->intr_info = NULL; | |
| 482 | − } | |
| 479 | + kfree(pdsc->intr_info); | |
| 480 | + pdsc->intr_info = NULL; | |
| 481 | + pdsc->nintrs = 0; | |
| 483 | 482 | } |
| 484 | 483 | |
| 485 | 484 | if (pdsc->kern_dbpage) { |
| @@ -487,6 +486,7 @@ void pdsc_teardown(struct pdsc *pdsc, bool removing) · 1 unmodified line | ||
| 487 | 486 | pdsc->kern_dbpage = NULL; |
| 488 | 487 | } |
| 489 | 488 | |
| 489 | + pci_free_irq_vectors(pdsc->pdev); | |
| 490 | 490 | set_bit(PDSC_S_FW_DEAD, &pdsc->state); |
| 491 | 491 | } |
| 492 | 492 | |
| @@ -512,6 +512,24 @@ void pdsc_stop(struct pdsc *pdsc) · 19 unmodified lines | ||
| 512 | 512 | PDS_CORE_INTR_MASK_SET); |
| 513 | 513 | } |
| 514 | 514 | |
| 515 | +static void pdsc_adminq_wait_and_dec_once_unused(struct pdsc *pdsc) | |
| 516 | +{ | |
| 517 | + /* The driver initializes the adminq_refcnt to 1 when the adminq is | |
| 518 | + * allocated and ready for use. Other users/requesters will increment | |
| 519 | + * the refcnt while in use. If the refcnt is down to 1 then the adminq | |
| 520 | + * is not in use and the refcnt can be cleared and adminq freed. Before | |
| 521 | + * calling this function the driver will set PDSC_S_FW_DEAD, which | |
| 522 | + * prevent subsequent attempts to use the adminq and increment the | |
| 523 | + * refcnt to fail. This guarantees that this function will eventually | |
| 524 | + * exit. | |
| 525 | + */ | |
| 526 | + while (!refcount_dec_if_one(&pdsc->adminq_refcnt)) { | |
| 527 | + dev_dbg_ratelimited(pdsc->dev, "%s: adminq in use\n", | |
| 528 | + __func__); | |
| 529 | + cpu_relax(); | |
| 530 | + } | |
| 531 | +} | |
| 532 | + | |
| 515 | 533 | void pdsc_fw_down(struct pdsc *pdsc) |
| 516 | 534 | { |
| 517 | 535 | union pds_core_notifyq_comp reset_event = { |
| @@ -527,6 +545,8 @@ void pdsc_fw_down(struct pdsc *pdsc) · 9 unmodified lines | ||
| 527 | 545 | if (pdsc->pdev->is_virtfn) |
| 528 | 546 | return; |
| 529 | 547 | |
| 548 | + pdsc_adminq_wait_and_dec_once_unused(pdsc); | |
| 549 | + | |
| 530 | 550 | /* Notify clients of fw_down */ |
| 531 | 551 | if (pdsc->fw_reporter) |
| 532 | 552 | devlink_health_report(pdsc->fw_reporter, "FW down reported", pdsc); |
| @@ -577,7 +597,13 @@ err_out: · 44 unmodified lines | ||
| 577 | 597 | |
| 578 | 598 | static void pdsc_check_pci_health(struct pdsc *pdsc) |
| 579 | 599 | { |
| 580 | − u8 fw_status = ioread8(&pdsc->info_regs->fw_status); | |
| 600 | + u8 fw_status; | |
| 601 | + | |
| 602 | + /* some sort of teardown already in progress */ | |
| 603 | + if (!pdsc->info_regs) | |
| 604 | + return; | |
| 605 | + | |
| 606 | + fw_status = ioread8(&pdsc->info_regs->fw_status); | |
| 581 | 607 | |
| 582 | 608 | /* is PCI broken? */ |
| 583 | 609 | if (fw_status != PDS_RC_BAD_PCI) |
| @@ -184,6 +184,7 @@ struct pdsc { · 183 unmodified lines | ||
| 184 | 184 | struct mutex devcmd_lock; /* lock for dev_cmd operations */ |
| 185 | 185 | struct mutex config_lock; /* lock for configuration operations */ |
| 186 | 186 | spinlock_t adminq_lock; /* lock for adminq operations */ |
| 187 | + refcount_t adminq_refcnt; | |
| 187 | 188 | struct pds_core_dev_info_regs __iomem *info_regs; |
| 188 | 189 | struct pds_core_dev_cmd_regs __iomem *cmd_regs; |
| 189 | 190 | struct pds_core_intr __iomem *intr_ctrl; |
| @@ -280,7 +281,6 @@ int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd, · 90 unmodified lines | ||
| 280 | 281 | union pds_core_dev_comp *comp, int max_seconds); |
| 281 | 282 | int pdsc_devcmd_init(struct pdsc *pdsc); |
| 282 | 283 | int pdsc_devcmd_reset(struct pdsc *pdsc); |
| 283 | −int pdsc_dev_reinit(struct pdsc *pdsc); | |
| 284 | 284 | int pdsc_dev_init(struct pdsc *pdsc); |
| 285 | 285 | |
| 286 | 286 | void pdsc_reset_prepare(struct pci_dev *pdev); |
| @@ -64,6 +64,10 @@ DEFINE_SHOW_ATTRIBUTE(identity); · 63 unmodified lines | ||
| 64 | 64 | |
| 65 | 65 | void pdsc_debugfs_add_ident(struct pdsc *pdsc) |
| 66 | 66 | { |
| 67 | + /* This file will already exist in the reset flow */ | |
| 68 | + if (debugfs_lookup("identity", pdsc->dentry)) | |
| 69 | + return; | |
| 70 | + | |
| 67 | 71 | debugfs_create_file("identity", 0400, pdsc->dentry, |
| 68 | 72 | pdsc, &identity_fops); |
| 69 | 73 | } |
| @@ -57,6 +57,9 @@ int pdsc_err_to_errno(enum pds_core_status_code code) · 56 unmodified lines | ||
| 57 | 57 | |
| 58 | 58 | bool pdsc_is_fw_running(struct pdsc *pdsc) |
| 59 | 59 | { |
| 60 | + if (!pdsc->info_regs) | |
| 61 | + return false; | |
| 62 | + | |
| 60 | 63 | pdsc->fw_status = ioread8(&pdsc->info_regs->fw_status); |
| 61 | 64 | pdsc->last_fw_time = jiffies; |
| 62 | 65 | pdsc->last_hb = ioread32(&pdsc->info_regs->fw_heartbeat); |
| @@ -182,13 +185,17 @@ int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd, · 119 unmodified lines | ||
| 182 | 185 | { |
| 183 | 186 | int err; |
| 184 | 187 | |
| 188 | + if (!pdsc->cmd_regs) | |
| 189 | + return -ENXIO; | |
| 190 | + | |
| 185 | 191 | memcpy_toio(&pdsc->cmd_regs->cmd, cmd, sizeof(*cmd)); |
| 186 | 192 | pdsc_devcmd_dbell(pdsc); |
| 187 | 193 | err = pdsc_devcmd_wait(pdsc, cmd->opcode, max_seconds); |
| 188 | − memcpy_fromio(comp, &pdsc->cmd_regs->comp, sizeof(*comp)); | |
| 189 | 194 | |
| 190 | 195 | if ((err == -ENXIO || err == -ETIMEDOUT) && pdsc->wq) |
| 191 | 196 | queue_work(pdsc->wq, &pdsc->health_work); |
| 197 | + else | |
| 198 | + memcpy_fromio(comp, &pdsc->cmd_regs->comp, sizeof(*comp)); | |
| 192 | 199 | |
| 193 | 200 | return err; |
| 194 | 201 | } |
| @@ -309,13 +316,6 @@ static int pdsc_identify(struct pdsc *pdsc) · 114 unmodified lines | ||
| 309 | 316 | return 0; |
| 310 | 317 | } |
| 311 | 318 | |
| 312 | −int pdsc_dev_reinit(struct pdsc *pdsc) | |
| 313 | −{ | |
| 314 | − pdsc_init_devinfo(pdsc); | |
| 315 | − | |
| 316 | − return pdsc_identify(pdsc); | |
| 317 | −} | |
| 318 | − | |
| 319 | 319 | int pdsc_dev_init(struct pdsc *pdsc) |
| 320 | 320 | { |
| 321 | 321 | unsigned int nintrs; |
| @@ -111,7 +111,8 @@ int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req, · 110 unmodified lines | ||
| 111 | 111 | |
| 112 | 112 | mutex_lock(&pdsc->devcmd_lock); |
| 113 | 113 | err = pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout * 2); |
| 114 | − memcpy_fromio(&fw_list, pdsc->cmd_regs->data, sizeof(fw_list)); | |
| 114 | + if (!err) | |
| 115 | + memcpy_fromio(&fw_list, pdsc->cmd_regs->data, sizeof(fw_list)); | |
| 115 | 116 | mutex_unlock(&pdsc->devcmd_lock); |
| 116 | 117 | if (err && err != -EIO) |
| 117 | 118 | return err; |
| @@ -107,6 +107,9 @@ int pdsc_firmware_update(struct pdsc *pdsc, const struct firmware *fw, · 106 unmodified lines | ||
| 107 | 107 | |
| 108 | 108 | dev_info(pdsc->dev, "Installing firmware\n"); |
| 109 | 109 | |
| 110 | + if (!pdsc->cmd_regs) | |
| 111 | + return -ENXIO; | |
| 112 | + | |
| 110 | 113 | dl = priv_to_devlink(pdsc); |
| 111 | 114 | devlink_flash_update_status_notify(dl, "Preparing to flash", |
| 112 | 115 | NULL, 0, 0); |
| @@ -37,6 +37,11 @@ static void pdsc_unmap_bars(struct pdsc *pdsc) · 36 unmodified lines | ||
| 37 | 37 | struct pdsc_dev_bar *bars = pdsc->bars; |
| 38 | 38 | unsigned int i; |
| 39 | 39 | |
| 40 | + pdsc->info_regs = NULL; | |
| 41 | + pdsc->cmd_regs = NULL; | |
| 42 | + pdsc->intr_status = NULL; | |
| 43 | + pdsc->intr_ctrl = NULL; | |
| 44 | + | |
| 40 | 45 | for (i = 0; i < PDS_CORE_BARS_MAX; i++) { |
| 41 | 46 | if (bars[i].vaddr) |
| 42 | 47 | pci_iounmap(pdsc->pdev, bars[i].vaddr); |
| @@ -293,7 +298,7 @@ err_out_stop: · 250 unmodified lines | ||
| 293 | 298 | err_out_teardown: |
| 294 | 299 | pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING); |
| 295 | 300 | err_out_unmap_bars: |
| 296 | − del_timer_sync(&pdsc->wdtimer); | |
| 301 | + timer_shutdown_sync(&pdsc->wdtimer); | |
| 297 | 302 | if (pdsc->wq) |
| 298 | 303 | destroy_workqueue(pdsc->wq); |
| 299 | 304 | mutex_destroy(&pdsc->config_lock); |
| @@ -420,7 +425,7 @@ static void pdsc_remove(struct pci_dev *pdev) · 120 unmodified lines | ||
| 420 | 425 | */ |
| 421 | 426 | pdsc_sriov_configure(pdev, 0); |
| 422 | 427 | |
| 423 | − del_timer_sync(&pdsc->wdtimer); | |
| 428 | + timer_shutdown_sync(&pdsc->wdtimer); | |
| 424 | 429 | if (pdsc->wq) |
| 425 | 430 | destroy_workqueue(pdsc->wq); |
| 426 | 431 | |
| @@ -433,7 +438,6 @@ static void pdsc_remove(struct pci_dev *pdev) · 6 unmodified lines | ||
| 433 | 438 | mutex_destroy(&pdsc->config_lock); |
| 434 | 439 | mutex_destroy(&pdsc->devcmd_lock); |
| 435 | 440 | |
| 436 | − pci_free_irq_vectors(pdev); | |
| 437 | 441 | pdsc_unmap_bars(pdsc); |
| 438 | 442 | pci_release_regions(pdev); |
| 439 | 443 | } |
| @@ -445,13 +449,26 @@ static void pdsc_remove(struct pci_dev *pdev) · 5 unmodified lines | ||
| 445 | 449 | devlink_free(dl); |
| 446 | 450 | } |
| 447 | 451 | |
| 452 | +static void pdsc_stop_health_thread(struct pdsc *pdsc) | |
| 453 | +{ | |
| 454 | + timer_shutdown_sync(&pdsc->wdtimer); | |
| 455 | + if (pdsc->health_work.func) | |
| 456 | + cancel_work_sync(&pdsc->health_work); | |
| 457 | +} | |
| 458 | + | |
| 459 | +static void pdsc_restart_health_thread(struct pdsc *pdsc) | |
| 460 | +{ | |
| 461 | + timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0); | |
| 462 | + mod_timer(&pdsc->wdtimer, jiffies + 1); | |
| 463 | +} | |
| 464 | + | |
| 448 | 465 | void pdsc_reset_prepare(struct pci_dev *pdev) |
| 449 | 466 | { |
| 450 | 467 | struct pdsc *pdsc = pci_get_drvdata(pdev); |
| 451 | 468 | |
| 469 | + pdsc_stop_health_thread(pdsc); | |
| 452 | 470 | pdsc_fw_down(pdsc); |
| 453 | 471 | |
| 454 | − pci_free_irq_vectors(pdev); | |
| 455 | 472 | pdsc_unmap_bars(pdsc); |
| 456 | 473 | pci_release_regions(pdev); |
| 457 | 474 | pci_disable_device(pdev); |
| @@ -486,6 +503,7 @@ void pdsc_reset_done(struct pci_dev *pdev) · 28 unmodified lines | ||
| 486 | 503 | } |
| 487 | 504 | |
| 488 | 505 | pdsc_fw_up(pdsc); |
| 506 | + pdsc_restart_health_thread(pdsc); | |
| 489 | 507 | } |
| 490 | 508 | |
| 491 | 509 | static const struct pci_error_handlers pdsc_err_handler = { |
| @@ -684,7 +684,7 @@ static void bnxt_stamp_tx_skb(struct bnxt *bp, struct sk_buff *skb) · 683 unmodified lines | ||
| 684 | 684 | timestamp.hwtstamp = ns_to_ktime(ns); |
| 685 | 685 | skb_tstamp_tx(ptp->tx_skb, ×tamp); |
| 686 | 686 | } else { |
| 687 | − netdev_WARN_ONCE(bp->dev, | |
| 687 | + netdev_warn_once(bp->dev, | |
| 688 | 688 | "TS query for TX timer failed rc = %x\n", rc); |
| 689 | 689 | } |
| 690 | 690 | |
| @@ -402,7 +402,7 @@ static enum pkt_hash_types gve_rss_type(__be16 pkt_flags) · 401 unmodified lines | ||
| 402 | 402 | |
| 403 | 403 | static struct sk_buff *gve_rx_add_frags(struct napi_struct *napi, |
| 404 | 404 | struct gve_rx_slot_page_info *page_info, |
| 405 | − u16 packet_buffer_size, u16 len, | |
| 405 | + unsigned int truesize, u16 len, | |
| 406 | 406 | struct gve_rx_ctx *ctx) |
| 407 | 407 | { |
| 408 | 408 | u32 offset = page_info->page_offset + page_info->pad; |
| @@ -435,10 +435,10 @@ static struct sk_buff *gve_rx_add_frags(struct napi_struct *napi, · 26 unmodified lines | ||
| 435 | 435 | if (skb != ctx->skb_head) { |
| 436 | 436 | ctx->skb_head->len += len; |
| 437 | 437 | ctx->skb_head->data_len += len; |
| 438 | − ctx->skb_head->truesize += packet_buffer_size; | |
| 438 | + ctx->skb_head->truesize += truesize; | |
| 439 | 439 | } |
| 440 | 440 | skb_add_rx_frag(skb, num_frags, page_info->page, |
| 441 | − offset, len, packet_buffer_size); | |
| 441 | + offset, len, truesize); | |
| 442 | 442 | |
| 443 | 443 | return ctx->skb_head; |
| 444 | 444 | } |
| @@ -532,7 +532,7 @@ static struct sk_buff *gve_rx_copy_to_pool(struct gve_rx_ring *rx, · 87 unmodified lines | ||
| 532 | 532 | |
| 533 | 533 | memcpy(alloc_page_info.page_address, src, page_info->pad + len); |
| 534 | 534 | skb = gve_rx_add_frags(napi, &alloc_page_info, |
| 535 | − rx->packet_buffer_size, | |
| 535 | + PAGE_SIZE, | |
| 536 | 536 | len, ctx); |
| 537 | 537 | |
| 538 | 538 | u64_stats_update_begin(&rx->statss); |
| @@ -360,23 +360,43 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca); · 359 unmodified lines | ||
| 360 | 360 | * As a result, a shift of INCVALUE_SHIFT_n is used to fit a value of |
| 361 | 361 | * INCVALUE_n into the TIMINCA register allowing 32+8+(24-INCVALUE_SHIFT_n) |
| 362 | 362 | * bits to count nanoseconds leaving the rest for fractional nonseconds. |
| 363 | + * | |
| 364 | + * Any given INCVALUE also has an associated maximum adjustment value. This | |
| 365 | + * maximum adjustment value is the largest increase (or decrease) which can be | |
| 366 | + * safely applied without overflowing the INCVALUE. Since INCVALUE has | |
| 367 | + * a maximum range of 24 bits, its largest value is 0xFFFFFF. | |
| 368 | + * | |
| 369 | + * To understand where the maximum value comes from, consider the following | |
| 370 | + * equation: | |
| 371 | + * | |
| 372 | + * new_incval = base_incval + (base_incval * adjustment) / 1billion | |
| 373 | + * | |
| 374 | + * To avoid overflow that means: | |
| 375 | + * max_incval = base_incval + (base_incval * max_adj) / billion | |
| 376 | + * | |
| 377 | + * Re-arranging: | |
| 378 | + * max_adj = floor(((max_incval - base_incval) * 1billion) / 1billion) | |
| 363 | 379 | */ |
| 364 | 380 | #define INCVALUE_96MHZ 125 |
| 365 | 381 | #define INCVALUE_SHIFT_96MHZ 17 |
| 366 | 382 | #define INCPERIOD_SHIFT_96MHZ 2 |
| 367 | 383 | #define INCPERIOD_96MHZ (12 >> INCPERIOD_SHIFT_96MHZ) |
| 384 | +#define MAX_PPB_96MHZ 23999900 /* 23,999,900 ppb */ | |
| 368 | 385 | |
| 369 | 386 | #define INCVALUE_25MHZ 40 |
| 370 | 387 | #define INCVALUE_SHIFT_25MHZ 18 |
| 371 | 388 | #define INCPERIOD_25MHZ 1 |
| 389 | +#define MAX_PPB_25MHZ 599999900 /* 599,999,900 ppb */ | |
| 372 | 390 | |
| 373 | 391 | #define INCVALUE_24MHZ 125 |
| 374 | 392 | #define INCVALUE_SHIFT_24MHZ 14 |
| 375 | 393 | #define INCPERIOD_24MHZ 3 |
| 394 | +#define MAX_PPB_24MHZ 999999999 /* 999,999,999 ppb */ | |
| 376 | 395 | |
| 377 | 396 | #define INCVALUE_38400KHZ 26 |
| 378 | 397 | #define INCVALUE_SHIFT_38400KHZ 19 |
| 379 | 398 | #define INCPERIOD_38400KHZ 1 |
| 399 | +#define MAX_PPB_38400KHZ 230769100 /* 230,769,100 ppb */ | |
| 380 | 400 | |
| 381 | 401 | /* Another drawback of scaling the incvalue by a large factor is the |
| 382 | 402 | * 64-bit SYSTIM register overflows more quickly. This is dealt with |
| @@ -280,8 +280,17 @@ void e1000e_ptp_init(struct e1000_adapter *adapter) · 279 unmodified lines | ||
| 280 | 280 | |
| 281 | 281 | switch (hw->mac.type) { |
| 282 | 282 | case e1000_pch2lan: |
| 283 | + adapter->ptp_clock_info.max_adj = MAX_PPB_96MHZ; | |
| 284 | + break; | |
| 283 | 285 | case e1000_pch_lpt: |
| 286 | + if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) | |
| 287 | + adapter->ptp_clock_info.max_adj = MAX_PPB_96MHZ; | |
| 288 | + else | |
| 289 | + adapter->ptp_clock_info.max_adj = MAX_PPB_25MHZ; | |
| 290 | + break; | |
| 284 | 291 | case e1000_pch_spt: |
| 292 | + adapter->ptp_clock_info.max_adj = MAX_PPB_24MHZ; | |
| 293 | + break; | |
| 285 | 294 | case e1000_pch_cnp: |
| 286 | 295 | case e1000_pch_tgp: |
| 287 | 296 | case e1000_pch_adp: |
| @@ -289,15 +298,14 @@ void e1000e_ptp_init(struct e1000_adapter *adapter) · 1 unmodified line | ||
| 289 | 298 | case e1000_pch_lnp: |
| 290 | 299 | case e1000_pch_ptp: |
| 291 | 300 | case e1000_pch_nvp: |
| 292 | − if ((hw->mac.type < e1000_pch_lpt) || | |
| 293 | − (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) { | |
| 294 | − adapter->ptp_clock_info.max_adj = 24000000 - 1; | |
| 295 | − break; | |
| 296 | − } | |
| 297 | − fallthrough; | |
| 301 | + if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) | |
| 302 | + adapter->ptp_clock_info.max_adj = MAX_PPB_24MHZ; | |
| 303 | + else | |
| 304 | + adapter->ptp_clock_info.max_adj = MAX_PPB_38400KHZ; | |
| 305 | + break; | |
| 298 | 306 | case e1000_82574: |
| 299 | 307 | case e1000_82583: |
| 300 | − adapter->ptp_clock_info.max_adj = 600000000 - 1; | |
| 308 | + adapter->ptp_clock_info.max_adj = MAX_PPB_25MHZ; | |
| 301 | 309 | break; |
| 302 | 310 | default: |
| 303 | 311 | break; |
| @@ -978,7 +978,7 @@ struct virtchnl2_ptype { · 977 unmodified lines | ||
| 978 | 978 | u8 proto_id_count; |
| 979 | 979 | __le16 pad; |
| 980 | 980 | __le16 proto_id[]; |
| 981 | −}; | |
| 981 | +} __packed __aligned(2); | |
| 982 | 982 | VIRTCHNL2_CHECK_STRUCT_LEN(6, virtchnl2_ptype); |
| 983 | 983 | |
| 984 | 984 | /** |
| @@ -716,7 +716,8 @@ static s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, · 715 unmodified lines | ||
| 716 | 716 | if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) { |
| 717 | 717 | error = FIELD_GET(IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK, command); |
| 718 | 718 | hw_dbg(hw, "Failed to read, error %x\n", error); |
| 719 | − return -EIO; | |
| 719 | + ret = -EIO; | |
| 720 | + goto out; | |
| 720 | 721 | } |
| 721 | 722 | |
| 722 | 723 | if (!ret) |
| @@ -314,7 +314,6 @@ static int otx2_set_channels(struct net_device *dev, · 313 unmodified lines | ||
| 314 | 314 | pfvf->hw.tx_queues = channel->tx_count; |
| 315 | 315 | if (pfvf->xdp_prog) |
| 316 | 316 | pfvf->hw.xdp_queues = channel->rx_count; |
| 317 | − pfvf->hw.non_qos_queues = pfvf->hw.tx_queues + pfvf->hw.xdp_queues; | |
| 318 | 317 | |
| 319 | 318 | if (if_up) |
| 320 | 319 | err = dev->netdev_ops->ndo_open(dev); |
| @@ -1744,6 +1744,7 @@ int otx2_open(struct net_device *netdev) · 1743 unmodified lines | ||
| 1744 | 1744 | /* RQ and SQs are mapped to different CQs, |
| 1745 | 1745 | * so find out max CQ IRQs (i.e CINTs) needed. |
| 1746 | 1746 | */ |
| 1747 | + pf->hw.non_qos_queues = pf->hw.tx_queues + pf->hw.xdp_queues; | |
| 1747 | 1748 | pf->hw.cint_cnt = max3(pf->hw.rx_queues, pf->hw.tx_queues, |
| 1748 | 1749 | pf->hw.tc_tx_queues); |
| 1749 | 1750 | |
| @@ -2643,8 +2644,6 @@ static int otx2_xdp_setup(struct otx2_nic *pf, struct bpf_prog *prog) · 893 unmodified lines | ||
| 2643 | 2644 | xdp_features_clear_redirect_target(dev); |
| 2644 | 2645 | } |
| 2645 | 2646 | |
| 2646 | − pf->hw.non_qos_queues += pf->hw.xdp_queues; | |
| 2647 | − | |
| 2648 | 2647 | if (if_up) |
| 2649 | 2648 | otx2_open(pf->netdev); |
| 2650 | 2649 | |
| @@ -1403,7 +1403,7 @@ static bool otx2_xdp_rcv_pkt_handler(struct otx2_nic *pfvf, · 1402 unmodified lines | ||
| 1403 | 1403 | struct otx2_cq_queue *cq, |
| 1404 | 1404 | bool *need_xdp_flush) |
| 1405 | 1405 | { |
| 1406 | − unsigned char *hard_start, *data; | |
| 1406 | + unsigned char *hard_start; | |
| 1407 | 1407 | int qidx = cq->cq_idx; |
| 1408 | 1408 | struct xdp_buff xdp; |
| 1409 | 1409 | struct page *page; |
| @@ -1417,9 +1417,8 @@ static bool otx2_xdp_rcv_pkt_handler(struct otx2_nic *pfvf, · 7 unmodified lines | ||
| 1417 | 1417 | |
| 1418 | 1418 | xdp_init_buff(&xdp, pfvf->rbsize, &cq->xdp_rxq); |
| 1419 | 1419 | |
| 1420 | − data = (unsigned char *)phys_to_virt(pa); | |
| 1421 | − hard_start = page_address(page); | |
| 1422 | − xdp_prepare_buff(&xdp, hard_start, data - hard_start, | |
| 1420 | + hard_start = (unsigned char *)phys_to_virt(pa); | |
| 1421 | + xdp_prepare_buff(&xdp, hard_start, OTX2_HEAD_ROOM, | |
| 1423 | 1422 | cqe->sg.seg_size, false); |
| 1424 | 1423 | |
| 1425 | 1424 | act = bpf_prog_run_xdp(prog, &xdp); |
| @@ -4761,7 +4761,10 @@ static int mtk_probe(struct platform_device *pdev) · 4760 unmodified lines | ||
| 4761 | 4761 | } |
| 4762 | 4762 | |
| 4763 | 4763 | if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA)) { |
| 4764 | − err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36)); | |
| 4764 | + err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(36)); | |
| 4765 | + if (!err) | |
| 4766 | + err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); | |
| 4767 | + | |
| 4765 | 4768 | if (err) { |
| 4766 | 4769 | dev_err(&pdev->dev, "Wrong DMA config\n"); |
| 4767 | 4770 | return -EINVAL; |
| @@ -168,9 +168,10 @@ static void lan966x_port_link_up(struct lan966x_port *port) · 167 unmodified lines | ||
| 168 | 168 | lan966x_taprio_speed_set(port, config->speed); |
| 169 | 169 | |
| 170 | 170 | /* Also the GIGA_MODE_ENA(1) needs to be set regardless of the |
| 171 | − * port speed for QSGMII ports. | |
| 171 | + * port speed for QSGMII or SGMII ports. | |
| 172 | 172 | */ |
| 173 | − if (phy_interface_num_ports(config->portmode) == 4) | |
| 173 | + if (phy_interface_num_ports(config->portmode) == 4 || | |
| 174 | + config->portmode == PHY_INTERFACE_MODE_SGMII) | |
| 174 | 175 | mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA_SET(1); |
| 175 | 176 | |
| 176 | 177 | lan_wr(config->duplex | mode, |
| @@ -1424,10 +1424,30 @@ static void nfp_nft_ct_translate_mangle_action(struct flow_action_entry *mangle_ · 1423 unmodified lines | ||
| 1424 | 1424 | mangle_action->mangle.mask = (__force u32)cpu_to_be32(mangle_action->mangle.mask); |
| 1425 | 1425 | return; |
| 1426 | 1426 | |
| 1427 | + /* Both struct tcphdr and struct udphdr start with | |
| 1428 | + * __be16 source; | |
| 1429 | + * __be16 dest; | |
| 1430 | + * so we can use the same code for both. | |
| 1431 | + */ | |
| 1427 | 1432 | case FLOW_ACT_MANGLE_HDR_TYPE_TCP: |
| 1428 | 1433 | case FLOW_ACT_MANGLE_HDR_TYPE_UDP: |
| 1429 | − mangle_action->mangle.val = (__force u16)cpu_to_be16(mangle_action->mangle.val); | |
| 1430 | − mangle_action->mangle.mask = (__force u16)cpu_to_be16(mangle_action->mangle.mask); | |
| 1434 | + if (mangle_action->mangle.offset == offsetof(struct tcphdr, source)) { | |
| 1435 | + mangle_action->mangle.val = | |
| 1436 | + (__force u32)cpu_to_be32(mangle_action->mangle.val << 16); | |
| 1437 | + /* The mask of mangle action is inverse mask, | |
| 1438 | + * so clear the dest tp port with 0xFFFF to | |
| 1439 | + * instead of rotate-left operation. | |
| 1440 | + */ | |
| 1441 | + mangle_action->mangle.mask = | |
| 1442 | + (__force u32)cpu_to_be32(mangle_action->mangle.mask << 16 | 0xFFFF); | |
| 1443 | + } | |
| 1444 | + if (mangle_action->mangle.offset == offsetof(struct tcphdr, dest)) { | |
| 1445 | + mangle_action->mangle.offset = 0; | |
| 1446 | + mangle_action->mangle.val = | |
| 1447 | + (__force u32)cpu_to_be32(mangle_action->mangle.val); | |
| 1448 | + mangle_action->mangle.mask = | |
| 1449 | + (__force u32)cpu_to_be32(mangle_action->mangle.mask); | |
| 1450 | + } | |
| 1431 | 1451 | return; |
| 1432 | 1452 | |
| 1433 | 1453 | default: |
| @@ -1864,10 +1884,30 @@ int nfp_fl_ct_handle_post_ct(struct nfp_flower_priv *priv, · 430 unmodified lines | ||
| 1864 | 1884 | { |
| 1865 | 1885 | struct flow_rule *rule = flow_cls_offload_flow_rule(flow); |
| 1866 | 1886 | struct nfp_fl_ct_flow_entry *ct_entry; |
| 1887 | + struct flow_action_entry *ct_goto; | |
| 1867 | 1888 | struct nfp_fl_ct_zone_entry *zt; |
| 1889 | + struct flow_action_entry *act; | |
| 1868 | 1890 | bool wildcarded = false; |
| 1869 | 1891 | struct flow_match_ct ct; |
| 1870 | − struct flow_action_entry *ct_goto; | |
| 1892 | + int i; | |
| 1893 | + | |
| 1894 | + flow_action_for_each(i, act, &rule->action) { | |
| 1895 | + switch (act->id) { | |
| 1896 | + case FLOW_ACTION_REDIRECT: | |
| 1897 | + case FLOW_ACTION_REDIRECT_INGRESS: | |
| 1898 | + case FLOW_ACTION_MIRRED: | |
| 1899 | + case FLOW_ACTION_MIRRED_INGRESS: | |
| 1900 | + if (act->dev->rtnl_link_ops && | |
| 1901 | + !strcmp(act->dev->rtnl_link_ops->kind, "openvswitch")) { | |
| 1902 | + NL_SET_ERR_MSG_MOD(extack, | |
| 1903 | + "unsupported offload: out port is openvswitch internal port"); | |
| 1904 | + return -EOPNOTSUPP; | |
| 1905 | + } | |
| 1906 | + break; | |
| 1907 | + default: | |
| 1908 | + break; | |
| 1909 | + } | |
| 1910 | + } | |
| 1871 | 1911 | |
| 1872 | 1912 | flow_rule_match_ct(rule, &ct); |
| 1873 | 1913 | if (!ct.mask->ct_zone) { |
| @@ -353,6 +353,10 @@ static int imx_dwmac_probe(struct platform_device *pdev) · 352 unmodified lines | ||
| 353 | 353 | if (data->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY) |
| 354 | 354 | plat_dat->flags |= STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY; |
| 355 | 355 | |
| 356 | + /* Default TX Q0 to use TSO and rest TXQ for TBS */ | |
| 357 | + for (int i = 1; i < plat_dat->tx_queues_to_use; i++) | |
| 358 | + plat_dat->tx_queues_cfg[i].tbs_en = 1; | |
| 359 | + | |
| 356 | 360 | plat_dat->host_dma_width = dwmac->ops->addr_width; |
| 357 | 361 | plat_dat->init = imx_dwmac_init; |
| 358 | 362 | plat_dat->exit = imx_dwmac_exit; |
| @@ -3939,6 +3939,9 @@ static int __stmmac_open(struct net_device *dev, · 3938 unmodified lines | ||
| 3939 | 3939 | priv->rx_copybreak = STMMAC_RX_COPYBREAK; |
| 3940 | 3940 | |
| 3941 | 3941 | buf_sz = dma_conf->dma_buf_sz; |
| 3942 | + for (int i = 0; i < MTL_MAX_TX_QUEUES; i++) | |
| 3943 | + if (priv->dma_conf.tx_queue[i].tbs & STMMAC_TBS_EN) | |
| 3944 | + dma_conf->tx_queue[i].tbs = priv->dma_conf.tx_queue[i].tbs; | |
| 3942 | 3945 | memcpy(&priv->dma_conf, dma_conf, sizeof(*dma_conf)); |
| 3943 | 3946 | |
| 3944 | 3947 | stmmac_reset_queues_param(priv); |
| @@ -708,7 +708,10 @@ void netvsc_device_remove(struct hv_device *device) · 707 unmodified lines | ||
| 708 | 708 | /* Disable NAPI and disassociate its context from the device. */ |
| 709 | 709 | for (i = 0; i < net_device->num_chn; i++) { |
| 710 | 710 | /* See also vmbus_reset_channel_cb(). */ |
| 711 | − napi_disable(&net_device->chan_table[i].napi); | |
| 711 | + /* only disable enabled NAPI channel */ | |
| 712 | + if (i < ndev->real_num_rx_queues) | |
| 713 | + napi_disable(&net_device->chan_table[i].napi); | |
| 714 | + | |
| 712 | 715 | netif_napi_del(&net_device->chan_table[i].napi); |
| 713 | 716 | } |
| 714 | 717 | |
| @@ -489,7 +489,7 @@ static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val, · 488 unmodified lines | ||
| 489 | 489 | u16 reg, val; |
| 490 | 490 | |
| 491 | 491 | if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988) |
| 492 | − bias = -2; | |
| 492 | + bias = -1; | |
| 493 | 493 | |
| 494 | 494 | val = clamp_val(bias + tx_r50_cal_val, 0, 63); |
| 495 | 495 | |
| @@ -705,6 +705,11 @@ restore: · 209 unmodified lines | ||
| 705 | 705 | static void mt798x_phy_common_finetune(struct phy_device *phydev) |
| 706 | 706 | { |
| 707 | 707 | phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); |
| 708 | + /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */ | |
| 709 | + __phy_write(phydev, 0x11, 0xc71); | |
| 710 | + __phy_write(phydev, 0x12, 0xc); | |
| 711 | + __phy_write(phydev, 0x10, 0x8fae); | |
| 712 | + | |
| 708 | 713 | /* EnabRandUpdTrig = 1 */ |
| 709 | 714 | __phy_write(phydev, 0x11, 0x2f00); |
| 710 | 715 | __phy_write(phydev, 0x12, 0xe); |
| @@ -715,15 +720,56 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev) · 4 unmodified lines | ||
| 715 | 720 | __phy_write(phydev, 0x12, 0x0); |
| 716 | 721 | __phy_write(phydev, 0x10, 0x83aa); |
| 717 | 722 | |
| 718 | − /* TrFreeze = 0 */ | |
| 723 | + /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */ | |
| 724 | + __phy_write(phydev, 0x11, 0x240); | |
| 725 | + __phy_write(phydev, 0x12, 0x0); | |
| 726 | + __phy_write(phydev, 0x10, 0x9680); | |
| 727 | + | |
| 728 | + /* TrFreeze = 0 (mt7988 default) */ | |
| 719 | 729 | __phy_write(phydev, 0x11, 0x0); |
| 720 | 730 | __phy_write(phydev, 0x12, 0x0); |
| 721 | 731 | __phy_write(phydev, 0x10, 0x9686); |
| 722 | 732 | |
| 733 | + /* SSTrKp100 = 5 */ | |
| 734 | + /* SSTrKf100 = 6 */ | |
| 735 | + /* SSTrKp1000Mas = 5 */ | |
| 736 | + /* SSTrKf1000Mas = 6 */ | |
| 723 | 737 | /* SSTrKp1000Slv = 5 */ |
| 738 | + /* SSTrKf1000Slv = 6 */ | |
| 724 | 739 | __phy_write(phydev, 0x11, 0xbaef); |
| 725 | 740 | __phy_write(phydev, 0x12, 0x2e); |
| 726 | 741 | __phy_write(phydev, 0x10, 0x968c); |
| 742 | + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); | |
| 743 | +} | |
| 744 | + | |
| 745 | +static void mt7981_phy_finetune(struct phy_device *phydev) | |
| 746 | +{ | |
| 747 | + u16 val[8] = { 0x01ce, 0x01c1, | |
| 748 | + 0x020f, 0x0202, | |
| 749 | + 0x03d0, 0x03c0, | |
| 750 | + 0x0013, 0x0005 }; | |
| 751 | + int i, k; | |
| 752 | + | |
| 753 | + /* 100M eye finetune: | |
| 754 | + * Keep middle level of TX MLT3 shapper as default. | |
| 755 | + * Only change TX MLT3 overshoot level here. | |
| 756 | + */ | |
| 757 | + for (k = 0, i = 1; i < 12; i++) { | |
| 758 | + if (i % 3 == 0) | |
| 759 | + continue; | |
| 760 | + phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]); | |
| 761 | + } | |
| 762 | + | |
| 763 | + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); | |
| 764 | + /* ResetSyncOffset = 6 */ | |
| 765 | + __phy_write(phydev, 0x11, 0x600); | |
| 766 | + __phy_write(phydev, 0x12, 0x0); | |
| 767 | + __phy_write(phydev, 0x10, 0x8fc0); | |
| 768 | + | |
| 769 | + /* VgaDecRate = 1 */ | |
| 770 | + __phy_write(phydev, 0x11, 0x4c2a); | |
| 771 | + __phy_write(phydev, 0x12, 0x3e); | |
| 772 | + __phy_write(phydev, 0x10, 0x8fa4); | |
| 727 | 773 | |
| 728 | 774 | /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2, |
| 729 | 775 | * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2 |
| @@ -738,7 +784,7 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev) · 8 unmodified lines | ||
| 738 | 784 | __phy_write(phydev, 0x10, 0x8ec0); |
| 739 | 785 | phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); |
| 740 | 786 | |
| 741 | − /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9*/ | |
| 787 | + /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */ | |
| 742 | 788 | phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, |
| 743 | 789 | MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK, |
| 744 | 790 | BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9)); |
| @@ -771,48 +817,6 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev) · 26 unmodified lines | ||
| 771 | 817 | phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222); |
| 772 | 818 | } |
| 773 | 819 | |
| 774 | −static void mt7981_phy_finetune(struct phy_device *phydev) | |
| 775 | −{ | |
| 776 | − u16 val[8] = { 0x01ce, 0x01c1, | |
| 777 | − 0x020f, 0x0202, | |
| 778 | − 0x03d0, 0x03c0, | |
| 779 | − 0x0013, 0x0005 }; | |
| 780 | − int i, k; | |
| 781 | − | |
| 782 | − /* 100M eye finetune: | |
| 783 | − * Keep middle level of TX MLT3 shapper as default. | |
| 784 | − * Only change TX MLT3 overshoot level here. | |
| 785 | − */ | |
| 786 | − for (k = 0, i = 1; i < 12; i++) { | |
| 787 | − if (i % 3 == 0) | |
| 788 | − continue; | |
| 789 | − phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]); | |
| 790 | − } | |
| 791 | − | |
| 792 | − phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); | |
| 793 | − /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */ | |
| 794 | − __phy_write(phydev, 0x11, 0xc71); | |
| 795 | − __phy_write(phydev, 0x12, 0xc); | |
| 796 | − __phy_write(phydev, 0x10, 0x8fae); | |
| 797 | − | |
| 798 | − /* ResetSyncOffset = 6 */ | |
| 799 | − __phy_write(phydev, 0x11, 0x600); | |
| 800 | − __phy_write(phydev, 0x12, 0x0); | |
| 801 | − __phy_write(phydev, 0x10, 0x8fc0); | |
| 802 | − | |
| 803 | − /* VgaDecRate = 1 */ | |
| 804 | − __phy_write(phydev, 0x11, 0x4c2a); | |
| 805 | − __phy_write(phydev, 0x12, 0x3e); | |
| 806 | − __phy_write(phydev, 0x10, 0x8fa4); | |
| 807 | − | |
| 808 | − /* FfeUpdGainForce = 4 */ | |
| 809 | − __phy_write(phydev, 0x11, 0x240); | |
| 810 | − __phy_write(phydev, 0x12, 0x0); | |
| 811 | − __phy_write(phydev, 0x10, 0x9680); | |
| 812 | − | |
| 813 | − phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); | |
| 814 | −} | |
| 815 | − | |
| 816 | 820 | static void mt7988_phy_finetune(struct phy_device *phydev) |
| 817 | 821 | { |
| 818 | 822 | u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182, |
| @@ -827,17 +831,7 @@ static void mt7988_phy_finetune(struct phy_device *phydev) · 8 unmodified lines | ||
| 827 | 831 | /* TCT finetune */ |
| 828 | 832 | phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5); |
| 829 | 833 | |
| 830 | − /* Disable TX power saving */ | |
| 831 | − phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7, | |
| 832 | − MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8); | |
| 833 | − | |
| 834 | 834 | phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); |
| 835 | − | |
| 836 | − /* SlvDSPreadyTime = 24, MasDSPreadyTime = 12 */ | |
| 837 | − __phy_write(phydev, 0x11, 0x671); | |
| 838 | − __phy_write(phydev, 0x12, 0xc); | |
| 839 | − __phy_write(phydev, 0x10, 0x8fae); | |
| 840 | − | |
| 841 | 835 | /* ResetSyncOffset = 5 */ |
| 842 | 836 | __phy_write(phydev, 0x11, 0x500); |
| 843 | 837 | __phy_write(phydev, 0x12, 0x0); |
| @@ -845,13 +839,27 @@ static void mt7988_phy_finetune(struct phy_device *phydev) · 1 unmodified line | ||
| 845 | 839 | |
| 846 | 840 | /* VgaDecRate is 1 at default on mt7988 */ |
| 847 | 841 | |
| 848 | − phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); | |
| 842 | + /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7, | |
| 843 | + * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7 | |
| 844 | + */ | |
| 845 | + __phy_write(phydev, 0x11, 0xb90a); | |
| 846 | + __phy_write(phydev, 0x12, 0x6f); | |
| 847 | + __phy_write(phydev, 0x10, 0x8f82); | |
| 848 | + | |
| 849 | + /* RemAckCntLimitCtrl = 1 */ | |
| 850 | + __phy_write(phydev, 0x11, 0xfbba); | |
| 851 | + __phy_write(phydev, 0x12, 0xc3); | |
| 852 | + __phy_write(phydev, 0x10, 0x87f8); | |
| 849 | 853 | |
| 850 | − phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_2A30); | |
| 851 | − /* TxClkOffset = 2 */ | |
| 852 | − __phy_modify(phydev, MTK_PHY_ANARG_RG, MTK_PHY_TCLKOFFSET_MASK, | |
| 853 | − FIELD_PREP(MTK_PHY_TCLKOFFSET_MASK, 0x2)); | |
| 854 | 854 | phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); |
| 855 | + | |
| 856 | + /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */ | |
| 857 | + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, | |
| 858 | + MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK, | |
| 859 | + BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa)); | |
| 860 | + | |
| 861 | + /* rg_tr_lpf_cnt_val = 1023 */ | |
| 862 | + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff); | |
| 855 | 863 | } |
| 856 | 864 | |
| 857 | 865 | static void mt798x_phy_eee(struct phy_device *phydev) |
| @@ -884,11 +892,11 @@ static void mt798x_phy_eee(struct phy_device *phydev) · 26 unmodified lines | ||
| 884 | 892 | MTK_PHY_LPI_SLV_SEND_TX_EN, |
| 885 | 893 | FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120)); |
| 886 | 894 | |
| 887 | − phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239, | |
| 888 | − MTK_PHY_LPI_SEND_LOC_TIMER_MASK | | |
| 889 | − MTK_PHY_LPI_TXPCS_LOC_RCV, | |
| 890 | − FIELD_PREP(MTK_PHY_LPI_SEND_LOC_TIMER_MASK, 0x117)); | |
| 895 | + /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */ | |
| 896 | + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239, | |
| 897 | + MTK_PHY_LPI_TXPCS_LOC_RCV); | |
| 891 | 898 | |
| 899 | + /* This also fixes some IoT issues, such as CH340 */ | |
| 892 | 900 | phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7, |
| 893 | 901 | MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK, |
| 894 | 902 | FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) | |
| @@ -922,7 +930,7 @@ static void mt798x_phy_eee(struct phy_device *phydev) · 27 unmodified lines | ||
| 922 | 930 | __phy_write(phydev, 0x12, 0x0); |
| 923 | 931 | __phy_write(phydev, 0x10, 0x9690); |
| 924 | 932 | |
| 925 | − /* REG_EEE_st2TrKf1000 = 3 */ | |
| 933 | + /* REG_EEE_st2TrKf1000 = 2 */ | |
| 926 | 934 | __phy_write(phydev, 0x11, 0x114f); |
| 927 | 935 | __phy_write(phydev, 0x12, 0x2); |
| 928 | 936 | __phy_write(phydev, 0x10, 0x969a); |
| @@ -947,7 +955,7 @@ static void mt798x_phy_eee(struct phy_device *phydev) · 18 unmodified lines | ||
| 947 | 955 | __phy_write(phydev, 0x12, 0x0); |
| 948 | 956 | __phy_write(phydev, 0x10, 0x96b8); |
| 949 | 957 | |
| 950 | − /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 1 */ | |
| 958 | + /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */ | |
| 951 | 959 | __phy_write(phydev, 0x11, 0x1463); |
| 952 | 960 | __phy_write(phydev, 0x12, 0x0); |
| 953 | 961 | __phy_write(phydev, 0x10, 0x96ca); |
| @@ -1459,6 +1467,13 @@ static int mt7988_phy_probe(struct phy_device *phydev) · 505 unmodified lines | ||
| 1459 | 1467 | if (err) |
| 1460 | 1468 | return err; |
| 1461 | 1469 | |
| 1470 | + /* Disable TX power saving at probing to: | |
| 1471 | + * 1. Meet common mode compliance test criteria | |
| 1472 | + * 2. Make sure that TX-VCM calibration works fine | |
| 1473 | + */ | |
| 1474 | + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7, | |
| 1475 | + MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8); | |
| 1476 | + | |
| 1462 | 1477 | return mt798x_phy_calibration(phydev); |
| 1463 | 1478 | } |
| 1464 | 1479 | |
| @@ -104,13 +104,12 @@ bool provides_xdp_headroom = true; · 103 unmodified lines | ||
| 104 | 104 | module_param(provides_xdp_headroom, bool, 0644); |
| 105 | 105 | |
| 106 | 106 | static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx, |
| 107 | − u8 status); | |
| 107 | + s8 status); | |
| 108 | 108 | |
| 109 | 109 | static void make_tx_response(struct xenvif_queue *queue, |
| 110 | − struct xen_netif_tx_request *txp, | |
| 110 | + const struct xen_netif_tx_request *txp, | |
| 111 | 111 | unsigned int extra_count, |
| 112 | − s8 st); | |
| 113 | −static void push_tx_responses(struct xenvif_queue *queue); | |
| 112 | + s8 status); | |
| 114 | 113 | |
| 115 | 114 | static void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx); |
| 116 | 115 | |
| @@ -208,13 +207,9 @@ static void xenvif_tx_err(struct xenvif_queue *queue, · 91 unmodified lines | ||
| 208 | 207 | unsigned int extra_count, RING_IDX end) |
| 209 | 208 | { |
| 210 | 209 | RING_IDX cons = queue->tx.req_cons; |
| 211 | − unsigned long flags; | |
| 212 | 210 | |
| 213 | 211 | do { |
| 214 | − spin_lock_irqsave(&queue->response_lock, flags); | |
| 215 | 212 | make_tx_response(queue, txp, extra_count, XEN_NETIF_RSP_ERROR); |
| 216 | − push_tx_responses(queue); | |
| 217 | − spin_unlock_irqrestore(&queue->response_lock, flags); | |
| 218 | 213 | if (cons == end) |
| 219 | 214 | break; |
| 220 | 215 | RING_COPY_REQUEST(&queue->tx, cons++, txp); |
| @@ -465,12 +460,7 @@ static void xenvif_get_requests(struct xenvif_queue *queue, · 244 unmodified lines | ||
| 465 | 460 | for (shinfo->nr_frags = 0; nr_slots > 0 && shinfo->nr_frags < MAX_SKB_FRAGS; |
| 466 | 461 | nr_slots--) { |
| 467 | 462 | if (unlikely(!txp->size)) { |
| 468 | − unsigned long flags; | |
| 469 | − | |
| 470 | − spin_lock_irqsave(&queue->response_lock, flags); | |
| 471 | 463 | make_tx_response(queue, txp, 0, XEN_NETIF_RSP_OKAY); |
| 472 | − push_tx_responses(queue); | |
| 473 | − spin_unlock_irqrestore(&queue->response_lock, flags); | |
| 474 | 464 | ++txp; |
| 475 | 465 | continue; |
| 476 | 466 | } |
| @@ -496,14 +486,8 @@ static void xenvif_get_requests(struct xenvif_queue *queue, · 19 unmodified lines | ||
| 496 | 486 | |
| 497 | 487 | for (shinfo->nr_frags = 0; shinfo->nr_frags < nr_slots; ++txp) { |
| 498 | 488 | if (unlikely(!txp->size)) { |
| 499 | − unsigned long flags; | |
| 500 | − | |
| 501 | − spin_lock_irqsave(&queue->response_lock, flags); | |
| 502 | 489 | make_tx_response(queue, txp, 0, |
| 503 | 490 | XEN_NETIF_RSP_OKAY); |
| 504 | − push_tx_responses(queue); | |
| 505 | − spin_unlock_irqrestore(&queue->response_lock, | |
| 506 | − flags); | |
| 507 | 491 | continue; |
| 508 | 492 | } |
| 509 | 493 | |
| @@ -995,7 +979,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, · 485 unmodified lines | ||
| 995 | 979 | (ret == 0) ? |
| 996 | 980 | XEN_NETIF_RSP_OKAY : |
| 997 | 981 | XEN_NETIF_RSP_ERROR); |
| 998 | − push_tx_responses(queue); | |
| 999 | 982 | continue; |
| 1000 | 983 | } |
| 1001 | 984 | |
| @@ -1007,7 +990,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, · 5 unmodified lines | ||
| 1007 | 990 | |
| 1008 | 991 | make_tx_response(queue, &txreq, extra_count, |
| 1009 | 992 | XEN_NETIF_RSP_OKAY); |
| 1010 | − push_tx_responses(queue); | |
| 1011 | 993 | continue; |
| 1012 | 994 | } |
| 1013 | 995 | |
| @@ -1433,8 +1415,35 @@ int xenvif_tx_action(struct xenvif_queue *queue, int budget) · 419 unmodified lines | ||
| 1433 | 1415 | return work_done; |
| 1434 | 1416 | } |
| 1435 | 1417 | |
| 1418 | +static void _make_tx_response(struct xenvif_queue *queue, | |
| 1419 | + const struct xen_netif_tx_request *txp, | |
| 1420 | + unsigned int extra_count, | |
| 1421 | + s8 status) | |
| 1422 | +{ | |
| 1423 | + RING_IDX i = queue->tx.rsp_prod_pvt; | |
| 1424 | + struct xen_netif_tx_response *resp; | |
| 1425 | + | |
| 1426 | + resp = RING_GET_RESPONSE(&queue->tx, i); | |
| 1427 | + resp->id = txp->id; | |
| 1428 | + resp->status = status; | |
| 1429 | + | |
| 1430 | + while (extra_count-- != 0) | |
| 1431 | + RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL; | |
| 1432 | + | |
| 1433 | + queue->tx.rsp_prod_pvt = ++i; | |
| 1434 | +} | |
| 1435 | + | |
| 1436 | +static void push_tx_responses(struct xenvif_queue *queue) | |
| 1437 | +{ | |
| 1438 | + int notify; | |
| 1439 | + | |
| 1440 | + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify); | |
| 1441 | + if (notify) | |
| 1442 | + notify_remote_via_irq(queue->tx_irq); | |
| 1443 | +} | |
| 1444 | + | |
| 1436 | 1445 | static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx, |
| 1437 | − u8 status) | |
| 1446 | + s8 status) | |
| 1438 | 1447 | { |
| 1439 | 1448 | struct pending_tx_info *pending_tx_info; |
| 1440 | 1449 | pending_ring_idx_t index; |
| @@ -1444,8 +1453,8 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx, · 3 unmodified lines | ||
| 1444 | 1453 | |
| 1445 | 1454 | spin_lock_irqsave(&queue->response_lock, flags); |
| 1446 | 1455 | |
| 1447 | − make_tx_response(queue, &pending_tx_info->req, | |
| 1448 | − pending_tx_info->extra_count, status); | |
| 1456 | + _make_tx_response(queue, &pending_tx_info->req, | |
| 1457 | + pending_tx_info->extra_count, status); | |
| 1449 | 1458 | |
| 1450 | 1459 | /* Release the pending index before pusing the Tx response so |
| 1451 | 1460 | * its available before a new Tx request is pushed by the |
| @@ -1459,32 +1468,19 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx, · 7 unmodified lines | ||
| 1459 | 1468 | spin_unlock_irqrestore(&queue->response_lock, flags); |
| 1460 | 1469 | } |
| 1461 | 1470 | |
| 1462 | − | |
| 1463 | 1471 | static void make_tx_response(struct xenvif_queue *queue, |
| 1464 | − struct xen_netif_tx_request *txp, | |
| 1472 | + const struct xen_netif_tx_request *txp, | |
| 1465 | 1473 | unsigned int extra_count, |
| 1466 | − s8 st) | |
| 1474 | + s8 status) | |
| 1467 | 1475 | { |
| 1468 | − RING_IDX i = queue->tx.rsp_prod_pvt; | |
| 1469 | − struct xen_netif_tx_response *resp; | |
| 1470 | − | |
| 1471 | − resp = RING_GET_RESPONSE(&queue->tx, i); | |
| 1472 | − resp->id = txp->id; | |
| 1473 | − resp->status = st; | |
| 1474 | − | |
| 1475 | − while (extra_count-- != 0) | |
| 1476 | − RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL; | |
| 1476 | + unsigned long flags; | |
| 1477 | 1477 | |
| 1478 | − queue->tx.rsp_prod_pvt = ++i; | |
| 1479 | −} | |
| 1478 | + spin_lock_irqsave(&queue->response_lock, flags); | |
| 1480 | 1479 | |
| 1481 | −static void push_tx_responses(struct xenvif_queue *queue) | |
| 1482 | −{ | |
| 1483 | − int notify; | |
| 1480 | + _make_tx_response(queue, txp, extra_count, status); | |
| 1481 | + push_tx_responses(queue); | |
| 1484 | 1482 | |
| 1485 | − RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify); | |
| 1486 | − if (notify) | |
| 1487 | − notify_remote_via_irq(queue->tx_irq); | |
| 1483 | + spin_unlock_irqrestore(&queue->response_lock, flags); | |
| 1488 | 1484 | } |
| 1489 | 1485 | |
| 1490 | 1486 | static void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx) |
| @@ -1170,7 +1170,7 @@ static int mlxbf_pmc_program_crspace_counter(int blk_num, uint32_t cnt_num, · 1169 unmodified lines | ||
| 1170 | 1170 | int ret; |
| 1171 | 1171 | |
| 1172 | 1172 | addr = pmc->block[blk_num].mmio_base + |
| 1173 | − (rounddown(cnt_num, 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ); | |
| 1173 | + ((cnt_num / 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ); | |
| 1174 | 1174 | ret = mlxbf_pmc_readl(addr, &word); |
| 1175 | 1175 | if (ret) |
| 1176 | 1176 | return ret; |
| @@ -1413,7 +1413,7 @@ static int mlxbf_pmc_read_crspace_event(int blk_num, uint32_t cnt_num, · 236 unmodified lines | ||
| 1413 | 1413 | int ret; |
| 1414 | 1414 | |
| 1415 | 1415 | addr = pmc->block[blk_num].mmio_base + |
| 1416 | − (rounddown(cnt_num, 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ); | |
| 1416 | + ((cnt_num / 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ); | |
| 1417 | 1417 | ret = mlxbf_pmc_readl(addr, &word); |
| 1418 | 1418 | if (ret) |
| 1419 | 1419 | return ret; |
| @@ -47,6 +47,9 @@ · 46 unmodified lines | ||
| 47 | 47 | /* Message with data needs at least two words (for header & data). */ |
| 48 | 48 | #define MLXBF_TMFIFO_DATA_MIN_WORDS 2 |
| 49 | 49 | |
| 50 | +/* Tx timeout in milliseconds. */ | |
| 51 | +#define TMFIFO_TX_TIMEOUT 2000 | |
| 52 | + | |
| 50 | 53 | /* ACPI UID for BlueField-3. */ |
| 51 | 54 | #define TMFIFO_BF3_UID 1 |
| 52 | 55 | |
| @@ -62,12 +65,14 @@ struct mlxbf_tmfifo; · 9 unmodified lines | ||
| 62 | 65 | * @drop_desc: dummy desc for packet dropping |
| 63 | 66 | * @cur_len: processed length of the current descriptor |
| 64 | 67 | * @rem_len: remaining length of the pending packet |
| 68 | + * @rem_padding: remaining bytes to send as paddings | |
| 65 | 69 | * @pkt_len: total length of the pending packet |
| 66 | 70 | * @next_avail: next avail descriptor id |
| 67 | 71 | * @num: vring size (number of descriptors) |
| 68 | 72 | * @align: vring alignment size |
| 69 | 73 | * @index: vring index |
| 70 | 74 | * @vdev_id: vring virtio id (VIRTIO_ID_xxx) |
| 75 | + * @tx_timeout: expire time of last tx packet | |
| 71 | 76 | * @fifo: pointer to the tmfifo structure |
| 72 | 77 | */ |
| 73 | 78 | struct mlxbf_tmfifo_vring { |
| @@ -79,12 +84,14 @@ struct mlxbf_tmfifo_vring { · 5 unmodified lines | ||
| 79 | 84 | struct vring_desc drop_desc; |
| 80 | 85 | int cur_len; |
| 81 | 86 | int rem_len; |
| 87 | + int rem_padding; | |
| 82 | 88 | u32 pkt_len; |
| 83 | 89 | u16 next_avail; |
| 84 | 90 | int num; |
| 85 | 91 | int align; |
| 86 | 92 | int index; |
| 87 | 93 | int vdev_id; |
| 94 | + unsigned long tx_timeout; | |
| 88 | 95 | struct mlxbf_tmfifo *fifo; |
| 89 | 96 | }; |
| 90 | 97 | |
| @@ -819,6 +826,50 @@ mlxbf_tmfifo_desc_done: · 728 unmodified lines | ||
| 819 | 826 | return true; |
| 820 | 827 | } |
| 821 | 828 | |
| 829 | +static void mlxbf_tmfifo_check_tx_timeout(struct mlxbf_tmfifo_vring *vring) | |
| 830 | +{ | |
| 831 | + unsigned long flags; | |
| 832 | + | |
| 833 | + /* Only handle Tx timeout for network vdev. */ | |
| 834 | + if (vring->vdev_id != VIRTIO_ID_NET) | |
| 835 | + return; | |
| 836 | + | |
| 837 | + /* Initialize the timeout or return if not expired. */ | |
| 838 | + if (!vring->tx_timeout) { | |
| 839 | + /* Initialize the timeout. */ | |
| 840 | + vring->tx_timeout = jiffies + | |
| 841 | + msecs_to_jiffies(TMFIFO_TX_TIMEOUT); | |
| 842 | + return; | |
| 843 | + } else if (time_before(jiffies, vring->tx_timeout)) { | |
| 844 | + /* Return if not timeout yet. */ | |
| 845 | + return; | |
| 846 | + } | |
| 847 | + | |
| 848 | + /* | |
| 849 | + * Drop the packet after timeout. The outstanding packet is | |
| 850 | + * released and the remaining bytes will be sent with padding byte 0x00 | |
| 851 | + * as a recovery. On the peer(host) side, the padding bytes 0x00 will be | |
| 852 | + * either dropped directly, or appended into existing outstanding packet | |
| 853 | + * thus dropped as corrupted network packet. | |
| 854 | + */ | |
| 855 | + vring->rem_padding = round_up(vring->rem_len, sizeof(u64)); | |
| 856 | + mlxbf_tmfifo_release_pkt(vring); | |
| 857 | + vring->cur_len = 0; | |
| 858 | + vring->rem_len = 0; | |
| 859 | + vring->fifo->vring[0] = NULL; | |
| 860 | + | |
| 861 | + /* | |
| 862 | + * Make sure the load/store are in order before | |
| 863 | + * returning back to virtio. | |
| 864 | + */ | |
| 865 | + virtio_mb(false); | |
| 866 | + | |
| 867 | + /* Notify upper layer. */ | |
| 868 | + spin_lock_irqsave(&vring->fifo->spin_lock[0], flags); | |
| 869 | + vring_interrupt(0, vring->vq); | |
| 870 | + spin_unlock_irqrestore(&vring->fifo->spin_lock[0], flags); | |
| 871 | +} | |
| 872 | + | |
| 822 | 873 | /* Rx & Tx processing of a queue. */ |
| 823 | 874 | static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx) |
| 824 | 875 | { |
| @@ -841,6 +892,7 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx) · 16 unmodified lines | ||
| 841 | 892 | return; |
| 842 | 893 | |
| 843 | 894 | do { |
| 895 | +retry: | |
| 844 | 896 | /* Get available FIFO space. */ |
| 845 | 897 | if (avail == 0) { |
| 846 | 898 | if (is_rx) |
| @@ -851,6 +903,17 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx) · 4 unmodified lines | ||
| 851 | 903 | break; |
| 852 | 904 | } |
| 853 | 905 | |
| 906 | + /* Insert paddings for discarded Tx packet. */ | |
| 907 | + if (!is_rx) { | |
| 908 | + vring->tx_timeout = 0; | |
| 909 | + while (vring->rem_padding >= sizeof(u64)) { | |
| 910 | + writeq(0, vring->fifo->tx.data); | |
| 911 | + vring->rem_padding -= sizeof(u64); | |
| 912 | + if (--avail == 0) | |
| 913 | + goto retry; | |
| 914 | + } | |
| 915 | + } | |
| 916 | + | |
| 854 | 917 | /* Console output always comes from the Tx buffer. */ |
| 855 | 918 | if (!is_rx && devid == VIRTIO_ID_CONSOLE) { |
| 856 | 919 | mlxbf_tmfifo_console_tx(fifo, avail); |
| @@ -860,6 +923,10 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx) · 3 unmodified lines | ||
| 860 | 923 | /* Handle one descriptor. */ |
| 861 | 924 | more = mlxbf_tmfifo_rxtx_one_desc(vring, is_rx, &avail); |
| 862 | 925 | } while (more); |
| 926 | + | |
| 927 | + /* Check Tx timeout. */ | |
| 928 | + if (avail <= 0 && !is_rx) | |
| 929 | + mlxbf_tmfifo_check_tx_timeout(vring); | |
| 863 | 930 | } |
| 864 | 931 | |
| 865 | 932 | /* Handle Rx or Tx queues. */ |
| @@ -10,6 +10,7 @@ config AMD_PMF · 9 unmodified lines | ||
| 10 | 10 | depends on AMD_NB |
| 11 | 11 | select ACPI_PLATFORM_PROFILE |
| 12 | 12 | depends on TEE && AMDTEE |
| 13 | + depends on AMD_SFH_HID | |
| 13 | 14 | help |
| 14 | 15 | This driver provides support for the AMD Platform Management Framework. |
| 15 | 16 | The goal is to enhance end user experience by making AMD PCs smarter, |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | 12 | #include <acpi/button.h> |
| 13 | +#include <linux/amd-pmf-io.h> | |
| 13 | 14 | #include <linux/power_supply.h> |
| 14 | 15 | #include <linux/units.h> |
| 15 | 16 | #include "pmf.h" |
| @@ -44,6 +45,8 @@ void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table * · 28 unmodified lines | ||
| 44 | 45 | dev_dbg(dev->dev, "Max C0 Residency: %u\n", in->ev_info.max_c0residency); |
| 45 | 46 | dev_dbg(dev->dev, "GFX Busy: %u\n", in->ev_info.gfx_busy); |
| 46 | 47 | dev_dbg(dev->dev, "LID State: %s\n", in->ev_info.lid_state ? "close" : "open"); |
| 48 | + dev_dbg(dev->dev, "User Presence: %s\n", in->ev_info.user_present ? "Present" : "Away"); | |
| 49 | + dev_dbg(dev->dev, "Ambient Light: %d\n", in->ev_info.ambient_light); | |
| 47 | 50 | dev_dbg(dev->dev, "==== TA inputs END ====\n"); |
| 48 | 51 | } |
| 49 | 52 | #else |
| @@ -147,6 +150,38 @@ static int amd_pmf_get_slider_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_ · 97 unmodified lines | ||
| 147 | 150 | return 0; |
| 148 | 151 | } |
| 149 | 152 | |
| 153 | +static int amd_pmf_get_sensor_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) | |
| 154 | +{ | |
| 155 | + struct amd_sfh_info sfh_info; | |
| 156 | + int ret; | |
| 157 | + | |
| 158 | + /* Get ALS data */ | |
| 159 | + ret = amd_get_sfh_info(&sfh_info, MT_ALS); | |
| 160 | + if (!ret) | |
| 161 | + in->ev_info.ambient_light = sfh_info.ambient_light; | |
| 162 | + else | |
| 163 | + return ret; | |
| 164 | + | |
| 165 | + /* get HPD data */ | |
| 166 | + ret = amd_get_sfh_info(&sfh_info, MT_HPD); | |
| 167 | + if (ret) | |
| 168 | + return ret; | |
| 169 | + | |
| 170 | + switch (sfh_info.user_present) { | |
| 171 | + case SFH_NOT_DETECTED: | |
| 172 | + in->ev_info.user_present = 0xff; /* assume no sensors connected */ | |
| 173 | + break; | |
| 174 | + case SFH_USER_PRESENT: | |
| 175 | + in->ev_info.user_present = 1; | |
| 176 | + break; | |
| 177 | + case SFH_USER_AWAY: | |
| 178 | + in->ev_info.user_present = 0; | |
| 179 | + break; | |
| 180 | + } | |
| 181 | + | |
| 182 | + return 0; | |
| 183 | +} | |
| 184 | + | |
| 150 | 185 | void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) |
| 151 | 186 | { |
| 152 | 187 | /* TA side lid open is 1 and close is 0, hence the ! here */ |
| @@ -155,4 +190,5 @@ void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_tab · 2 unmodified lines | ||
| 155 | 190 | amd_pmf_get_smu_info(dev, in); |
| 156 | 191 | amd_pmf_get_battery_info(dev, in); |
| 157 | 192 | amd_pmf_get_slider_info(dev, in); |
| 193 | + amd_pmf_get_sensor_info(dev, in); | |
| 158 | 194 | } |
| @@ -298,8 +298,10 @@ static ssize_t amd_pmf_get_pb_data(struct file *filp, const char __user *buf, · 297 unmodified lines | ||
| 298 | 298 | if (!new_policy_buf) |
| 299 | 299 | return -ENOMEM; |
| 300 | 300 | |
| 301 | − if (copy_from_user(new_policy_buf, buf, length)) | |
| 301 | + if (copy_from_user(new_policy_buf, buf, length)) { | |
| 302 | + kfree(new_policy_buf); | |
| 302 | 303 | return -EFAULT; |
| 304 | + } | |
| 303 | 305 | |
| 304 | 306 | kfree(dev->policy_buf); |
| 305 | 307 | dev->policy_buf = new_policy_buf; |
| @@ -399,7 +399,8 @@ int ifs_load_firmware(struct device *dev) · 398 unmodified lines | ||
| 399 | 399 | if (fw->size != expected_size) { |
| 400 | 400 | dev_err(dev, "File size mismatch (expected %u, actual %zu). Corrupted IFS image.\n", |
| 401 | 401 | expected_size, fw->size); |
| 402 | − return -EINVAL; | |
| 402 | + ret = -EINVAL; | |
| 403 | + goto release; | |
| 403 | 404 | } |
| 404 | 405 | |
| 405 | 406 | ret = image_sanity_check(dev, (struct microcode_header_intel *)fw->data); |
| @@ -23,23 +23,23 @@ static int (*uncore_read)(struct uncore_data *data, unsigned int *min, unsigned · 22 unmodified lines | ||
| 23 | 23 | static int (*uncore_write)(struct uncore_data *data, unsigned int input, unsigned int min_max); |
| 24 | 24 | static int (*uncore_read_freq)(struct uncore_data *data, unsigned int *freq); |
| 25 | 25 | |
| 26 | −static ssize_t show_domain_id(struct device *dev, struct device_attribute *attr, char *buf) | |
| 26 | +static ssize_t show_domain_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf) | |
| 27 | 27 | { |
| 28 | − struct uncore_data *data = container_of(attr, struct uncore_data, domain_id_dev_attr); | |
| 28 | + struct uncore_data *data = container_of(attr, struct uncore_data, domain_id_kobj_attr); | |
| 29 | 29 | |
| 30 | 30 | return sprintf(buf, "%u\n", data->domain_id); |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | −static ssize_t show_fabric_cluster_id(struct device *dev, struct device_attribute *attr, char *buf) | |
| 33 | +static ssize_t show_fabric_cluster_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf) | |
| 34 | 34 | { |
| 35 | − struct uncore_data *data = container_of(attr, struct uncore_data, fabric_cluster_id_dev_attr); | |
| 35 | + struct uncore_data *data = container_of(attr, struct uncore_data, fabric_cluster_id_kobj_attr); | |
| 36 | 36 | |
| 37 | 37 | return sprintf(buf, "%u\n", data->cluster_id); |
| 38 | 38 | } |
| 39 | 39 | |
| 40 | −static ssize_t show_package_id(struct device *dev, struct device_attribute *attr, char *buf) | |
| 40 | +static ssize_t show_package_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf) | |
| 41 | 41 | { |
| 42 | − struct uncore_data *data = container_of(attr, struct uncore_data, package_id_dev_attr); | |
| 42 | + struct uncore_data *data = container_of(attr, struct uncore_data, package_id_kobj_attr); | |
| 43 | 43 | |
| 44 | 44 | return sprintf(buf, "%u\n", data->package_id); |
| 45 | 45 | } |
| @@ -97,30 +97,30 @@ static ssize_t show_perf_status_freq_khz(struct uncore_data *data, char *buf) · 51 unmodified lines | ||
| 97 | 97 | } |
| 98 | 98 | |
| 99 | 99 | #define store_uncore_min_max(name, min_max) \ |
| 100 | − static ssize_t store_##name(struct device *dev, \ | |
| 101 | − struct device_attribute *attr, \ | |
| 100 | + static ssize_t store_##name(struct kobject *kobj, \ | |
| 101 | + struct kobj_attribute *attr, \ | |
| 102 | 102 | const char *buf, size_t count) \ |
| 103 | 103 | { \ |
| 104 | − struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\ | |
| 104 | + struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\ | |
| 105 | 105 | \ |
| 106 | 106 | return store_min_max_freq_khz(data, buf, count, \ |
| 107 | 107 | min_max); \ |
| 108 | 108 | } |
| 109 | 109 | |
| 110 | 110 | #define show_uncore_min_max(name, min_max) \ |
| 111 | − static ssize_t show_##name(struct device *dev, \ | |
| 112 | − struct device_attribute *attr, char *buf)\ | |
| 111 | + static ssize_t show_##name(struct kobject *kobj, \ | |
| 112 | + struct kobj_attribute *attr, char *buf)\ | |
| 113 | 113 | { \ |
| 114 | − struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\ | |
| 114 | + struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\ | |
| 115 | 115 | \ |
| 116 | 116 | return show_min_max_freq_khz(data, buf, min_max); \ |
| 117 | 117 | } |
| 118 | 118 | |
| 119 | 119 | #define show_uncore_perf_status(name) \ |
| 120 | − static ssize_t show_##name(struct device *dev, \ | |
| 121 | − struct device_attribute *attr, char *buf)\ | |
| 120 | + static ssize_t show_##name(struct kobject *kobj, \ | |
| 121 | + struct kobj_attribute *attr, char *buf)\ | |
| 122 | 122 | { \ |
| 123 | − struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\ | |
| 123 | + struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\ | |
| 124 | 124 | \ |
| 125 | 125 | return show_perf_status_freq_khz(data, buf); \ |
| 126 | 126 | } |
| @@ -134,11 +134,11 @@ show_uncore_min_max(max_freq_khz, 1); · 7 unmodified lines | ||
| 134 | 134 | show_uncore_perf_status(current_freq_khz); |
| 135 | 135 | |
| 136 | 136 | #define show_uncore_data(member_name) \ |
| 137 | − static ssize_t show_##member_name(struct device *dev, \ | |
| 138 | − struct device_attribute *attr, char *buf)\ | |
| 137 | + static ssize_t show_##member_name(struct kobject *kobj, \ | |
| 138 | + struct kobj_attribute *attr, char *buf)\ | |
| 139 | 139 | { \ |
| 140 | 140 | struct uncore_data *data = container_of(attr, struct uncore_data,\ |
| 141 | − member_name##_dev_attr);\ | |
| 141 | + member_name##_kobj_attr);\ | |
| 142 | 142 | \ |
| 143 | 143 | return sysfs_emit(buf, "%u\n", \ |
| 144 | 144 | data->member_name); \ |
| @@ -149,29 +149,29 @@ show_uncore_data(initial_max_freq_khz); · 4 unmodified lines | ||
| 149 | 149 | |
| 150 | 150 | #define init_attribute_rw(_name) \ |
| 151 | 151 | do { \ |
| 152 | − sysfs_attr_init(&data->_name##_dev_attr.attr); \ | |
| 153 | − data->_name##_dev_attr.show = show_##_name; \ | |
| 154 | − data->_name##_dev_attr.store = store_##_name; \ | |
| 155 | − data->_name##_dev_attr.attr.name = #_name; \ | |
| 156 | − data->_name##_dev_attr.attr.mode = 0644; \ | |
| 152 | + sysfs_attr_init(&data->_name##_kobj_attr.attr); \ | |
| 153 | + data->_name##_kobj_attr.show = show_##_name; \ | |
| 154 | + data->_name##_kobj_attr.store = store_##_name; \ | |
| 155 | + data->_name##_kobj_attr.attr.name = #_name; \ | |
| 156 | + data->_name##_kobj_attr.attr.mode = 0644; \ | |
| 157 | 157 | } while (0) |
| 158 | 158 | |
| 159 | 159 | #define init_attribute_ro(_name) \ |
| 160 | 160 | do { \ |
| 161 | − sysfs_attr_init(&data->_name##_dev_attr.attr); \ | |
| 162 | − data->_name##_dev_attr.show = show_##_name; \ | |
| 163 | − data->_name##_dev_attr.store = NULL; \ | |
| 164 | − data->_name##_dev_attr.attr.name = #_name; \ | |
| 165 | − data->_name##_dev_attr.attr.mode = 0444; \ | |
| 161 | + sysfs_attr_init(&data->_name##_kobj_attr.attr); \ | |
| 162 | + data->_name##_kobj_attr.show = show_##_name; \ | |
| 163 | + data->_name##_kobj_attr.store = NULL; \ | |
| 164 | + data->_name##_kobj_attr.attr.name = #_name; \ | |
| 165 | + data->_name##_kobj_attr.attr.mode = 0444; \ | |
| 166 | 166 | } while (0) |
| 167 | 167 | |
| 168 | 168 | #define init_attribute_root_ro(_name) \ |
| 169 | 169 | do { \ |
| 170 | − sysfs_attr_init(&data->_name##_dev_attr.attr); \ | |
| 171 | − data->_name##_dev_attr.show = show_##_name; \ | |
| 172 | − data->_name##_dev_attr.store = NULL; \ | |
| 173 | − data->_name##_dev_attr.attr.name = #_name; \ | |
| 174 | − data->_name##_dev_attr.attr.mode = 0400; \ | |
| 170 | + sysfs_attr_init(&data->_name##_kobj_attr.attr); \ | |
| 171 | + data->_name##_kobj_attr.show = show_##_name; \ | |
| 172 | + data->_name##_kobj_attr.store = NULL; \ | |
| 173 | + data->_name##_kobj_attr.attr.name = #_name; \ | |
| 174 | + data->_name##_kobj_attr.attr.mode = 0400; \ | |
| 175 | 175 | } while (0) |
| 176 | 176 | |
| 177 | 177 | static int create_attr_group(struct uncore_data *data, char *name) |
| @@ -186,21 +186,21 @@ static int create_attr_group(struct uncore_data *data, char *name) · 8 unmodified lines | ||
| 186 | 186 | |
| 187 | 187 | if (data->domain_id != UNCORE_DOMAIN_ID_INVALID) { |
| 188 | 188 | init_attribute_root_ro(domain_id); |
| 189 | − data->uncore_attrs[index++] = &data->domain_id_dev_attr.attr; | |
| 189 | + data->uncore_attrs[index++] = &data->domain_id_kobj_attr.attr; | |
| 190 | 190 | init_attribute_root_ro(fabric_cluster_id); |
| 191 | − data->uncore_attrs[index++] = &data->fabric_cluster_id_dev_attr.attr; | |
| 191 | + data->uncore_attrs[index++] = &data->fabric_cluster_id_kobj_attr.attr; | |
| 192 | 192 | init_attribute_root_ro(package_id); |
| 193 | − data->uncore_attrs[index++] = &data->package_id_dev_attr.attr; | |
| 193 | + data->uncore_attrs[index++] = &data->package_id_kobj_attr.attr; | |
| 194 | 194 | } |
| 195 | 195 | |
| 196 | − data->uncore_attrs[index++] = &data->max_freq_khz_dev_attr.attr; | |
| 197 | − data->uncore_attrs[index++] = &data->min_freq_khz_dev_attr.attr; | |
| 198 | − data->uncore_attrs[index++] = &data->initial_min_freq_khz_dev_attr.attr; | |
| 199 | − data->uncore_attrs[index++] = &data->initial_max_freq_khz_dev_attr.attr; | |
| 196 | + data->uncore_attrs[index++] = &data->max_freq_khz_kobj_attr.attr; | |
| 197 | + data->uncore_attrs[index++] = &data->min_freq_khz_kobj_attr.attr; | |
| 198 | + data->uncore_attrs[index++] = &data->initial_min_freq_khz_kobj_attr.attr; | |
| 199 | + data->uncore_attrs[index++] = &data->initial_max_freq_khz_kobj_attr.attr; | |
| 200 | 200 | |
| 201 | 201 | ret = uncore_read_freq(data, &freq); |
| 202 | 202 | if (!ret) |
| 203 | − data->uncore_attrs[index++] = &data->current_freq_khz_dev_attr.attr; | |
| 203 | + data->uncore_attrs[index++] = &data->current_freq_khz_kobj_attr.attr; | |
| 204 | 204 | |
| 205 | 205 | data->uncore_attrs[index] = NULL; |
| 206 | 206 | |
| @@ -26,14 +26,14 @@ · 25 unmodified lines | ||
| 26 | 26 | * @instance_id: Unique instance id to append to directory name |
| 27 | 27 | * @name: Sysfs entry name for this instance |
| 28 | 28 | * @uncore_attr_group: Attribute group storage |
| 29 | − * @max_freq_khz_dev_attr: Storage for device attribute max_freq_khz | |
| 30 | − * @mix_freq_khz_dev_attr: Storage for device attribute min_freq_khz | |
| 31 | − * @initial_max_freq_khz_dev_attr: Storage for device attribute initial_max_freq_khz | |
| 32 | − * @initial_min_freq_khz_dev_attr: Storage for device attribute initial_min_freq_khz | |
| 33 | − * @current_freq_khz_dev_attr: Storage for device attribute current_freq_khz | |
| 34 | − * @domain_id_dev_attr: Storage for device attribute domain_id | |
| 35 | − * @fabric_cluster_id_dev_attr: Storage for device attribute fabric_cluster_id | |
| 36 | − * @package_id_dev_attr: Storage for device attribute package_id | |
| 29 | + * @max_freq_khz_kobj_attr: Storage for kobject attribute max_freq_khz | |
| 30 | + * @mix_freq_khz_kobj_attr: Storage for kobject attribute min_freq_khz | |
| 31 | + * @initial_max_freq_khz_kobj_attr: Storage for kobject attribute initial_max_freq_khz | |
| 32 | + * @initial_min_freq_khz_kobj_attr: Storage for kobject attribute initial_min_freq_khz | |
| 33 | + * @current_freq_khz_kobj_attr: Storage for kobject attribute current_freq_khz | |
| 34 | + * @domain_id_kobj_attr: Storage for kobject attribute domain_id | |
| 35 | + * @fabric_cluster_id_kobj_attr: Storage for kobject attribute fabric_cluster_id | |
| 36 | + * @package_id_kobj_attr: Storage for kobject attribute package_id | |
| 37 | 37 | * @uncore_attrs: Attribute storage for group creation |
| 38 | 38 | * |
| 39 | 39 | * This structure is used to encapsulate all data related to uncore sysfs |
| @@ -53,14 +53,14 @@ struct uncore_data { · 13 unmodified lines | ||
| 53 | 53 | char name[32]; |
| 54 | 54 | |
| 55 | 55 | struct attribute_group uncore_attr_group; |
| 56 | − struct device_attribute max_freq_khz_dev_attr; | |
| 57 | − struct device_attribute min_freq_khz_dev_attr; | |
| 58 | − struct device_attribute initial_max_freq_khz_dev_attr; | |
| 59 | − struct device_attribute initial_min_freq_khz_dev_attr; | |
| 60 | − struct device_attribute current_freq_khz_dev_attr; | |
| 61 | − struct device_attribute domain_id_dev_attr; | |
| 62 | − struct device_attribute fabric_cluster_id_dev_attr; | |
| 63 | − struct device_attribute package_id_dev_attr; | |
| 56 | + struct kobj_attribute max_freq_khz_kobj_attr; | |
| 57 | + struct kobj_attribute min_freq_khz_kobj_attr; | |
| 58 | + struct kobj_attribute initial_max_freq_khz_kobj_attr; | |
| 59 | + struct kobj_attribute initial_min_freq_khz_kobj_attr; | |
| 60 | + struct kobj_attribute current_freq_khz_kobj_attr; | |
| 61 | + struct kobj_attribute domain_id_kobj_attr; | |
| 62 | + struct kobj_attribute fabric_cluster_id_kobj_attr; | |
| 63 | + struct kobj_attribute package_id_kobj_attr; | |
| 64 | 64 | struct attribute *uncore_attrs[9]; |
| 65 | 65 | }; |
| 66 | 66 | |
| @@ -32,7 +32,7 @@ static int get_fwu_request(struct device *dev, u32 *out) · 31 unmodified lines | ||
| 32 | 32 | return -ENODEV; |
| 33 | 33 | |
| 34 | 34 | if (obj->type != ACPI_TYPE_INTEGER) { |
| 35 | − dev_warn(dev, "wmi_query_block returned invalid value\n"); | |
| 35 | + dev_warn(dev, "wmidev_block_query returned invalid value\n"); | |
| 36 | 36 | kfree(obj); |
| 37 | 37 | return -EINVAL; |
| 38 | 38 | } |
| @@ -55,7 +55,7 @@ static int set_fwu_request(struct device *dev, u32 in) · 16 unmodified lines | ||
| 55 | 55 | |
| 56 | 56 | status = wmidev_block_set(to_wmi_device(dev), 0, &input); |
| 57 | 57 | if (ACPI_FAILURE(status)) { |
| 58 | − dev_err(dev, "wmi_set_block failed\n"); | |
| 58 | + dev_err(dev, "wmidev_block_set failed\n"); | |
| 59 | 59 | return -ENODEV; |
| 60 | 60 | } |
| 61 | 61 | |
| @@ -26,6 +26,21 @@ static const struct x86_cpu_id p2sb_cpu_ids[] = { · 25 unmodified lines | ||
| 26 | 26 | {} |
| 27 | 27 | }; |
| 28 | 28 | |
| 29 | +/* | |
| 30 | + * Cache BAR0 of P2SB device functions 0 to 7. | |
| 31 | + * TODO: The constant 8 is the number of functions that PCI specification | |
| 32 | + * defines. Same definitions exist tree-wide. Unify this definition and | |
| 33 | + * the other definitions then move to include/uapi/linux/pci.h. | |
| 34 | + */ | |
| 35 | +#define NR_P2SB_RES_CACHE 8 | |
| 36 | + | |
| 37 | +struct p2sb_res_cache { | |
| 38 | + u32 bus_dev_id; | |
| 39 | + struct resource res; | |
| 40 | +}; | |
| 41 | + | |
| 42 | +static struct p2sb_res_cache p2sb_resources[NR_P2SB_RES_CACHE]; | |
| 43 | + | |
| 29 | 44 | static int p2sb_get_devfn(unsigned int *devfn) |
| 30 | 45 | { |
| 31 | 46 | unsigned int fn = P2SB_DEVFN_DEFAULT; |
| @@ -39,10 +54,18 @@ static int p2sb_get_devfn(unsigned int *devfn) · 7 unmodified lines | ||
| 39 | 54 | return 0; |
| 40 | 55 | } |
| 41 | 56 | |
| 57 | +static bool p2sb_valid_resource(struct resource *res) | |
| 58 | +{ | |
| 59 | + if (res->flags) | |
| 60 | + return true; | |
| 61 | + | |
| 62 | + return false; | |
| 63 | +} | |
| 64 | + | |
| 42 | 65 | /* Copy resource from the first BAR of the device in question */ |
| 43 | −static int p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem) | |
| 66 | +static void p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem) | |
| 44 | 67 | { |
| 45 | − struct resource *bar0 = &pdev->resource[0]; | |
| 68 | + struct resource *bar0 = pci_resource_n(pdev, 0); | |
| 46 | 69 | |
| 47 | 70 | /* Make sure we have no dangling pointers in the output */ |
| 48 | 71 | memset(mem, 0, sizeof(*mem)); |
| @@ -56,49 +79,66 @@ static int p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem) · 7 unmodified lines | ||
| 56 | 79 | mem->end = bar0->end; |
| 57 | 80 | mem->flags = bar0->flags; |
| 58 | 81 | mem->desc = bar0->desc; |
| 59 | − | |
| 60 | − return 0; | |
| 61 | 82 | } |
| 62 | 83 | |
| 63 | −static int p2sb_scan_and_read(struct pci_bus *bus, unsigned int devfn, struct resource *mem) | |
| 84 | +static void p2sb_scan_and_cache_devfn(struct pci_bus *bus, unsigned int devfn) | |
| 64 | 85 | { |
| 86 | + struct p2sb_res_cache *cache = &p2sb_resources[PCI_FUNC(devfn)]; | |
| 65 | 87 | struct pci_dev *pdev; |
| 66 | − int ret; | |
| 67 | 88 | |
| 68 | 89 | pdev = pci_scan_single_device(bus, devfn); |
| 69 | 90 | if (!pdev) |
| 70 | − return -ENODEV; | |
| 91 | + return; | |
| 71 | 92 | |
| 72 | − ret = p2sb_read_bar0(pdev, mem); | |
| 93 | + p2sb_read_bar0(pdev, &cache->res); | |
| 94 | + cache->bus_dev_id = bus->dev.id; | |
| 73 | 95 | |
| 74 | 96 | pci_stop_and_remove_bus_device(pdev); |
| 75 | − return ret; | |
| 76 | 97 | } |
| 77 | 98 | |
| 78 | −/** | |
| 79 | − * p2sb_bar - Get Primary to Sideband (P2SB) bridge device BAR | |
| 80 | − * @bus: PCI bus to communicate with | |
| 81 | − * @devfn: PCI slot and function to communicate with | |
| 82 | − * @mem: memory resource to be filled in | |
| 83 | − * | |
| 84 | − * The BIOS prevents the P2SB device from being enumerated by the PCI | |
| 85 | − * subsystem, so we need to unhide and hide it back to lookup the BAR. | |
| 86 | − * | |
| 87 | − * if @bus is NULL, the bus 0 in domain 0 will be used. | |
| 88 | − * If @devfn is 0, it will be replaced by devfn of the P2SB device. | |
| 89 | − * | |
| 90 | − * Caller must provide a valid pointer to @mem. | |
| 91 | − * | |
| 92 | − * Locking is handled by pci_rescan_remove_lock mutex. | |
| 93 | − * | |
| 94 | − * Return: | |
| 95 | − * 0 on success or appropriate errno value on error. | |
| 96 | − */ | |
| 97 | −int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) | |
| 99 | +static int p2sb_scan_and_cache(struct pci_bus *bus, unsigned int devfn) | |
| 100 | +{ | |
| 101 | + unsigned int slot, fn; | |
| 102 | + | |
| 103 | + if (PCI_FUNC(devfn) == 0) { | |
| 104 | + /* | |
| 105 | + * When function number of the P2SB device is zero, scan it and | |
| 106 | + * other function numbers, and if devices are available, cache | |
| 107 | + * their BAR0s. | |
| 108 | + */ | |
| 109 | + slot = PCI_SLOT(devfn); | |
| 110 | + for (fn = 0; fn < NR_P2SB_RES_CACHE; fn++) | |
| 111 | + p2sb_scan_and_cache_devfn(bus, PCI_DEVFN(slot, fn)); | |
| 112 | + } else { | |
| 113 | + /* Scan the P2SB device and cache its BAR0 */ | |
| 114 | + p2sb_scan_and_cache_devfn(bus, devfn); | |
| 115 | + } | |
| 116 | + | |
| 117 | + if (!p2sb_valid_resource(&p2sb_resources[PCI_FUNC(devfn)].res)) | |
| 118 | + return -ENOENT; | |
| 119 | + | |
| 120 | + return 0; | |
| 121 | +} | |
| 122 | + | |
| 123 | +static struct pci_bus *p2sb_get_bus(struct pci_bus *bus) | |
| 124 | +{ | |
| 125 | + static struct pci_bus *p2sb_bus; | |
| 126 | + | |
| 127 | + bus = bus ?: p2sb_bus; | |
| 128 | + if (bus) | |
| 129 | + return bus; | |
| 130 | + | |
| 131 | + /* Assume P2SB is on the bus 0 in domain 0 */ | |
| 132 | + p2sb_bus = pci_find_bus(0, 0); | |
| 133 | + return p2sb_bus; | |
| 134 | +} | |
| 135 | + | |
| 136 | +static int p2sb_cache_resources(void) | |
| 98 | 137 | { |
| 99 | − struct pci_dev *pdev_p2sb; | |
| 100 | 138 | unsigned int devfn_p2sb; |
| 101 | 139 | u32 value = P2SBC_HIDE; |
| 140 | + struct pci_bus *bus; | |
| 141 | + u16 class; | |
| 102 | 142 | int ret; |
| 103 | 143 | |
| 104 | 144 | /* Get devfn for P2SB device itself */ |
| @@ -106,8 +146,17 @@ int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) · 1 unmodified line | ||
| 106 | 146 | if (ret) |
| 107 | 147 | return ret; |
| 108 | 148 | |
| 109 | − /* if @bus is NULL, use bus 0 in domain 0 */ | |
| 110 | − bus = bus ?: pci_find_bus(0, 0); | |
| 149 | + bus = p2sb_get_bus(NULL); | |
| 150 | + if (!bus) | |
| 151 | + return -ENODEV; | |
| 152 | + | |
| 153 | + /* | |
| 154 | + * When a device with same devfn exists and its device class is not | |
| 155 | + * PCI_CLASS_MEMORY_OTHER for P2SB, do not touch it. | |
| 156 | + */ | |
| 157 | + pci_bus_read_config_word(bus, devfn_p2sb, PCI_CLASS_DEVICE, &class); | |
| 158 | + if (!PCI_POSSIBLE_ERROR(class) && class != PCI_CLASS_MEMORY_OTHER) | |
| 159 | + return -ENODEV; | |
| 111 | 160 | |
| 112 | 161 | /* |
| 113 | 162 | * Prevent concurrent PCI bus scan from seeing the P2SB device and |
| @@ -115,17 +164,16 @@ int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) · 1 unmodified line | ||
| 115 | 164 | */ |
| 116 | 165 | pci_lock_rescan_remove(); |
| 117 | 166 | |
| 118 | − /* Unhide the P2SB device, if needed */ | |
| 167 | + /* | |
| 168 | + * The BIOS prevents the P2SB device from being enumerated by the PCI | |
| 169 | + * subsystem, so we need to unhide and hide it back to lookup the BAR. | |
| 170 | + * Unhide the P2SB device here, if needed. | |
| 171 | + */ | |
| 119 | 172 | pci_bus_read_config_dword(bus, devfn_p2sb, P2SBC, &value); |
| 120 | 173 | if (value & P2SBC_HIDE) |
| 121 | 174 | pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, 0); |
| 122 | 175 | |
| 123 | − pdev_p2sb = pci_scan_single_device(bus, devfn_p2sb); | |
| 124 | − if (devfn) | |
| 125 | − ret = p2sb_scan_and_read(bus, devfn, mem); | |
| 126 | − else | |
| 127 | − ret = p2sb_read_bar0(pdev_p2sb, mem); | |
| 128 | − pci_stop_and_remove_bus_device(pdev_p2sb); | |
| 176 | + ret = p2sb_scan_and_cache(bus, devfn_p2sb); | |
| 129 | 177 | |
| 130 | 178 | /* Hide the P2SB device, if it was hidden */ |
| 131 | 179 | if (value & P2SBC_HIDE) |
| @@ -133,12 +181,62 @@ int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) · 1 unmodified line | ||
| 133 | 181 | |
| 134 | 182 | pci_unlock_rescan_remove(); |
| 135 | 183 | |
| 136 | − if (ret) | |
| 137 | − return ret; | |
| 184 | + return ret; | |
| 185 | +} | |
| 186 | + | |
| 187 | +/** | |
| 188 | + * p2sb_bar - Get Primary to Sideband (P2SB) bridge device BAR | |
| 189 | + * @bus: PCI bus to communicate with | |
| 190 | + * @devfn: PCI slot and function to communicate with | |
| 191 | + * @mem: memory resource to be filled in | |
| 192 | + * | |
| 193 | + * If @bus is NULL, the bus 0 in domain 0 will be used. | |
| 194 | + * If @devfn is 0, it will be replaced by devfn of the P2SB device. | |
| 195 | + * | |
| 196 | + * Caller must provide a valid pointer to @mem. | |
| 197 | + * | |
| 198 | + * Return: | |
| 199 | + * 0 on success or appropriate errno value on error. | |
| 200 | + */ | |
| 201 | +int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) | |
| 202 | +{ | |
| 203 | + struct p2sb_res_cache *cache; | |
| 204 | + int ret; | |
| 205 | + | |
| 206 | + bus = p2sb_get_bus(bus); | |
| 207 | + if (!bus) | |
| 208 | + return -ENODEV; | |
| 209 | + | |
| 210 | + if (!devfn) { | |
| 211 | + ret = p2sb_get_devfn(&devfn); | |
| 212 | + if (ret) | |
| 213 | + return ret; | |
| 214 | + } | |
| 138 | 215 | |
| 139 | − if (mem->flags == 0) | |
| 216 | + cache = &p2sb_resources[PCI_FUNC(devfn)]; | |
| 217 | + if (cache->bus_dev_id != bus->dev.id) | |
| 140 | 218 | return -ENODEV; |
| 141 | 219 | |
| 220 | + if (!p2sb_valid_resource(&cache->res)) | |
| 221 | + return -ENOENT; | |
| 222 | + | |
| 223 | + memcpy(mem, &cache->res, sizeof(*mem)); | |
| 142 | 224 | return 0; |
| 143 | 225 | } |
| 144 | 226 | EXPORT_SYMBOL_GPL(p2sb_bar); |
| 227 | + | |
| 228 | +static int __init p2sb_fs_init(void) | |
| 229 | +{ | |
| 230 | + p2sb_cache_resources(); | |
| 231 | + return 0; | |
| 232 | +} | |
| 233 | + | |
| 234 | +/* | |
| 235 | + * pci_rescan_remove_lock to avoid access to unhidden P2SB devices can | |
| 236 | + * not be locked in sysfs pci bus rescan path because of deadlock. To | |
| 237 | + * avoid the deadlock, access to P2SB devices with the lock at an early | |
| 238 | + * step in kernel initialization and cache required resources. This | |
| 239 | + * should happen after subsys_initcall which initializes PCI subsystem | |
| 240 | + * and before device_initcall which requires P2SB resources. | |
| 241 | + */ | |
| 242 | +fs_initcall(p2sb_fs_init); | |
| @@ -944,6 +944,32 @@ static const struct ts_dmi_data teclast_tbook11_data = { · 943 unmodified lines | ||
| 944 | 944 | .properties = teclast_tbook11_props, |
| 945 | 945 | }; |
| 946 | 946 | |
| 947 | +static const struct property_entry teclast_x16_plus_props[] = { | |
| 948 | + PROPERTY_ENTRY_U32("touchscreen-min-x", 8), | |
| 949 | + PROPERTY_ENTRY_U32("touchscreen-min-y", 14), | |
| 950 | + PROPERTY_ENTRY_U32("touchscreen-size-x", 1916), | |
| 951 | + PROPERTY_ENTRY_U32("touchscreen-size-y", 1264), | |
| 952 | + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), | |
| 953 | + PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-teclast-x16-plus.fw"), | |
| 954 | + PROPERTY_ENTRY_U32("silead,max-fingers", 10), | |
| 955 | + PROPERTY_ENTRY_BOOL("silead,home-button"), | |
| 956 | + { } | |
| 957 | +}; | |
| 958 | + | |
| 959 | +static const struct ts_dmi_data teclast_x16_plus_data = { | |
| 960 | + .embedded_fw = { | |
| 961 | + .name = "silead/gsl3692-teclast-x16-plus.fw", | |
| 962 | + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, | |
| 963 | + .length = 43560, | |
| 964 | + .sha256 = { 0x9d, 0xb0, 0x3d, 0xf1, 0x00, 0x3c, 0xb5, 0x25, | |
| 965 | + 0x62, 0x8a, 0xa0, 0x93, 0x4b, 0xe0, 0x4e, 0x75, | |
| 966 | + 0xd1, 0x27, 0xb1, 0x65, 0x3c, 0xba, 0xa5, 0x0f, | |
| 967 | + 0xcd, 0xb4, 0xbe, 0x00, 0xbb, 0xf6, 0x43, 0x29 }, | |
| 968 | + }, | |
| 969 | + .acpi_name = "MSSL1680:00", | |
| 970 | + .properties = teclast_x16_plus_props, | |
| 971 | +}; | |
| 972 | + | |
| 947 | 973 | static const struct property_entry teclast_x3_plus_props[] = { |
| 948 | 974 | PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), |
| 949 | 975 | PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), |
| @@ -1612,6 +1638,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = { · 662 unmodified lines | ||
| 1612 | 1638 | DMI_MATCH(DMI_PRODUCT_SKU, "E5A6_A1"), |
| 1613 | 1639 | }, |
| 1614 | 1640 | }, |
| 1641 | + { | |
| 1642 | + /* Teclast X16 Plus */ | |
| 1643 | + .driver_data = (void *)&teclast_x16_plus_data, | |
| 1644 | + .matches = { | |
| 1645 | + DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), | |
| 1646 | + DMI_MATCH(DMI_PRODUCT_NAME, "Default string"), | |
| 1647 | + DMI_MATCH(DMI_PRODUCT_SKU, "D3A5_A1"), | |
| 1648 | + }, | |
| 1649 | + }, | |
| 1615 | 1650 | { |
| 1616 | 1651 | /* Teclast X3 Plus */ |
| 1617 | 1652 | .driver_data = (void *)&teclast_x3_plus_data, |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | ||
| 25 | 25 | #include <linux/list.h> |
| 26 | 26 | #include <linux/module.h> |
| 27 | 27 | #include <linux/platform_device.h> |
| 28 | +#include <linux/rwsem.h> | |
| 28 | 29 | #include <linux/slab.h> |
| 29 | 30 | #include <linux/sysfs.h> |
| 30 | 31 | #include <linux/types.h> |
| @@ -56,7 +57,6 @@ static_assert(__alignof__(struct guid_block) == 1); · 25 unmodified lines | ||
| 56 | 57 | |
| 57 | 58 | enum { /* wmi_block flags */ |
| 58 | 59 | WMI_READ_TAKES_NO_ARGS, |
| 59 | − WMI_PROBED, | |
| 60 | 60 | }; |
| 61 | 61 | |
| 62 | 62 | struct wmi_block { |
| @@ -64,8 +64,10 @@ struct wmi_block { · 1 unmodified line | ||
| 64 | 64 | struct list_head list; |
| 65 | 65 | struct guid_block gblock; |
| 66 | 66 | struct acpi_device *acpi_device; |
| 67 | + struct rw_semaphore notify_lock; /* Protects notify callback add/remove */ | |
| 67 | 68 | wmi_notify_handler handler; |
| 68 | 69 | void *handler_data; |
| 70 | + bool driver_ready; | |
| 69 | 71 | unsigned long flags; |
| 70 | 72 | }; |
| 71 | 73 | |
| @@ -219,6 +221,17 @@ static int wmidev_match_guid(struct device *dev, const void *data) · 147 unmodified lines | ||
| 219 | 221 | return 0; |
| 220 | 222 | } |
| 221 | 223 | |
| 224 | +static int wmidev_match_notify_id(struct device *dev, const void *data) | |
| 225 | +{ | |
| 226 | + struct wmi_block *wblock = dev_to_wblock(dev); | |
| 227 | + const u32 *notify_id = data; | |
| 228 | + | |
| 229 | + if (wblock->gblock.flags & ACPI_WMI_EVENT && wblock->gblock.notify_id == *notify_id) | |
| 230 | + return 1; | |
| 231 | + | |
| 232 | + return 0; | |
| 233 | +} | |
| 234 | + | |
| 222 | 235 | static struct bus_type wmi_bus_type; |
| 223 | 236 | |
| 224 | 237 | static struct wmi_device *wmi_find_device_by_guid(const char *guid_string) |
| @@ -238,6 +251,17 @@ static struct wmi_device *wmi_find_device_by_guid(const char *guid_string) · 13 unmodified lines | ||
| 238 | 251 | return dev_to_wdev(dev); |
| 239 | 252 | } |
| 240 | 253 | |
| 254 | +static struct wmi_device *wmi_find_event_by_notify_id(const u32 notify_id) | |
| 255 | +{ | |
| 256 | + struct device *dev; | |
| 257 | + | |
| 258 | + dev = bus_find_device(&wmi_bus_type, NULL, ¬ify_id, wmidev_match_notify_id); | |
| 259 | + if (!dev) | |
| 260 | + return ERR_PTR(-ENODEV); | |
| 261 | + | |
| 262 | + return to_wmi_device(dev); | |
| 263 | +} | |
| 264 | + | |
| 241 | 265 | static void wmi_device_put(struct wmi_device *wdev) |
| 242 | 266 | { |
| 243 | 267 | put_device(&wdev->dev); |
| @@ -572,32 +596,31 @@ acpi_status wmi_install_notify_handler(const char *guid, · 328 unmodified lines | ||
| 572 | 596 | wmi_notify_handler handler, |
| 573 | 597 | void *data) |
| 574 | 598 | { |
| 575 | − struct wmi_block *block; | |
| 576 | − acpi_status status = AE_NOT_EXIST; | |
| 577 | − guid_t guid_input; | |
| 578 | − | |
| 579 | − if (!guid || !handler) | |
| 580 | − return AE_BAD_PARAMETER; | |
| 599 | + struct wmi_block *wblock; | |
| 600 | + struct wmi_device *wdev; | |
| 601 | + acpi_status status; | |
| 581 | 602 | |
| 582 | − if (guid_parse(guid, &guid_input)) | |
| 583 | − return AE_BAD_PARAMETER; | |
| 603 | + wdev = wmi_find_device_by_guid(guid); | |
| 604 | + if (IS_ERR(wdev)) | |
| 605 | + return AE_ERROR; | |
| 584 | 606 | |
| 585 | − list_for_each_entry(block, &wmi_block_list, list) { | |
| 586 | − acpi_status wmi_status; | |
| 607 | + wblock = container_of(wdev, struct wmi_block, dev); | |
| 587 | 608 | |
| 588 | − if (guid_equal(&block->gblock.guid, &guid_input)) { | |
| 589 | − if (block->handler) | |
| 590 | − return AE_ALREADY_ACQUIRED; | |
| 609 | + down_write(&wblock->notify_lock); | |
| 610 | + if (wblock->handler) { | |
| 611 | + status = AE_ALREADY_ACQUIRED; | |
| 612 | + } else { | |
| 613 | + wblock->handler = handler; | |
| 614 | + wblock->handler_data = data; | |
| 591 | 615 | |
| 592 | − block->handler = handler; | |
| 593 | − block->handler_data = data; | |
| 616 | + if (ACPI_FAILURE(wmi_method_enable(wblock, true))) | |
| 617 | + dev_warn(&wblock->dev.dev, "Failed to enable device\n"); | |
| 594 | 618 | |
| 595 | − wmi_status = wmi_method_enable(block, true); | |
| 596 | − if ((wmi_status != AE_OK) || | |
| 597 | − ((wmi_status == AE_OK) && (status == AE_NOT_EXIST))) | |
| 598 | − status = wmi_status; | |
| 599 | − } | |
| 619 | + status = AE_OK; | |
| 600 | 620 | } |
| 621 | + up_write(&wblock->notify_lock); | |
| 622 | + | |
| 623 | + wmi_device_put(wdev); | |
| 601 | 624 | |
| 602 | 625 | return status; |
| 603 | 626 | } |
| @@ -613,30 +636,31 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler); · 9 unmodified lines | ||
| 613 | 636 | */ |
| 614 | 637 | acpi_status wmi_remove_notify_handler(const char *guid) |
| 615 | 638 | { |
| 616 | − struct wmi_block *block; | |
| 617 | − acpi_status status = AE_NOT_EXIST; | |
| 618 | − guid_t guid_input; | |
| 639 | + struct wmi_block *wblock; | |
| 640 | + struct wmi_device *wdev; | |
| 641 | + acpi_status status; | |
| 619 | 642 | |
| 620 | − if (!guid) | |
| 621 | − return AE_BAD_PARAMETER; | |
| 643 | + wdev = wmi_find_device_by_guid(guid); | |
| 644 | + if (IS_ERR(wdev)) | |
| 645 | + return AE_ERROR; | |
| 622 | 646 | |
| 623 | − if (guid_parse(guid, &guid_input)) | |
| 624 | − return AE_BAD_PARAMETER; | |
| 647 | + wblock = container_of(wdev, struct wmi_block, dev); | |
| 625 | 648 | |
| 626 | − list_for_each_entry(block, &wmi_block_list, list) { | |
| 627 | − acpi_status wmi_status; | |
| 649 | + down_write(&wblock->notify_lock); | |
| 650 | + if (!wblock->handler) { | |
| 651 | + status = AE_NULL_ENTRY; | |
| 652 | + } else { | |
| 653 | + if (ACPI_FAILURE(wmi_method_enable(wblock, false))) | |
| 654 | + dev_warn(&wblock->dev.dev, "Failed to disable device\n"); | |
| 628 | 655 | |
| 629 | − if (guid_equal(&block->gblock.guid, &guid_input)) { | |
| 630 | − if (!block->handler) | |
| 631 | − return AE_NULL_ENTRY; | |
| 656 | + wblock->handler = NULL; | |
| 657 | + wblock->handler_data = NULL; | |
| 632 | 658 | |
| 633 | − wmi_status = wmi_method_enable(block, false); | |
| 634 | − block->handler = NULL; | |
| 635 | − block->handler_data = NULL; | |
| 636 | − if (wmi_status != AE_OK || (wmi_status == AE_OK && status == AE_NOT_EXIST)) | |
| 637 | − status = wmi_status; | |
| 638 | − } | |
| 659 | + status = AE_OK; | |
| 639 | 660 | } |
| 661 | + up_write(&wblock->notify_lock); | |
| 662 | + | |
| 663 | + wmi_device_put(wdev); | |
| 640 | 664 | |
| 641 | 665 | return status; |
| 642 | 666 | } |
| @@ -655,15 +679,19 @@ EXPORT_SYMBOL_GPL(wmi_remove_notify_handler); · 12 unmodified lines | ||
| 655 | 679 | acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out) |
| 656 | 680 | { |
| 657 | 681 | struct wmi_block *wblock; |
| 682 | + struct wmi_device *wdev; | |
| 683 | + acpi_status status; | |
| 658 | 684 | |
| 659 | − list_for_each_entry(wblock, &wmi_block_list, list) { | |
| 660 | − struct guid_block *gblock = &wblock->gblock; | |
| 685 | + wdev = wmi_find_event_by_notify_id(event); | |
| 686 | + if (IS_ERR(wdev)) | |
| 687 | + return AE_NOT_FOUND; | |
| 661 | 688 | |
| 662 | − if ((gblock->flags & ACPI_WMI_EVENT) && gblock->notify_id == event) | |
| 663 | − return get_event_data(wblock, out); | |
| 664 | − } | |
| 689 | + wblock = container_of(wdev, struct wmi_block, dev); | |
| 690 | + status = get_event_data(wblock, out); | |
| 665 | 691 | |
| 666 | − return AE_NOT_FOUND; | |
| 692 | + wmi_device_put(wdev); | |
| 693 | + | |
| 694 | + return status; | |
| 667 | 695 | } |
| 668 | 696 | EXPORT_SYMBOL_GPL(wmi_get_event_data); |
| 669 | 697 | |
| @@ -868,7 +896,7 @@ static int wmi_dev_probe(struct device *dev) · 198 unmodified lines | ||
| 868 | 896 | if (wdriver->probe) { |
| 869 | 897 | ret = wdriver->probe(dev_to_wdev(dev), |
| 870 | 898 | find_guid_context(wblock, wdriver)); |
| 871 | − if (!ret) { | |
| 899 | + if (ret) { | |
| 872 | 900 | if (ACPI_FAILURE(wmi_method_enable(wblock, false))) |
| 873 | 901 | dev_warn(dev, "Failed to disable device\n"); |
| 874 | 902 | |
| @@ -876,7 +904,9 @@ static int wmi_dev_probe(struct device *dev) · 1 unmodified line | ||
| 876 | 904 | } |
| 877 | 905 | } |
| 878 | 906 | |
| 879 | − set_bit(WMI_PROBED, &wblock->flags); | |
| 907 | + down_write(&wblock->notify_lock); | |
| 908 | + wblock->driver_ready = true; | |
| 909 | + up_write(&wblock->notify_lock); | |
| 880 | 910 | |
| 881 | 911 | return 0; |
| 882 | 912 | } |
| @@ -886,7 +916,9 @@ static void wmi_dev_remove(struct device *dev) · 3 unmodified lines | ||
| 886 | 916 | struct wmi_block *wblock = dev_to_wblock(dev); |
| 887 | 917 | struct wmi_driver *wdriver = drv_to_wdrv(dev->driver); |
| 888 | 918 | |
| 889 | − clear_bit(WMI_PROBED, &wblock->flags); | |
| 919 | + down_write(&wblock->notify_lock); | |
| 920 | + wblock->driver_ready = false; | |
| 921 | + up_write(&wblock->notify_lock); | |
| 890 | 922 | |
| 891 | 923 | if (wdriver->remove) |
| 892 | 924 | wdriver->remove(dev_to_wdev(dev)); |
| @@ -999,6 +1031,8 @@ static int wmi_create_device(struct device *wmi_bus_dev, · 106 unmodified lines | ||
| 999 | 1031 | wblock->dev.setable = true; |
| 1000 | 1032 | |
| 1001 | 1033 | out_init: |
| 1034 | + init_rwsem(&wblock->notify_lock); | |
| 1035 | + wblock->driver_ready = false; | |
| 1002 | 1036 | wblock->dev.dev.bus = &wmi_bus_type; |
| 1003 | 1037 | wblock->dev.dev.parent = wmi_bus_dev; |
| 1004 | 1038 | |
| @@ -1171,6 +1205,26 @@ acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address, · 166 unmodified lines | ||
| 1171 | 1205 | } |
| 1172 | 1206 | } |
| 1173 | 1207 | |
| 1208 | +static void wmi_notify_driver(struct wmi_block *wblock) | |
| 1209 | +{ | |
| 1210 | + struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver); | |
| 1211 | + struct acpi_buffer data = { ACPI_ALLOCATE_BUFFER, NULL }; | |
| 1212 | + acpi_status status; | |
| 1213 | + | |
| 1214 | + if (!driver->no_notify_data) { | |
| 1215 | + status = get_event_data(wblock, &data); | |
| 1216 | + if (ACPI_FAILURE(status)) { | |
| 1217 | + dev_warn(&wblock->dev.dev, "Failed to get event data\n"); | |
| 1218 | + return; | |
| 1219 | + } | |
| 1220 | + } | |
| 1221 | + | |
| 1222 | + if (driver->notify) | |
| 1223 | + driver->notify(&wblock->dev, data.pointer); | |
| 1224 | + | |
| 1225 | + kfree(data.pointer); | |
| 1226 | +} | |
| 1227 | + | |
| 1174 | 1228 | static int wmi_notify_device(struct device *dev, void *data) |
| 1175 | 1229 | { |
| 1176 | 1230 | struct wmi_block *wblock = dev_to_wblock(dev); |
| @@ -1179,28 +1233,17 @@ static int wmi_notify_device(struct device *dev, void *data) · 2 unmodified lines | ||
| 1179 | 1233 | if (!(wblock->gblock.flags & ACPI_WMI_EVENT && wblock->gblock.notify_id == *event)) |
| 1180 | 1234 | return 0; |
| 1181 | 1235 | |
| 1182 | − /* If a driver is bound, then notify the driver. */ | |
| 1183 | − if (test_bit(WMI_PROBED, &wblock->flags) && wblock->dev.dev.driver) { | |
| 1184 | − struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver); | |
| 1185 | − struct acpi_buffer evdata = { ACPI_ALLOCATE_BUFFER, NULL }; | |
| 1186 | − acpi_status status; | |
| 1187 | − | |
| 1188 | − if (!driver->no_notify_data) { | |
| 1189 | − status = get_event_data(wblock, &evdata); | |
| 1190 | − if (ACPI_FAILURE(status)) { | |
| 1191 | − dev_warn(&wblock->dev.dev, "failed to get event data\n"); | |
| 1192 | − return -EIO; | |
| 1193 | − } | |
| 1194 | − } | |
| 1195 | − | |
| 1196 | − if (driver->notify) | |
| 1197 | − driver->notify(&wblock->dev, evdata.pointer); | |
| 1198 | − | |
| 1199 | − kfree(evdata.pointer); | |
| 1200 | − } else if (wblock->handler) { | |
| 1201 | − /* Legacy handler */ | |
| 1202 | − wblock->handler(*event, wblock->handler_data); | |
| 1236 | + down_read(&wblock->notify_lock); | |
| 1237 | + /* The WMI driver notify handler conflicts with the legacy WMI handler. | |
| 1238 | + * Because of this the WMI driver notify handler takes precedence. | |
| 1239 | + */ | |
| 1240 | + if (wblock->dev.dev.driver && wblock->driver_ready) { | |
| 1241 | + wmi_notify_driver(wblock); | |
| 1242 | + } else { | |
| 1243 | + if (wblock->handler) | |
| 1244 | + wblock->handler(*event, wblock->handler_data); | |
| 1203 | 1245 | } |
| 1246 | + up_read(&wblock->notify_lock); | |
| 1204 | 1247 | |
| 1205 | 1248 | acpi_bus_generate_netlink_event(wblock->acpi_device->pnp.device_class, |
| 1206 | 1249 | dev_name(&wblock->dev.dev), *event, 0); |
| @@ -392,7 +392,7 @@ static int max597x_regmap_read_clear(struct regmap *map, unsigned int reg, · 391 unmodified lines | ||
| 392 | 392 | return ret; |
| 393 | 393 | |
| 394 | 394 | if (*val) |
| 395 | − return regmap_write(map, reg, *val); | |
| 395 | + return regmap_write(map, reg, 0); | |
| 396 | 396 | |
| 397 | 397 | return 0; |
| 398 | 398 | } |
| @@ -157,7 +157,17 @@ static int pwm_regulator_get_voltage(struct regulator_dev *rdev) · 156 unmodified lines | ||
| 157 | 157 | |
| 158 | 158 | pwm_get_state(drvdata->pwm, &pstate); |
| 159 | 159 | |
| 160 | + if (!pstate.enabled) { | |
| 161 | + if (pstate.polarity == PWM_POLARITY_INVERSED) | |
| 162 | + pstate.duty_cycle = pstate.period; | |
| 163 | + else | |
| 164 | + pstate.duty_cycle = 0; | |
| 165 | + } | |
| 166 | + | |
| 160 | 167 | voltage = pwm_get_relative_duty_cycle(&pstate, duty_unit); |
| 168 | + if (voltage < min(max_uV_duty, min_uV_duty) || | |
| 169 | + voltage > max(max_uV_duty, min_uV_duty)) | |
| 170 | + return -ENOTRECOVERABLE; | |
| 161 | 171 | |
| 162 | 172 | /* |
| 163 | 173 | * The dutycycle for min_uV might be greater than the one for max_uV. |
| @@ -313,6 +323,32 @@ static int pwm_regulator_init_continuous(struct platform_device *pdev, · 149 unmodified lines | ||
| 313 | 323 | return 0; |
| 314 | 324 | } |
| 315 | 325 | |
| 326 | +static int pwm_regulator_init_boot_on(struct platform_device *pdev, | |
| 327 | + struct pwm_regulator_data *drvdata, | |
| 328 | + const struct regulator_init_data *init_data) | |
| 329 | +{ | |
| 330 | + struct pwm_state pstate; | |
| 331 | + | |
| 332 | + if (!init_data->constraints.boot_on || drvdata->enb_gpio) | |
| 333 | + return 0; | |
| 334 | + | |
| 335 | + pwm_get_state(drvdata->pwm, &pstate); | |
| 336 | + if (pstate.enabled) | |
| 337 | + return 0; | |
| 338 | + | |
| 339 | + /* | |
| 340 | + * Update the duty cycle so the output does not change | |
| 341 | + * when the regulator core enables the regulator (and | |
| 342 | + * thus the PWM channel). | |
| 343 | + */ | |
| 344 | + if (pstate.polarity == PWM_POLARITY_INVERSED) | |
| 345 | + pstate.duty_cycle = pstate.period; | |
| 346 | + else | |
| 347 | + pstate.duty_cycle = 0; | |
| 348 | + | |
| 349 | + return pwm_apply_might_sleep(drvdata->pwm, &pstate); | |
| 350 | +} | |
| 351 | + | |
| 316 | 352 | static int pwm_regulator_probe(struct platform_device *pdev) |
| 317 | 353 | { |
| 318 | 354 | const struct regulator_init_data *init_data; |
| @@ -372,6 +408,13 @@ static int pwm_regulator_probe(struct platform_device *pdev) · 53 unmodified lines | ||
| 372 | 408 | if (ret) |
| 373 | 409 | return ret; |
| 374 | 410 | |
| 411 | + ret = pwm_regulator_init_boot_on(pdev, drvdata, init_data); | |
| 412 | + if (ret) { | |
| 413 | + dev_err(&pdev->dev, "Failed to apply boot_on settings: %d\n", | |
| 414 | + ret); | |
| 415 | + return ret; | |
| 416 | + } | |
| 417 | + | |
| 375 | 418 | regulator = devm_regulator_register(&pdev->dev, |
| 376 | 419 | &drvdata->desc, &config); |
| 377 | 420 | if (IS_ERR(regulator)) { |
| @@ -726,9 +726,25 @@ static int ti_abb_probe(struct platform_device *pdev) · 725 unmodified lines | ||
| 726 | 726 | return PTR_ERR(abb->setup_reg); |
| 727 | 727 | } |
| 728 | 728 | |
| 729 | − abb->int_base = devm_platform_ioremap_resource_byname(pdev, "int-address"); | |
| 730 | − if (IS_ERR(abb->int_base)) | |
| 731 | − return PTR_ERR(abb->int_base); | |
| 729 | + pname = "int-address"; | |
| 730 | + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); | |
| 731 | + if (!res) { | |
| 732 | + dev_err(dev, "Missing '%s' IO resource\n", pname); | |
| 733 | + return -ENODEV; | |
| 734 | + } | |
| 735 | + /* | |
| 736 | + * The MPU interrupt status register (PRM_IRQSTATUS_MPU) is | |
| 737 | + * shared between regulator-abb-{ivahd,dspeve,gpu} driver | |
| 738 | + * instances. Therefore use devm_ioremap() rather than | |
| 739 | + * devm_platform_ioremap_resource_byname() to avoid busy | |
| 740 | + * resource region conflicts. | |
| 741 | + */ | |
| 742 | + abb->int_base = devm_ioremap(dev, res->start, | |
| 743 | + resource_size(res)); | |
| 744 | + if (!abb->int_base) { | |
| 745 | + dev_err(dev, "Unable to map '%s'\n", pname); | |
| 746 | + return -ENOMEM; | |
| 747 | + } | |
| 732 | 748 | |
| 733 | 749 | /* Map Optional resources */ |
| 734 | 750 | pname = "efuse-address"; |
| @@ -371,7 +371,6 @@ static u16 initio_se2_rd(unsigned long base, u8 addr) · 370 unmodified lines | ||
| 371 | 371 | */ |
| 372 | 372 | static void initio_se2_wr(unsigned long base, u8 addr, u16 val) |
| 373 | 373 | { |
| 374 | − u8 rb; | |
| 375 | 374 | u8 instr; |
| 376 | 375 | int i; |
| 377 | 376 | |
| @@ -400,7 +399,7 @@ static void initio_se2_wr(unsigned long base, u8 addr, u16 val) · 22 unmodified lines | ||
| 400 | 399 | udelay(30); |
| 401 | 400 | outb(SE2CS, base + TUL_NVRAM); /* -CLK */ |
| 402 | 401 | udelay(30); |
| 403 | − if ((rb = inb(base + TUL_NVRAM)) & SE2DI) | |
| 402 | + if (inb(base + TUL_NVRAM) & SE2DI) | |
| 404 | 403 | break; /* write complete */ |
| 405 | 404 | } |
| 406 | 405 | outb(0, base + TUL_NVRAM); /* -CS */ |
| @@ -3387,7 +3387,7 @@ static enum sci_status isci_io_request_build(struct isci_host *ihost, · 3386 unmodified lines | ||
| 3387 | 3387 | return SCI_FAILURE; |
| 3388 | 3388 | } |
| 3389 | 3389 | |
| 3390 | − return SCI_SUCCESS; | |
| 3390 | + return status; | |
| 3391 | 3391 | } |
| 3392 | 3392 | |
| 3393 | 3393 | static struct isci_request *isci_request_from_tag(struct isci_host *ihost, u16 tag) |
| @@ -61,11 +61,11 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd); · 60 unmodified lines | ||
| 61 | 61 | static enum scsi_disposition scsi_try_to_abort_cmd(const struct scsi_host_template *, |
| 62 | 62 | struct scsi_cmnd *); |
| 63 | 63 | |
| 64 | −void scsi_eh_wakeup(struct Scsi_Host *shost) | |
| 64 | +void scsi_eh_wakeup(struct Scsi_Host *shost, unsigned int busy) | |
| 65 | 65 | { |
| 66 | 66 | lockdep_assert_held(shost->host_lock); |
| 67 | 67 | |
| 68 | − if (scsi_host_busy(shost) == shost->host_failed) { | |
| 68 | + if (busy == shost->host_failed) { | |
| 69 | 69 | trace_scsi_eh_wakeup(shost); |
| 70 | 70 | wake_up_process(shost->ehandler); |
| 71 | 71 | SCSI_LOG_ERROR_RECOVERY(5, shost_printk(KERN_INFO, shost, |
| @@ -88,7 +88,7 @@ void scsi_schedule_eh(struct Scsi_Host *shost) · 16 unmodified lines | ||
| 88 | 88 | if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 || |
| 89 | 89 | scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) { |
| 90 | 90 | shost->host_eh_scheduled++; |
| 91 | − scsi_eh_wakeup(shost); | |
| 91 | + scsi_eh_wakeup(shost, scsi_host_busy(shost)); | |
| 92 | 92 | } |
| 93 | 93 | |
| 94 | 94 | spin_unlock_irqrestore(shost->host_lock, flags); |
| @@ -286,7 +286,7 @@ static void scsi_eh_inc_host_failed(struct rcu_head *head) · 191 unmodified lines | ||
| 286 | 286 | |
| 287 | 287 | spin_lock_irqsave(shost->host_lock, flags); |
| 288 | 288 | shost->host_failed++; |
| 289 | − scsi_eh_wakeup(shost); | |
| 289 | + scsi_eh_wakeup(shost, scsi_host_busy(shost)); | |
| 290 | 290 | spin_unlock_irqrestore(shost->host_lock, flags); |
| 291 | 291 | } |
| 292 | 292 | |
| @@ -280,7 +280,7 @@ static void scsi_dec_host_busy(struct Scsi_Host *shost, struct scsi_cmnd *cmd) · 279 unmodified lines | ||
| 280 | 280 | if (unlikely(scsi_host_in_recovery(shost))) { |
| 281 | 281 | spin_lock_irqsave(shost->host_lock, flags); |
| 282 | 282 | if (shost->host_failed || shost->host_eh_scheduled) |
| 283 | − scsi_eh_wakeup(shost); | |
| 283 | + scsi_eh_wakeup(shost, scsi_host_busy(shost)); | |
| 284 | 284 | spin_unlock_irqrestore(shost->host_lock, flags); |
| 285 | 285 | } |
| 286 | 286 | rcu_read_unlock(); |
| @@ -92,7 +92,7 @@ extern void scmd_eh_abort_handler(struct work_struct *work); · 91 unmodified lines | ||
| 92 | 92 | extern enum blk_eh_timer_return scsi_timeout(struct request *req); |
| 93 | 93 | extern int scsi_error_handler(void *host); |
| 94 | 94 | extern enum scsi_disposition scsi_decide_disposition(struct scsi_cmnd *cmd); |
| 95 | −extern void scsi_eh_wakeup(struct Scsi_Host *shost); | |
| 95 | +extern void scsi_eh_wakeup(struct Scsi_Host *shost, unsigned int busy); | |
| 96 | 96 | extern void scsi_eh_scmd_add(struct scsi_cmnd *); |
| 97 | 97 | void scsi_eh_ready_devs(struct Scsi_Host *shost, |
| 98 | 98 | struct list_head *work_q, |
| @@ -330,6 +330,7 @@ enum storvsc_request_type { · 329 unmodified lines | ||
| 330 | 330 | */ |
| 331 | 331 | |
| 332 | 332 | static int storvsc_ringbuffer_size = (128 * 1024); |
| 333 | +static int aligned_ringbuffer_size; | |
| 333 | 334 | static u32 max_outstanding_req_per_channel; |
| 334 | 335 | static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth); |
| 335 | 336 | |
| @@ -687,8 +688,8 @@ static void handle_sc_creation(struct vmbus_channel *new_sc) · 351 unmodified lines | ||
| 687 | 688 | new_sc->next_request_id_callback = storvsc_next_request_id; |
| 688 | 689 | |
| 689 | 690 | ret = vmbus_open(new_sc, |
| 690 | − storvsc_ringbuffer_size, | |
| 691 | − storvsc_ringbuffer_size, | |
| 691 | + aligned_ringbuffer_size, | |
| 692 | + aligned_ringbuffer_size, | |
| 692 | 693 | (void *)&props, |
| 693 | 694 | sizeof(struct vmstorage_channel_properties), |
| 694 | 695 | storvsc_on_channel_callback, new_sc); |
| @@ -1973,7 +1974,7 @@ static int storvsc_probe(struct hv_device *device, · 1278 unmodified lines | ||
| 1973 | 1974 | dma_set_min_align_mask(&device->device, HV_HYP_PAGE_SIZE - 1); |
| 1974 | 1975 | |
| 1975 | 1976 | stor_device->port_number = host->host_no; |
| 1976 | − ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size, is_fc); | |
| 1977 | + ret = storvsc_connect_to_vsp(device, aligned_ringbuffer_size, is_fc); | |
| 1977 | 1978 | if (ret) |
| 1978 | 1979 | goto err_out1; |
| 1979 | 1980 | |
| @@ -2164,7 +2165,7 @@ static int storvsc_resume(struct hv_device *hv_dev) · 184 unmodified lines | ||
| 2164 | 2165 | { |
| 2165 | 2166 | int ret; |
| 2166 | 2167 | |
| 2167 | − ret = storvsc_connect_to_vsp(hv_dev, storvsc_ringbuffer_size, | |
| 2168 | + ret = storvsc_connect_to_vsp(hv_dev, aligned_ringbuffer_size, | |
| 2168 | 2169 | hv_dev_is_fc(hv_dev)); |
| 2169 | 2170 | return ret; |
| 2170 | 2171 | } |
| @@ -2198,8 +2199,9 @@ static int __init storvsc_drv_init(void) · 27 unmodified lines | ||
| 2198 | 2199 | * the ring buffer indices) by the max request size (which is |
| 2199 | 2200 | * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64) |
| 2200 | 2201 | */ |
| 2202 | + aligned_ringbuffer_size = VMBUS_RING_SIZE(storvsc_ringbuffer_size); | |
| 2201 | 2203 | max_outstanding_req_per_channel = |
| 2202 | − ((storvsc_ringbuffer_size - PAGE_SIZE) / | |
| 2204 | + ((aligned_ringbuffer_size - PAGE_SIZE) / | |
| 2203 | 2205 | ALIGN(MAX_MULTIPAGE_BUFFER_PACKET + |
| 2204 | 2206 | sizeof(struct vstor_packet) + sizeof(u64), |
| 2205 | 2207 | sizeof(u64))); |
| @@ -188,8 +188,6 @@ static void virtscsi_vq_done(struct virtio_scsi *vscsi, · 187 unmodified lines | ||
| 188 | 188 | while ((buf = virtqueue_get_buf(vq, &len)) != NULL) |
| 189 | 189 | fn(vscsi, buf); |
| 190 | 190 | |
| 191 | − if (unlikely(virtqueue_is_broken(vq))) | |
| 192 | − break; | |
| 193 | 191 | } while (!virtqueue_enable_cb(vq)); |
| 194 | 192 | spin_unlock_irqrestore(&virtscsi_vq->vq_lock, flags); |
| 195 | 193 | } |
| @@ -296,14 +296,14 @@ struct apple_mbox *apple_mbox_get(struct device *dev, int index) · 295 unmodified lines | ||
| 296 | 296 | of_node_put(args.np); |
| 297 | 297 | |
| 298 | 298 | if (!pdev) |
| 299 | − return ERR_PTR(EPROBE_DEFER); | |
| 299 | + return ERR_PTR(-EPROBE_DEFER); | |
| 300 | 300 | |
| 301 | 301 | mbox = platform_get_drvdata(pdev); |
| 302 | 302 | if (!mbox) |
| 303 | − return ERR_PTR(EPROBE_DEFER); | |
| 303 | + return ERR_PTR(-EPROBE_DEFER); | |
| 304 | 304 | |
| 305 | 305 | if (!device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_CONSUMER)) |
| 306 | − return ERR_PTR(ENODEV); | |
| 306 | + return ERR_PTR(-ENODEV); | |
| 307 | 307 | |
| 308 | 308 | return mbox; |
| 309 | 309 | } |
| @@ -19,7 +19,7 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <linux/platform_device.h> |
| 20 | 20 | #include <linux/slab.h> |
| 21 | 21 | #include <linux/spi/spi.h> |
| 22 | −#include <linux/spi/spi-mem.h> | |
| 22 | +#include <linux/mtd/spi-nor.h> | |
| 23 | 23 | #include <linux/sysfs.h> |
| 24 | 24 | #include <linux/types.h> |
| 25 | 25 | #include "spi-bcm-qspi.h" |
| @@ -1221,7 +1221,7 @@ static int bcm_qspi_exec_mem_op(struct spi_mem *mem, · 1195 unmodified lines | ||
| 1221 | 1221 | |
| 1222 | 1222 | /* non-aligned and very short transfers are handled by MSPI */ |
| 1223 | 1223 | if (!IS_ALIGNED((uintptr_t)addr, 4) || !IS_ALIGNED((uintptr_t)buf, 4) || |
| 1224 | − len < 4) | |
| 1224 | + len < 4 || op->cmd.opcode == SPINOR_OP_RDSFDP) | |
| 1225 | 1225 | mspi_read = true; |
| 1226 | 1226 | |
| 1227 | 1227 | if (!has_bspi(qspi) || mspi_read) |
| @@ -317,6 +317,15 @@ static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx) · 316 unmodified lines | ||
| 317 | 317 | xspi->rx_bytes -= nrx; |
| 318 | 318 | |
| 319 | 319 | while (ntx || nrx) { |
| 320 | + if (nrx) { | |
| 321 | + u8 data = cdns_spi_read(xspi, CDNS_SPI_RXD); | |
| 322 | + | |
| 323 | + if (xspi->rxbuf) | |
| 324 | + *xspi->rxbuf++ = data; | |
| 325 | + | |
| 326 | + nrx--; | |
| 327 | + } | |
| 328 | + | |
| 320 | 329 | if (ntx) { |
| 321 | 330 | if (xspi->txbuf) |
| 322 | 331 | cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++); |
| @@ -326,14 +335,6 @@ static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx) · 3 unmodified lines | ||
| 326 | 335 | ntx--; |
| 327 | 336 | } |
| 328 | 337 | |
| 329 | − if (nrx) { | |
| 330 | − u8 data = cdns_spi_read(xspi, CDNS_SPI_RXD); | |
| 331 | − | |
| 332 | − if (xspi->rxbuf) | |
| 333 | − *xspi->rxbuf++ = data; | |
| 334 | − | |
| 335 | − nrx--; | |
| 336 | − } | |
| 337 | 338 | } |
| 338 | 339 | } |
| 339 | 340 | |
| @@ -244,7 +244,10 @@ static int cs42l43_spi_probe(struct platform_device *pdev) · 243 unmodified lines | ||
| 244 | 244 | priv->ctlr->use_gpio_descriptors = true; |
| 245 | 245 | priv->ctlr->auto_runtime_pm = true; |
| 246 | 246 | |
| 247 | − devm_pm_runtime_enable(priv->dev); | |
| 247 | + ret = devm_pm_runtime_enable(priv->dev); | |
| 248 | + if (ret) | |
| 249 | + return ret; | |
| 250 | + | |
| 248 | 251 | pm_runtime_idle(priv->dev); |
| 249 | 252 | |
| 250 | 253 | regmap_write(priv->regmap, CS42L43_TRAN_CONFIG6, CS42L43_FIFO_SIZE - 1); |
| @@ -377,6 +377,11 @@ static const struct spi_controller_mem_ops hisi_sfc_v3xx_mem_ops = { · 376 unmodified lines | ||
| 377 | 377 | static irqreturn_t hisi_sfc_v3xx_isr(int irq, void *data) |
| 378 | 378 | { |
| 379 | 379 | struct hisi_sfc_v3xx_host *host = data; |
| 380 | + u32 reg; | |
| 381 | + | |
| 382 | + reg = readl(host->regbase + HISI_SFC_V3XX_INT_STAT); | |
| 383 | + if (!reg) | |
| 384 | + return IRQ_NONE; | |
| 380 | 385 | |
| 381 | 386 | hisi_sfc_v3xx_disable_int(host); |
| 382 | 387 | |
| @@ -1344,7 +1344,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx, · 1343 unmodified lines | ||
| 1344 | 1344 | controller->dma_tx = dma_request_chan(dev, "tx"); |
| 1345 | 1345 | if (IS_ERR(controller->dma_tx)) { |
| 1346 | 1346 | ret = PTR_ERR(controller->dma_tx); |
| 1347 | − dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret); | |
| 1347 | + dev_err_probe(dev, ret, "can't get the TX DMA channel!\n"); | |
| 1348 | 1348 | controller->dma_tx = NULL; |
| 1349 | 1349 | goto err; |
| 1350 | 1350 | } |
| @@ -1353,7 +1353,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx, · 2 unmodified lines | ||
| 1353 | 1353 | controller->dma_rx = dma_request_chan(dev, "rx"); |
| 1354 | 1354 | if (IS_ERR(controller->dma_rx)) { |
| 1355 | 1355 | ret = PTR_ERR(controller->dma_rx); |
| 1356 | − dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret); | |
| 1356 | + dev_err_probe(dev, ret, "can't get the RX DMA channel!\n"); | |
| 1357 | 1357 | controller->dma_rx = NULL; |
| 1358 | 1358 | goto err; |
| 1359 | 1359 | } |
| @@ -76,6 +76,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = { · 75 unmodified lines | ||
| 76 | 76 | { PCI_VDEVICE(INTEL, 0x7a24), (unsigned long)&cnl_info }, |
| 77 | 77 | { PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info }, |
| 78 | 78 | { PCI_VDEVICE(INTEL, 0x7e23), (unsigned long)&cnl_info }, |
| 79 | + { PCI_VDEVICE(INTEL, 0x7f24), (unsigned long)&cnl_info }, | |
| 79 | 80 | { PCI_VDEVICE(INTEL, 0x9d24), (unsigned long)&cnl_info }, |
| 80 | 81 | { PCI_VDEVICE(INTEL, 0x9da4), (unsigned long)&cnl_info }, |
| 81 | 82 | { PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&cnl_info }, |
| @@ -84,7 +85,6 @@ static const struct pci_device_id intel_spi_pci_ids[] = { · 2 unmodified lines | ||
| 84 | 85 | { PCI_VDEVICE(INTEL, 0xa2a4), (unsigned long)&cnl_info }, |
| 85 | 86 | { PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info }, |
| 86 | 87 | { PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&cnl_info }, |
| 87 | − { PCI_VDEVICE(INTEL, 0xae23), (unsigned long)&cnl_info }, | |
| 88 | 88 | { }, |
| 89 | 89 | }; |
| 90 | 90 | MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids); |
| @@ -136,14 +136,14 @@ struct sh_msiof_spi_priv { · 135 unmodified lines | ||
| 136 | 136 | |
| 137 | 137 | /* SIFCTR */ |
| 138 | 138 | #define SIFCTR_TFWM_MASK GENMASK(31, 29) /* Transmit FIFO Watermark */ |
| 139 | −#define SIFCTR_TFWM_64 (0 << 29) /* Transfer Request when 64 empty stages */ | |
| 140 | −#define SIFCTR_TFWM_32 (1 << 29) /* Transfer Request when 32 empty stages */ | |
| 141 | −#define SIFCTR_TFWM_24 (2 << 29) /* Transfer Request when 24 empty stages */ | |
| 142 | −#define SIFCTR_TFWM_16 (3 << 29) /* Transfer Request when 16 empty stages */ | |
| 143 | −#define SIFCTR_TFWM_12 (4 << 29) /* Transfer Request when 12 empty stages */ | |
| 144 | −#define SIFCTR_TFWM_8 (5 << 29) /* Transfer Request when 8 empty stages */ | |
| 145 | −#define SIFCTR_TFWM_4 (6 << 29) /* Transfer Request when 4 empty stages */ | |
| 146 | −#define SIFCTR_TFWM_1 (7 << 29) /* Transfer Request when 1 empty stage */ | |
| 139 | +#define SIFCTR_TFWM_64 (0UL << 29) /* Transfer Request when 64 empty stages */ | |
| 140 | +#define SIFCTR_TFWM_32 (1UL << 29) /* Transfer Request when 32 empty stages */ | |
| 141 | +#define SIFCTR_TFWM_24 (2UL << 29) /* Transfer Request when 24 empty stages */ | |
| 142 | +#define SIFCTR_TFWM_16 (3UL << 29) /* Transfer Request when 16 empty stages */ | |
| 143 | +#define SIFCTR_TFWM_12 (4UL << 29) /* Transfer Request when 12 empty stages */ | |
| 144 | +#define SIFCTR_TFWM_8 (5UL << 29) /* Transfer Request when 8 empty stages */ | |
| 145 | +#define SIFCTR_TFWM_4 (6UL << 29) /* Transfer Request when 4 empty stages */ | |
| 146 | +#define SIFCTR_TFWM_1 (7UL << 29) /* Transfer Request when 1 empty stage */ | |
| 147 | 147 | #define SIFCTR_TFUA_MASK GENMASK(26, 20) /* Transmit FIFO Usable Area */ |
| 148 | 148 | #define SIFCTR_TFUA_SHIFT 20 |
| 149 | 149 | #define SIFCTR_TFUA(i) ((i) << SIFCTR_TFUA_SHIFT) |
| @@ -1717,6 +1717,10 @@ static int __spi_pump_transfer_message(struct spi_controller *ctlr, · 1716 unmodified lines | ||
| 1717 | 1717 | pm_runtime_put_noidle(ctlr->dev.parent); |
| 1718 | 1718 | dev_err(&ctlr->dev, "Failed to power device: %d\n", |
| 1719 | 1719 | ret); |
| 1720 | + | |
| 1721 | + msg->status = ret; | |
| 1722 | + spi_finalize_current_message(ctlr); | |
| 1723 | + | |
| 1720 | 1724 | return ret; |
| 1721 | 1725 | } |
| 1722 | 1726 | } |
| @@ -49,7 +49,6 @@ · 48 unmodified lines | ||
| 49 | 49 | */ |
| 50 | 50 | #define DEFAULT_DURATION_JIFFIES (6) |
| 51 | 51 | |
| 52 | −static unsigned int target_mwait; | |
| 53 | 52 | static struct dentry *debug_dir; |
| 54 | 53 | static bool poll_pkg_cstate_enable; |
| 55 | 54 | |
| @@ -312,34 +311,6 @@ MODULE_PARM_DESC(window_size, "sliding window in number of clamping cycles\n" · 256 unmodified lines | ||
| 312 | 311 | "\twindow size results in slower response time but more smooth\n" |
| 313 | 312 | "\tclamping results. default to 2."); |
| 314 | 313 | |
| 315 | −static void find_target_mwait(void) | |
| 316 | −{ | |
| 317 | − unsigned int eax, ebx, ecx, edx; | |
| 318 | − unsigned int highest_cstate = 0; | |
| 319 | − unsigned int highest_subcstate = 0; | |
| 320 | − int i; | |
| 321 | − | |
| 322 | − if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF) | |
| 323 | − return; | |
| 324 | − | |
| 325 | − cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx); | |
| 326 | − | |
| 327 | − if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) || | |
| 328 | − !(ecx & CPUID5_ECX_INTERRUPT_BREAK)) | |
| 329 | − return; | |
| 330 | − | |
| 331 | − edx >>= MWAIT_SUBSTATE_SIZE; | |
| 332 | − for (i = 0; i < 7 && edx; i++, edx >>= MWAIT_SUBSTATE_SIZE) { | |
| 333 | − if (edx & MWAIT_SUBSTATE_MASK) { | |
| 334 | − highest_cstate = i; | |
| 335 | − highest_subcstate = edx & MWAIT_SUBSTATE_MASK; | |
| 336 | − } | |
| 337 | − } | |
| 338 | − target_mwait = (highest_cstate << MWAIT_SUBSTATE_SIZE) | | |
| 339 | − (highest_subcstate - 1); | |
| 340 | − | |
| 341 | −} | |
| 342 | − | |
| 343 | 314 | struct pkg_cstate_info { |
| 344 | 315 | bool skip; |
| 345 | 316 | int msr_index; |
| @@ -759,9 +730,6 @@ static int __init powerclamp_probe(void) · 413 unmodified lines | ||
| 759 | 730 | return -ENODEV; |
| 760 | 731 | } |
| 761 | 732 | |
| 762 | − /* find the deepest mwait value */ | |
| 763 | − find_target_mwait(); | |
| 764 | − | |
| 765 | 733 | return 0; |
| 766 | 734 | } |
| 767 | 735 | |
| @@ -1715,7 +1715,7 @@ static int bch2_discard_one_bucket(struct btree_trans *trans, · 1714 unmodified lines | ||
| 1715 | 1715 | * This works without any other locks because this is the only |
| 1716 | 1716 | * thread that removes items from the need_discard tree |
| 1717 | 1717 | */ |
| 1718 | − bch2_trans_unlock(trans); | |
| 1718 | + bch2_trans_unlock_long(trans); | |
| 1719 | 1719 | blkdev_issue_discard(ca->disk_sb.bdev, |
| 1720 | 1720 | k.k->p.offset * ca->mi.bucket_size, |
| 1721 | 1721 | ca->mi.bucket_size, |
| @@ -92,7 +92,7 @@ static noinline void print_cycle(struct printbuf *out, struct lock_graph *g) · 91 unmodified lines | ||
| 92 | 92 | continue; |
| 93 | 93 | |
| 94 | 94 | bch2_btree_trans_to_text(out, i->trans); |
| 95 | − bch2_prt_task_backtrace(out, task, i == g->g ? 5 : 1); | |
| 95 | + bch2_prt_task_backtrace(out, task, i == g->g ? 5 : 1, GFP_NOWAIT); | |
| 96 | 96 | } |
| 97 | 97 | } |
| 98 | 98 | |
| @@ -227,7 +227,7 @@ static noinline int break_cycle(struct lock_graph *g, struct printbuf *cycle) · 128 unmodified lines | ||
| 227 | 227 | prt_printf(&buf, "backtrace:"); |
| 228 | 228 | prt_newline(&buf); |
| 229 | 229 | printbuf_indent_add(&buf, 2); |
| 230 | − bch2_prt_task_backtrace(&buf, trans->locking_wait.task, 2); | |
| 230 | + bch2_prt_task_backtrace(&buf, trans->locking_wait.task, 2, GFP_NOWAIT); | |
| 231 | 231 | printbuf_indent_sub(&buf, 2); |
| 232 | 232 | prt_newline(&buf); |
| 233 | 233 | } |
| @@ -627,7 +627,7 @@ restart: · 626 unmodified lines | ||
| 627 | 627 | prt_printf(&i->buf, "backtrace:"); |
| 628 | 628 | prt_newline(&i->buf); |
| 629 | 629 | printbuf_indent_add(&i->buf, 2); |
| 630 | − bch2_prt_task_backtrace(&i->buf, task, 0); | |
| 630 | + bch2_prt_task_backtrace(&i->buf, task, 0, GFP_KERNEL); | |
| 631 | 631 | printbuf_indent_sub(&i->buf, 2); |
| 632 | 632 | prt_newline(&i->buf); |
| 633 | 633 | |
| @@ -79,7 +79,7 @@ void bch2_inode_flush_nocow_writes_async(struct bch_fs *c, · 78 unmodified lines | ||
| 79 | 79 | continue; |
| 80 | 80 | |
| 81 | 81 | bio = container_of(bio_alloc_bioset(ca->disk_sb.bdev, 0, |
| 82 | − REQ_OP_FLUSH, | |
| 82 | + REQ_OP_WRITE|REQ_PREFLUSH, | |
| 83 | 83 | GFP_KERNEL, |
| 84 | 84 | &c->nocow_flush_bioset), |
| 85 | 85 | struct nocow_flush, bio); |
| @@ -119,22 +119,19 @@ static int lookup_inode(struct btree_trans *trans, u64 inode_nr, · 118 unmodified lines | ||
| 119 | 119 | if (!ret) |
| 120 | 120 | *snapshot = iter.pos.snapshot; |
| 121 | 121 | err: |
| 122 | − bch_err_msg(trans->c, ret, "fetching inode %llu:%u", inode_nr, *snapshot); | |
| 123 | 122 | bch2_trans_iter_exit(trans, &iter); |
| 124 | 123 | return ret; |
| 125 | 124 | } |
| 126 | 125 | |
| 127 | −static int __lookup_dirent(struct btree_trans *trans, | |
| 126 | +static int lookup_dirent_in_snapshot(struct btree_trans *trans, | |
| 128 | 127 | struct bch_hash_info hash_info, |
| 129 | 128 | subvol_inum dir, struct qstr *name, |
| 130 | − u64 *target, unsigned *type) | |
| 129 | + u64 *target, unsigned *type, u32 snapshot) | |
| 131 | 130 | { |
| 132 | 131 | struct btree_iter iter; |
| 133 | 132 | struct bkey_s_c_dirent d; |
| 134 | − int ret; | |
| 135 | − | |
| 136 | − ret = bch2_hash_lookup(trans, &iter, bch2_dirent_hash_desc, | |
| 137 | − &hash_info, dir, name, 0); | |
| 133 | + int ret = bch2_hash_lookup_in_snapshot(trans, &iter, bch2_dirent_hash_desc, | |
| 134 | + &hash_info, dir, name, 0, snapshot); | |
| 138 | 135 | if (ret) |
| 139 | 136 | return ret; |
| 140 | 137 | |
| @@ -225,15 +222,16 @@ static int lookup_lostfound(struct btree_trans *trans, u32 snapshot, · 84 unmodified lines | ||
| 225 | 222 | |
| 226 | 223 | struct bch_inode_unpacked root_inode; |
| 227 | 224 | struct bch_hash_info root_hash_info; |
| 228 | − ret = lookup_inode(trans, root_inum.inum, &root_inode, &snapshot); | |
| 225 | + u32 root_inode_snapshot = snapshot; | |
| 226 | + ret = lookup_inode(trans, root_inum.inum, &root_inode, &root_inode_snapshot); | |
| 229 | 227 | bch_err_msg(c, ret, "looking up root inode"); |
| 230 | 228 | if (ret) |
| 231 | 229 | return ret; |
| 232 | 230 | |
| 233 | 231 | root_hash_info = bch2_hash_info_init(c, &root_inode); |
| 234 | 232 | |
| 235 | − ret = __lookup_dirent(trans, root_hash_info, root_inum, | |
| 236 | − &lostfound_str, &inum, &d_type); | |
| 233 | + ret = lookup_dirent_in_snapshot(trans, root_hash_info, root_inum, | |
| 234 | + &lostfound_str, &inum, &d_type, snapshot); | |
| 237 | 235 | if (bch2_err_matches(ret, ENOENT)) |
| 238 | 236 | goto create_lostfound; |
| 239 | 237 | |
| @@ -250,7 +248,10 @@ static int lookup_lostfound(struct btree_trans *trans, u32 snapshot, · 10 unmodified lines | ||
| 250 | 248 | * The bch2_check_dirents pass has already run, dangling dirents |
| 251 | 249 | * shouldn't exist here: |
| 252 | 250 | */ |
| 253 | − return lookup_inode(trans, inum, lostfound, &snapshot); | |
| 251 | + ret = lookup_inode(trans, inum, lostfound, &snapshot); | |
| 252 | + bch_err_msg(c, ret, "looking up lost+found %llu:%u in (root inode %llu, snapshot root %u)", | |
| 253 | + inum, snapshot, root_inum.inum, bch2_snapshot_root(c, snapshot)); | |
| 254 | + return ret; | |
| 254 | 255 | |
| 255 | 256 | create_lostfound: |
| 256 | 257 | /* |
| @@ -233,7 +233,7 @@ static void __journal_entry_close(struct journal *j, unsigned closed_val, bool t · 232 unmodified lines | ||
| 233 | 233 | prt_str(&pbuf, "entry size: "); |
| 234 | 234 | prt_human_readable_u64(&pbuf, vstruct_bytes(buf->data)); |
| 235 | 235 | prt_newline(&pbuf); |
| 236 | − bch2_prt_task_backtrace(&pbuf, current, 1); | |
| 236 | + bch2_prt_task_backtrace(&pbuf, current, 1, GFP_NOWAIT); | |
| 237 | 237 | trace_journal_entry_close(c, pbuf.buf); |
| 238 | 238 | printbuf_exit(&pbuf); |
| 239 | 239 | } |
| @@ -1988,7 +1988,8 @@ CLOSURE_CALLBACK(bch2_journal_write) · 1987 unmodified lines | ||
| 1988 | 1988 | percpu_ref_get(&ca->io_ref); |
| 1989 | 1989 | |
| 1990 | 1990 | bio = ca->journal.bio; |
| 1991 | − bio_reset(bio, ca->disk_sb.bdev, REQ_OP_FLUSH); | |
| 1991 | + bio_reset(bio, ca->disk_sb.bdev, | |
| 1992 | + REQ_OP_WRITE|REQ_PREFLUSH); | |
| 1992 | 1993 | bio->bi_end_io = journal_write_endio; |
| 1993 | 1994 | bio->bi_private = ca; |
| 1994 | 1995 | closure_bio_submit(bio, cl); |
| @@ -160,21 +160,16 @@ static inline bool is_visible_key(struct bch_hash_desc desc, subvol_inum inum, s · 159 unmodified lines | ||
| 160 | 160 | } |
| 161 | 161 | |
| 162 | 162 | static __always_inline int |
| 163 | −bch2_hash_lookup(struct btree_trans *trans, | |
| 163 | +bch2_hash_lookup_in_snapshot(struct btree_trans *trans, | |
| 164 | 164 | struct btree_iter *iter, |
| 165 | 165 | const struct bch_hash_desc desc, |
| 166 | 166 | const struct bch_hash_info *info, |
| 167 | 167 | subvol_inum inum, const void *key, |
| 168 | − unsigned flags) | |
| 168 | + unsigned flags, u32 snapshot) | |
| 169 | 169 | { |
| 170 | 170 | struct bkey_s_c k; |
| 171 | − u32 snapshot; | |
| 172 | 171 | int ret; |
| 173 | 172 | |
| 174 | − ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot); | |
| 175 | − if (ret) | |
| 176 | − return ret; | |
| 177 | − | |
| 178 | 173 | for_each_btree_key_upto_norestart(trans, *iter, desc.btree_id, |
| 179 | 174 | SPOS(inum.inum, desc.hash_key(info, key), snapshot), |
| 180 | 175 | POS(inum.inum, U64_MAX), |
| @@ -194,6 +189,19 @@ bch2_hash_lookup(struct btree_trans *trans, · 13 unmodified lines | ||
| 194 | 189 | return ret ?: -BCH_ERR_ENOENT_str_hash_lookup; |
| 195 | 190 | } |
| 196 | 191 | |
| 192 | +static __always_inline int | |
| 193 | +bch2_hash_lookup(struct btree_trans *trans, | |
| 194 | + struct btree_iter *iter, | |
| 195 | + const struct bch_hash_desc desc, | |
| 196 | + const struct bch_hash_info *info, | |
| 197 | + subvol_inum inum, const void *key, | |
| 198 | + unsigned flags) | |
| 199 | +{ | |
| 200 | + u32 snapshot; | |
| 201 | + return bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot) ?: | |
| 202 | + bch2_hash_lookup_in_snapshot(trans, iter, desc, info, inum, key, flags, snapshot); | |
| 203 | +} | |
| 204 | + | |
| 197 | 205 | static __always_inline int |
| 198 | 206 | bch2_hash_hole(struct btree_trans *trans, |
| 199 | 207 | struct btree_iter *iter, |
| @@ -272,14 +272,14 @@ void bch2_print_string_as_lines(const char *prefix, const char *lines) · 271 unmodified lines | ||
| 272 | 272 | console_unlock(); |
| 273 | 273 | } |
| 274 | 274 | |
| 275 | −int bch2_save_backtrace(bch_stacktrace *stack, struct task_struct *task, unsigned skipnr) | |
| 275 | +int bch2_save_backtrace(bch_stacktrace *stack, struct task_struct *task, unsigned skipnr, | |
| 276 | + gfp_t gfp) | |
| 276 | 277 | { |
| 277 | 278 | #ifdef CONFIG_STACKTRACE |
| 278 | 279 | unsigned nr_entries = 0; |
| 279 | − int ret = 0; | |
| 280 | 280 | |
| 281 | 281 | stack->nr = 0; |
| 282 | − ret = darray_make_room(stack, 32); | |
| 282 | + int ret = darray_make_room_gfp(stack, 32, gfp); | |
| 283 | 283 | if (ret) |
| 284 | 284 | return ret; |
| 285 | 285 | |
| @@ -308,10 +308,10 @@ void bch2_prt_backtrace(struct printbuf *out, bch_stacktrace *stack) · 22 unmodified lines | ||
| 308 | 308 | } |
| 309 | 309 | } |
| 310 | 310 | |
| 311 | −int bch2_prt_task_backtrace(struct printbuf *out, struct task_struct *task, unsigned skipnr) | |
| 311 | +int bch2_prt_task_backtrace(struct printbuf *out, struct task_struct *task, unsigned skipnr, gfp_t gfp) | |
| 312 | 312 | { |
| 313 | 313 | bch_stacktrace stack = { 0 }; |
| 314 | − int ret = bch2_save_backtrace(&stack, task, skipnr + 1); | |
| 314 | + int ret = bch2_save_backtrace(&stack, task, skipnr + 1, gfp); | |
| 315 | 315 | |
| 316 | 316 | bch2_prt_backtrace(out, &stack); |
| 317 | 317 | darray_exit(&stack); |
| @@ -348,9 +348,9 @@ void bch2_prt_u64_base2(struct printbuf *, u64); · 347 unmodified lines | ||
| 348 | 348 | void bch2_print_string_as_lines(const char *prefix, const char *lines); |
| 349 | 349 | |
| 350 | 350 | typedef DARRAY(unsigned long) bch_stacktrace; |
| 351 | −int bch2_save_backtrace(bch_stacktrace *stack, struct task_struct *, unsigned); | |
| 351 | +int bch2_save_backtrace(bch_stacktrace *stack, struct task_struct *, unsigned, gfp_t); | |
| 352 | 352 | void bch2_prt_backtrace(struct printbuf *, bch_stacktrace *); |
| 353 | −int bch2_prt_task_backtrace(struct printbuf *, struct task_struct *, unsigned); | |
| 353 | +int bch2_prt_task_backtrace(struct printbuf *, struct task_struct *, unsigned, gfp_t); | |
| 354 | 354 | |
| 355 | 355 | static inline void prt_bdevname(struct printbuf *out, struct block_device *bdev) |
| 356 | 356 | { |
| @@ -11,13 +11,12 @@ · 10 unmodified lines | ||
| 11 | 11 | struct z_erofs_decompress_req { |
| 12 | 12 | struct super_block *sb; |
| 13 | 13 | struct page **in, **out; |
| 14 | − | |
| 15 | 14 | unsigned short pageofs_in, pageofs_out; |
| 16 | 15 | unsigned int inputsize, outputsize; |
| 17 | 16 | |
| 18 | − /* indicate the algorithm will be used for decompression */ | |
| 19 | − unsigned int alg; | |
| 17 | + unsigned int alg; /* the algorithm for decompression */ | |
| 20 | 18 | bool inplace_io, partial_decoding, fillgaps; |
| 19 | + gfp_t gfp; /* allocation flags for extra temporary buffers */ | |
| 21 | 20 | }; |
| 22 | 21 | |
| 23 | 22 | struct z_erofs_decompressor { |
| @@ -111,8 +111,9 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_lz4_decompress_ctx *ctx, · 110 unmodified lines | ||
| 111 | 111 | victim = availables[--top]; |
| 112 | 112 | get_page(victim); |
| 113 | 113 | } else { |
| 114 | − victim = erofs_allocpage(pagepool, | |
| 115 | − GFP_KERNEL | __GFP_NOFAIL); | |
| 114 | + victim = erofs_allocpage(pagepool, rq->gfp); | |
| 115 | + if (!victim) | |
| 116 | + return -ENOMEM; | |
| 116 | 117 | set_page_private(victim, Z_EROFS_SHORTLIVED_PAGE); |
| 117 | 118 | } |
| 118 | 119 | rq->out[i] = victim; |
| @@ -95,7 +95,7 @@ int z_erofs_load_deflate_config(struct super_block *sb, · 94 unmodified lines | ||
| 95 | 95 | } |
| 96 | 96 | |
| 97 | 97 | int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq, |
| 98 | − struct page **pagepool) | |
| 98 | + struct page **pgpl) | |
| 99 | 99 | { |
| 100 | 100 | const unsigned int nrpages_out = |
| 101 | 101 | PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT; |
| @@ -158,8 +158,12 @@ again: · 56 unmodified lines | ||
| 158 | 158 | strm->z.avail_out = min_t(u32, outsz, PAGE_SIZE - pofs); |
| 159 | 159 | outsz -= strm->z.avail_out; |
| 160 | 160 | if (!rq->out[no]) { |
| 161 | − rq->out[no] = erofs_allocpage(pagepool, | |
| 162 | − GFP_KERNEL | __GFP_NOFAIL); | |
| 161 | + rq->out[no] = erofs_allocpage(pgpl, rq->gfp); | |
| 162 | + if (!rq->out[no]) { | |
| 163 | + kout = NULL; | |
| 164 | + err = -ENOMEM; | |
| 165 | + break; | |
| 166 | + } | |
| 163 | 167 | set_page_private(rq->out[no], |
| 164 | 168 | Z_EROFS_SHORTLIVED_PAGE); |
| 165 | 169 | } |
| @@ -211,8 +215,11 @@ again: · 45 unmodified lines | ||
| 211 | 215 | |
| 212 | 216 | DBG_BUGON(erofs_page_is_managed(EROFS_SB(sb), |
| 213 | 217 | rq->in[j])); |
| 214 | − tmppage = erofs_allocpage(pagepool, | |
| 215 | − GFP_KERNEL | __GFP_NOFAIL); | |
| 218 | + tmppage = erofs_allocpage(pgpl, rq->gfp); | |
| 219 | + if (!tmppage) { | |
| 220 | + err = -ENOMEM; | |
| 221 | + goto failed; | |
| 222 | + } | |
| 216 | 223 | set_page_private(tmppage, Z_EROFS_SHORTLIVED_PAGE); |
| 217 | 224 | copy_highpage(tmppage, rq->in[j]); |
| 218 | 225 | rq->in[j] = tmppage; |
| @@ -230,7 +237,7 @@ again: · 11 unmodified lines | ||
| 230 | 237 | break; |
| 231 | 238 | } |
| 232 | 239 | } |
| 233 | − | |
| 240 | +failed: | |
| 234 | 241 | if (zlib_inflateEnd(&strm->z) != Z_OK && !err) |
| 235 | 242 | err = -EIO; |
| 236 | 243 | if (kout) |
| @@ -148,7 +148,7 @@ again: · 147 unmodified lines | ||
| 148 | 148 | } |
| 149 | 149 | |
| 150 | 150 | int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq, |
| 151 | − struct page **pagepool) | |
| 151 | + struct page **pgpl) | |
| 152 | 152 | { |
| 153 | 153 | const unsigned int nrpages_out = |
| 154 | 154 | PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT; |
| @@ -215,8 +215,11 @@ again: · 60 unmodified lines | ||
| 215 | 215 | PAGE_SIZE - pageofs); |
| 216 | 216 | outlen -= strm->buf.out_size; |
| 217 | 217 | if (!rq->out[no] && rq->fillgaps) { /* deduped */ |
| 218 | − rq->out[no] = erofs_allocpage(pagepool, | |
| 219 | − GFP_KERNEL | __GFP_NOFAIL); | |
| 218 | + rq->out[no] = erofs_allocpage(pgpl, rq->gfp); | |
| 219 | + if (!rq->out[no]) { | |
| 220 | + err = -ENOMEM; | |
| 221 | + break; | |
| 222 | + } | |
| 220 | 223 | set_page_private(rq->out[no], |
| 221 | 224 | Z_EROFS_SHORTLIVED_PAGE); |
| 222 | 225 | } |
| @@ -258,8 +261,11 @@ again: · 35 unmodified lines | ||
| 258 | 261 | |
| 259 | 262 | DBG_BUGON(erofs_page_is_managed(EROFS_SB(rq->sb), |
| 260 | 263 | rq->in[j])); |
| 261 | − tmppage = erofs_allocpage(pagepool, | |
| 262 | − GFP_KERNEL | __GFP_NOFAIL); | |
| 264 | + tmppage = erofs_allocpage(pgpl, rq->gfp); | |
| 265 | + if (!tmppage) { | |
| 266 | + err = -ENOMEM; | |
| 267 | + goto failed; | |
| 268 | + } | |
| 263 | 269 | set_page_private(tmppage, Z_EROFS_SHORTLIVED_PAGE); |
| 264 | 270 | copy_highpage(tmppage, rq->in[j]); |
| 265 | 271 | rq->in[j] = tmppage; |
| @@ -277,6 +283,7 @@ again: · 11 unmodified lines | ||
| 277 | 283 | break; |
| 278 | 284 | } |
| 279 | 285 | } |
| 286 | +failed: | |
| 280 | 287 | if (no < nrpages_out && strm->buf.out) |
| 281 | 288 | kunmap(rq->out[no]); |
| 282 | 289 | if (ni < nrpages_in) |
| @@ -459,7 +459,7 @@ static struct erofs_fscache *erofs_fscache_acquire_cookie(struct super_block *sb · 458 unmodified lines | ||
| 459 | 459 | |
| 460 | 460 | inode->i_size = OFFSET_MAX; |
| 461 | 461 | inode->i_mapping->a_ops = &erofs_fscache_meta_aops; |
| 462 | − mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); | |
| 462 | + mapping_set_gfp_mask(inode->i_mapping, GFP_KERNEL); | |
| 463 | 463 | inode->i_blkbits = EROFS_SB(sb)->blkszbits; |
| 464 | 464 | inode->i_private = ctx; |
| 465 | 465 | |
| @@ -60,7 +60,7 @@ static void *erofs_read_inode(struct erofs_buf *buf, · 59 unmodified lines | ||
| 60 | 60 | } else { |
| 61 | 61 | const unsigned int gotten = sb->s_blocksize - *ofs; |
| 62 | 62 | |
| 63 | − copied = kmalloc(vi->inode_isize, GFP_NOFS); | |
| 63 | + copied = kmalloc(vi->inode_isize, GFP_KERNEL); | |
| 64 | 64 | if (!copied) { |
| 65 | 65 | err = -ENOMEM; |
| 66 | 66 | goto err_out; |
| @@ -81,7 +81,7 @@ struct erofs_workgroup *erofs_insert_workgroup(struct super_block *sb, · 80 unmodified lines | ||
| 81 | 81 | repeat: |
| 82 | 82 | xa_lock(&sbi->managed_pslots); |
| 83 | 83 | pre = __xa_cmpxchg(&sbi->managed_pslots, grp->index, |
| 84 | − NULL, grp, GFP_NOFS); | |
| 84 | + NULL, grp, GFP_KERNEL); | |
| 85 | 85 | if (pre) { |
| 86 | 86 | if (xa_is_err(pre)) { |
| 87 | 87 | pre = ERR_PTR(xa_err(pre)); |
| @@ -82,6 +82,9 @@ struct z_erofs_pcluster { · 81 unmodified lines | ||
| 82 | 82 | /* L: indicate several pageofs_outs or not */ |
| 83 | 83 | bool multibases; |
| 84 | 84 | |
| 85 | + /* L: whether extra buffer allocations are best-effort */ | |
| 86 | + bool besteffort; | |
| 87 | + | |
| 85 | 88 | /* A: compressed bvecs (can be cached or inplaced pages) */ |
| 86 | 89 | struct z_erofs_bvec compressed_bvecs[]; |
| 87 | 90 | }; |
| @@ -230,7 +233,7 @@ static int z_erofs_bvec_enqueue(struct z_erofs_bvec_iter *iter, · 142 unmodified lines | ||
| 230 | 233 | struct page *nextpage = *candidate_bvpage; |
| 231 | 234 | |
| 232 | 235 | if (!nextpage) { |
| 233 | − nextpage = erofs_allocpage(pagepool, GFP_NOFS); | |
| 236 | + nextpage = erofs_allocpage(pagepool, GFP_KERNEL); | |
| 234 | 237 | if (!nextpage) |
| 235 | 238 | return -ENOMEM; |
| 236 | 239 | set_page_private(nextpage, Z_EROFS_SHORTLIVED_PAGE); |
| @@ -302,7 +305,7 @@ static struct z_erofs_pcluster *z_erofs_alloc_pcluster(unsigned int size) · 65 unmodified lines | ||
| 302 | 305 | if (nrpages > pcs->maxpages) |
| 303 | 306 | continue; |
| 304 | 307 | |
| 305 | − pcl = kmem_cache_zalloc(pcs->slab, GFP_NOFS); | |
| 308 | + pcl = kmem_cache_zalloc(pcs->slab, GFP_KERNEL); | |
| 306 | 309 | if (!pcl) |
| 307 | 310 | return ERR_PTR(-ENOMEM); |
| 308 | 311 | pcl->pclustersize = size; |
| @@ -563,21 +566,19 @@ static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe) · 254 unmodified lines | ||
| 563 | 566 | __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN; |
| 564 | 567 | unsigned int i; |
| 565 | 568 | |
| 566 | − if (i_blocksize(fe->inode) != PAGE_SIZE) | |
| 567 | − return; | |
| 568 | − if (fe->mode < Z_EROFS_PCLUSTER_FOLLOWED) | |
| 569 | + if (i_blocksize(fe->inode) != PAGE_SIZE || | |
| 570 | + fe->mode < Z_EROFS_PCLUSTER_FOLLOWED) | |
| 569 | 571 | return; |
| 570 | 572 | |
| 571 | 573 | for (i = 0; i < pclusterpages; ++i) { |
| 572 | 574 | struct page *page, *newpage; |
| 573 | 575 | void *t; /* mark pages just found for debugging */ |
| 574 | 576 | |
| 575 | − /* the compressed page was loaded before */ | |
| 577 | + /* Inaccurate check w/o locking to avoid unneeded lookups */ | |
| 576 | 578 | if (READ_ONCE(pcl->compressed_bvecs[i].page)) |
| 577 | 579 | continue; |
| 578 | 580 | |
| 579 | 581 | page = find_get_page(mc, pcl->obj.index + i); |
| 580 | − | |
| 581 | 582 | if (page) { |
| 582 | 583 | t = (void *)((unsigned long)page | 1); |
| 583 | 584 | newpage = NULL; |
| @@ -597,9 +598,13 @@ static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe) · 13 unmodified lines | ||
| 597 | 598 | set_page_private(newpage, Z_EROFS_PREALLOCATED_PAGE); |
| 598 | 599 | t = (void *)((unsigned long)newpage | 1); |
| 599 | 600 | } |
| 600 | − | |
| 601 | − if (!cmpxchg_relaxed(&pcl->compressed_bvecs[i].page, NULL, t)) | |
| 601 | + spin_lock(&pcl->obj.lockref.lock); | |
| 602 | + if (!pcl->compressed_bvecs[i].page) { | |
| 603 | + pcl->compressed_bvecs[i].page = t; | |
| 604 | + spin_unlock(&pcl->obj.lockref.lock); | |
| 602 | 605 | continue; |
| 606 | + } | |
| 607 | + spin_unlock(&pcl->obj.lockref.lock); | |
| 603 | 608 | |
| 604 | 609 | if (page) |
| 605 | 610 | put_page(page); |
| @@ -694,7 +699,7 @@ static void z_erofs_cache_invalidate_folio(struct folio *folio, · 88 unmodified lines | ||
| 694 | 699 | DBG_BUGON(stop > folio_size(folio) || stop < length); |
| 695 | 700 | |
| 696 | 701 | if (offset == 0 && stop == folio_size(folio)) |
| 697 | − while (!z_erofs_cache_release_folio(folio, GFP_NOFS)) | |
| 702 | + while (!z_erofs_cache_release_folio(folio, 0)) | |
| 698 | 703 | cond_resched(); |
| 699 | 704 | } |
| 700 | 705 | |
| @@ -713,36 +718,30 @@ int erofs_init_managed_cache(struct super_block *sb) · 12 unmodified lines | ||
| 713 | 718 | set_nlink(inode, 1); |
| 714 | 719 | inode->i_size = OFFSET_MAX; |
| 715 | 720 | inode->i_mapping->a_ops = &z_erofs_cache_aops; |
| 716 | − mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); | |
| 721 | + mapping_set_gfp_mask(inode->i_mapping, GFP_KERNEL); | |
| 717 | 722 | EROFS_SB(sb)->managed_cache = inode; |
| 718 | 723 | return 0; |
| 719 | 724 | } |
| 720 | 725 | |
| 721 | −static bool z_erofs_try_inplace_io(struct z_erofs_decompress_frontend *fe, | |
| 722 | − struct z_erofs_bvec *bvec) | |
| 723 | −{ | |
| 724 | − struct z_erofs_pcluster *const pcl = fe->pcl; | |
| 725 | − | |
| 726 | − while (fe->icur > 0) { | |
| 727 | − if (!cmpxchg(&pcl->compressed_bvecs[--fe->icur].page, | |
| 728 | − NULL, bvec->page)) { | |
| 729 | − pcl->compressed_bvecs[fe->icur] = *bvec; | |
| 730 | − return true; | |
| 731 | − } | |
| 732 | − } | |
| 733 | − return false; | |
| 734 | −} | |
| 735 | − | |
| 736 | 726 | /* callers must be with pcluster lock held */ |
| 737 | 727 | static int z_erofs_attach_page(struct z_erofs_decompress_frontend *fe, |
| 738 | 728 | struct z_erofs_bvec *bvec, bool exclusive) |
| 739 | 729 | { |
| 730 | + struct z_erofs_pcluster *pcl = fe->pcl; | |
| 740 | 731 | int ret; |
| 741 | 732 | |
| 742 | 733 | if (exclusive) { |
| 743 | 734 | /* give priority for inplaceio to use file pages first */ |
| 744 | − if (z_erofs_try_inplace_io(fe, bvec)) | |
| 735 | + spin_lock(&pcl->obj.lockref.lock); | |
| 736 | + while (fe->icur > 0) { | |
| 737 | + if (pcl->compressed_bvecs[--fe->icur].page) | |
| 738 | + continue; | |
| 739 | + pcl->compressed_bvecs[fe->icur] = *bvec; | |
| 740 | + spin_unlock(&pcl->obj.lockref.lock); | |
| 745 | 741 | return 0; |
| 742 | + } | |
| 743 | + spin_unlock(&pcl->obj.lockref.lock); | |
| 744 | + | |
| 746 | 745 | /* otherwise, check if it can be used as a bvpage */ |
| 747 | 746 | if (fe->mode >= Z_EROFS_PCLUSTER_FOLLOWED && |
| 748 | 747 | !fe->candidate_bvpage) |
| @@ -964,7 +963,7 @@ static int z_erofs_read_fragment(struct super_block *sb, struct page *page, · 215 unmodified lines | ||
| 964 | 963 | } |
| 965 | 964 | |
| 966 | 965 | static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe, |
| 967 | − struct page *page) | |
| 966 | + struct page *page, bool ra) | |
| 968 | 967 | { |
| 969 | 968 | struct inode *const inode = fe->inode; |
| 970 | 969 | struct erofs_map_blocks *const map = &fe->map; |
| @@ -1014,6 +1013,7 @@ repeat: · 43 unmodified lines | ||
| 1014 | 1013 | err = z_erofs_pcluster_begin(fe); |
| 1015 | 1014 | if (err) |
| 1016 | 1015 | goto out; |
| 1016 | + fe->pcl->besteffort |= !ra; | |
| 1017 | 1017 | } |
| 1018 | 1018 | |
| 1019 | 1019 | /* |
| @@ -1280,6 +1280,9 @@ static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be, · 260 unmodified lines | ||
| 1280 | 1280 | .inplace_io = overlapped, |
| 1281 | 1281 | .partial_decoding = pcl->partial, |
| 1282 | 1282 | .fillgaps = pcl->multibases, |
| 1283 | + .gfp = pcl->besteffort ? | |
| 1284 | + GFP_KERNEL | __GFP_NOFAIL : | |
| 1285 | + GFP_NOWAIT | __GFP_NORETRY | |
| 1283 | 1286 | }, be->pagepool); |
| 1284 | 1287 | |
| 1285 | 1288 | /* must handle all compressed pages before actual file pages */ |
| @@ -1322,6 +1325,7 @@ static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be, · 36 unmodified lines | ||
| 1322 | 1325 | pcl->length = 0; |
| 1323 | 1326 | pcl->partial = true; |
| 1324 | 1327 | pcl->multibases = false; |
| 1328 | + pcl->besteffort = false; | |
| 1325 | 1329 | pcl->bvset.nextpage = NULL; |
| 1326 | 1330 | pcl->vcnt = 0; |
| 1327 | 1331 | |
| @@ -1423,23 +1427,26 @@ static void z_erofs_fill_bio_vec(struct bio_vec *bvec, · 95 unmodified lines | ||
| 1423 | 1427 | { |
| 1424 | 1428 | gfp_t gfp = mapping_gfp_mask(mc); |
| 1425 | 1429 | bool tocache = false; |
| 1426 | − struct z_erofs_bvec *zbv = pcl->compressed_bvecs + nr; | |
| 1430 | + struct z_erofs_bvec zbv; | |
| 1427 | 1431 | struct address_space *mapping; |
| 1428 | − struct page *page, *oldpage; | |
| 1432 | + struct page *page; | |
| 1429 | 1433 | int justfound, bs = i_blocksize(f->inode); |
| 1430 | 1434 | |
| 1431 | 1435 | /* Except for inplace pages, the entire page can be used for I/Os */ |
| 1432 | 1436 | bvec->bv_offset = 0; |
| 1433 | 1437 | bvec->bv_len = PAGE_SIZE; |
| 1434 | 1438 | repeat: |
| 1435 | − oldpage = READ_ONCE(zbv->page); | |
| 1436 | − if (!oldpage) | |
| 1439 | + spin_lock(&pcl->obj.lockref.lock); | |
| 1440 | + zbv = pcl->compressed_bvecs[nr]; | |
| 1441 | + page = zbv.page; | |
| 1442 | + justfound = (unsigned long)page & 1UL; | |
| 1443 | + page = (struct page *)((unsigned long)page & ~1UL); | |
| 1444 | + pcl->compressed_bvecs[nr].page = page; | |
| 1445 | + spin_unlock(&pcl->obj.lockref.lock); | |
| 1446 | + if (!page) | |
| 1437 | 1447 | goto out_allocpage; |
| 1438 | 1448 | |
| 1439 | − justfound = (unsigned long)oldpage & 1UL; | |
| 1440 | − page = (struct page *)((unsigned long)oldpage & ~1UL); | |
| 1441 | 1449 | bvec->bv_page = page; |
| 1442 | − | |
| 1443 | 1450 | DBG_BUGON(z_erofs_is_shortlived_page(page)); |
| 1444 | 1451 | /* |
| 1445 | 1452 | * Handle preallocated cached pages. We tried to allocate such pages |
| @@ -1448,7 +1455,6 @@ repeat: · 2 unmodified lines | ||
| 1448 | 1455 | */ |
| 1449 | 1456 | if (page->private == Z_EROFS_PREALLOCATED_PAGE) { |
| 1450 | 1457 | set_page_private(page, 0); |
| 1451 | − WRITE_ONCE(zbv->page, page); | |
| 1452 | 1458 | tocache = true; |
| 1453 | 1459 | goto out_tocache; |
| 1454 | 1460 | } |
| @@ -1459,9 +1465,9 @@ repeat: · 4 unmodified lines | ||
| 1459 | 1465 | * therefore it is impossible for `mapping` to be NULL. |
| 1460 | 1466 | */ |
| 1461 | 1467 | if (mapping && mapping != mc) { |
| 1462 | − if (zbv->offset < 0) | |
| 1463 | − bvec->bv_offset = round_up(-zbv->offset, bs); | |
| 1464 | − bvec->bv_len = round_up(zbv->end, bs) - bvec->bv_offset; | |
| 1468 | + if (zbv.offset < 0) | |
| 1469 | + bvec->bv_offset = round_up(-zbv.offset, bs); | |
| 1470 | + bvec->bv_len = round_up(zbv.end, bs) - bvec->bv_offset; | |
| 1465 | 1471 | return; |
| 1466 | 1472 | } |
| 1467 | 1473 | |
| @@ -1471,7 +1477,6 @@ repeat: · 3 unmodified lines | ||
| 1471 | 1477 | |
| 1472 | 1478 | /* the cached page is still in managed cache */ |
| 1473 | 1479 | if (page->mapping == mc) { |
| 1474 | − WRITE_ONCE(zbv->page, page); | |
| 1475 | 1480 | /* |
| 1476 | 1481 | * The cached page is still available but without a valid |
| 1477 | 1482 | * `->private` pcluster hint. Let's reconnect them. |
| @@ -1503,11 +1508,15 @@ repeat: · 25 unmodified lines | ||
| 1503 | 1508 | put_page(page); |
| 1504 | 1509 | out_allocpage: |
| 1505 | 1510 | page = erofs_allocpage(&f->pagepool, gfp | __GFP_NOFAIL); |
| 1506 | − if (oldpage != cmpxchg(&zbv->page, oldpage, page)) { | |
| 1511 | + spin_lock(&pcl->obj.lockref.lock); | |
| 1512 | + if (pcl->compressed_bvecs[nr].page) { | |
| 1507 | 1513 | erofs_pagepool_add(&f->pagepool, page); |
| 1514 | + spin_unlock(&pcl->obj.lockref.lock); | |
| 1508 | 1515 | cond_resched(); |
| 1509 | 1516 | goto repeat; |
| 1510 | 1517 | } |
| 1518 | + pcl->compressed_bvecs[nr].page = page; | |
| 1519 | + spin_unlock(&pcl->obj.lockref.lock); | |
| 1511 | 1520 | bvec->bv_page = page; |
| 1512 | 1521 | out_tocache: |
| 1513 | 1522 | if (!tocache || bs != PAGE_SIZE || |
| @@ -1685,6 +1694,7 @@ submit_bio_retry: · 171 unmodified lines | ||
| 1685 | 1694 | |
| 1686 | 1695 | if (cur + bvec.bv_len > end) |
| 1687 | 1696 | bvec.bv_len = end - cur; |
| 1697 | + DBG_BUGON(bvec.bv_len < sb->s_blocksize); | |
| 1688 | 1698 | if (!bio_add_page(bio, bvec.bv_page, bvec.bv_len, |
| 1689 | 1699 | bvec.bv_offset)) |
| 1690 | 1700 | goto submit_bio_retry; |
| @@ -1785,7 +1795,7 @@ static void z_erofs_pcluster_readmore(struct z_erofs_decompress_frontend *f, · 94 unmodified lines | ||
| 1785 | 1795 | if (PageUptodate(page)) |
| 1786 | 1796 | unlock_page(page); |
| 1787 | 1797 | else |
| 1788 | − (void)z_erofs_do_read_page(f, page); | |
| 1798 | + (void)z_erofs_do_read_page(f, page, !!rac); | |
| 1789 | 1799 | put_page(page); |
| 1790 | 1800 | } |
| 1791 | 1801 | |
| @@ -1806,7 +1816,7 @@ static int z_erofs_read_folio(struct file *file, struct folio *folio) · 14 unmodified lines | ||
| 1806 | 1816 | f.headoffset = (erofs_off_t)folio->index << PAGE_SHIFT; |
| 1807 | 1817 | |
| 1808 | 1818 | z_erofs_pcluster_readmore(&f, NULL, true); |
| 1809 | − err = z_erofs_do_read_page(&f, &folio->page); | |
| 1819 | + err = z_erofs_do_read_page(&f, &folio->page, false); | |
| 1810 | 1820 | z_erofs_pcluster_readmore(&f, NULL, false); |
| 1811 | 1821 | z_erofs_pcluster_end(&f); |
| 1812 | 1822 | |
| @@ -1847,7 +1857,7 @@ static void z_erofs_readahead(struct readahead_control *rac) · 34 unmodified lines | ||
| 1847 | 1857 | folio = head; |
| 1848 | 1858 | head = folio_get_private(folio); |
| 1849 | 1859 | |
| 1850 | − err = z_erofs_do_read_page(&f, &folio->page); | |
| 1860 | + err = z_erofs_do_read_page(&f, &folio->page, true); | |
| 1851 | 1861 | if (err && err != -EINTR) |
| 1852 | 1862 | erofs_err(inode->i_sb, "readahead error at folio %lu @ nid %llu", |
| 1853 | 1863 | folio->index, EROFS_I(inode)->nid); |
| @@ -501,7 +501,7 @@ static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) · 500 unmodified lines | ||
| 501 | 501 | struct inode *inode = mapping->host; |
| 502 | 502 | struct exfat_inode_info *ei = EXFAT_I(inode); |
| 503 | 503 | loff_t pos = iocb->ki_pos; |
| 504 | − loff_t size = iocb->ki_pos + iov_iter_count(iter); | |
| 504 | + loff_t size = pos + iov_iter_count(iter); | |
| 505 | 505 | int rw = iov_iter_rw(iter); |
| 506 | 506 | ssize_t ret; |
| 507 | 507 | |
| @@ -525,11 +525,10 @@ static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) · 17 unmodified lines | ||
| 525 | 525 | */ |
| 526 | 526 | ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block); |
| 527 | 527 | if (ret < 0) { |
| 528 | − if (rw == WRITE) | |
| 528 | + if (rw == WRITE && ret != -EIOCBQUEUED) | |
| 529 | 529 | exfat_write_failed(mapping, size); |
| 530 | 530 | |
| 531 | − if (ret != -EIOCBQUEUED) | |
| 532 | − return ret; | |
| 531 | + return ret; | |
| 533 | 532 | } else |
| 534 | 533 | size = pos + ret; |
| 535 | 534 | |
| @@ -340,7 +340,7 @@ static ssize_t hugetlbfs_read_iter(struct kiocb *iocb, struct iov_iter *to) · 339 unmodified lines | ||
| 340 | 340 | } else { |
| 341 | 341 | folio_unlock(folio); |
| 342 | 342 | |
| 343 | − if (!folio_test_has_hwpoisoned(folio)) | |
| 343 | + if (!folio_test_hwpoison(folio)) | |
| 344 | 344 | want = nr; |
| 345 | 345 | else { |
| 346 | 346 | /* |
| @@ -2763,9 +2763,7 @@ static int dbBackSplit(dmtree_t *tp, int leafno, bool is_ctl) · 2762 unmodified lines | ||
| 2763 | 2763 | * leafno - the number of the leaf to be updated. |
| 2764 | 2764 | * newval - the new value for the leaf. |
| 2765 | 2765 | * |
| 2766 | − * RETURN VALUES: | |
| 2767 | − * 0 - success | |
| 2768 | − * -EIO - i/o error | |
| 2766 | + * RETURN VALUES: none | |
| 2769 | 2767 | */ |
| 2770 | 2768 | static int dbJoin(dmtree_t *tp, int leafno, int newval, bool is_ctl) |
| 2771 | 2769 | { |
| @@ -2792,10 +2790,6 @@ static int dbJoin(dmtree_t *tp, int leafno, int newval, bool is_ctl) · 20 unmodified lines | ||
| 2792 | 2790 | * get the buddy size (number of words covered) of |
| 2793 | 2791 | * the new value. |
| 2794 | 2792 | */ |
| 2795 | − | |
| 2796 | − if ((newval - tp->dmt_budmin) > BUDMIN) | |
| 2797 | − return -EIO; | |
| 2798 | − | |
| 2799 | 2793 | budsz = BUDSIZE(newval, tp->dmt_budmin); |
| 2800 | 2794 | |
| 2801 | 2795 | /* try to join. |
| @@ -145,21 +145,27 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, · 144 unmodified lines | ||
| 145 | 145 | struct cached_fid *cfid; |
| 146 | 146 | struct cached_fids *cfids; |
| 147 | 147 | const char *npath; |
| 148 | + int retries = 0, cur_sleep = 1; | |
| 148 | 149 | |
| 149 | 150 | if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache || |
| 150 | 151 | is_smb1_server(tcon->ses->server) || (dir_cache_timeout == 0)) |
| 151 | 152 | return -EOPNOTSUPP; |
| 152 | 153 | |
| 153 | 154 | ses = tcon->ses; |
| 154 | − server = cifs_pick_channel(ses); | |
| 155 | 155 | cfids = tcon->cfids; |
| 156 | 156 | |
| 157 | − if (!server->ops->new_lease_key) | |
| 158 | − return -EIO; | |
| 159 | − | |
| 160 | 157 | if (cifs_sb->root == NULL) |
| 161 | 158 | return -ENOENT; |
| 162 | 159 | |
| 160 | +replay_again: | |
| 161 | + /* reinitialize for possible replay */ | |
| 162 | + flags = 0; | |
| 163 | + oplock = SMB2_OPLOCK_LEVEL_II; | |
| 164 | + server = cifs_pick_channel(ses); | |
| 165 | + | |
| 166 | + if (!server->ops->new_lease_key) | |
| 167 | + return -EIO; | |
| 168 | + | |
| 163 | 169 | utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); |
| 164 | 170 | if (!utf16_path) |
| 165 | 171 | return -ENOMEM; |
| @@ -268,6 +274,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, · 102 unmodified lines | ||
| 268 | 274 | */ |
| 269 | 275 | cfid->has_lease = true; |
| 270 | 276 | |
| 277 | + if (retries) { | |
| 278 | + smb2_set_replay(server, &rqst[0]); | |
| 279 | + smb2_set_replay(server, &rqst[1]); | |
| 280 | + } | |
| 281 | + | |
| 271 | 282 | rc = compound_send_recv(xid, ses, server, |
| 272 | 283 | flags, 2, rqst, |
| 273 | 284 | resp_buftype, rsp_iov); |
| @@ -367,6 +378,11 @@ out: · 93 unmodified lines | ||
| 367 | 378 | atomic_inc(&tcon->num_remote_opens); |
| 368 | 379 | } |
| 369 | 380 | kfree(utf16_path); |
| 381 | + | |
| 382 | + if (is_replayable_error(rc) && | |
| 383 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 384 | + goto replay_again; | |
| 385 | + | |
| 370 | 386 | return rc; |
| 371 | 387 | } |
| 372 | 388 | |
| @@ -572,7 +572,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, · 571 unmodified lines | ||
| 572 | 572 | len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp); |
| 573 | 573 | UniStrupr(user); |
| 574 | 574 | } else { |
| 575 | − memset(user, '\0', 2); | |
| 575 | + *(u16 *)user = 0; | |
| 576 | 576 | } |
| 577 | 577 | |
| 578 | 578 | rc = crypto_shash_update(ses->server->secmech.hmacmd5, |
| @@ -396,7 +396,7 @@ cifs_alloc_inode(struct super_block *sb) · 395 unmodified lines | ||
| 396 | 396 | spin_lock_init(&cifs_inode->writers_lock); |
| 397 | 397 | cifs_inode->writers = 0; |
| 398 | 398 | cifs_inode->netfs.inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
| 399 | − cifs_inode->server_eof = 0; | |
| 399 | + cifs_inode->netfs.remote_i_size = 0; | |
| 400 | 400 | cifs_inode->uniqueid = 0; |
| 401 | 401 | cifs_inode->createtime = 0; |
| 402 | 402 | cifs_inode->epoch = 0; |
| @@ -1380,6 +1380,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, · 977 unmodified lines | ||
| 1380 | 1380 | struct inode *src_inode = file_inode(src_file); |
| 1381 | 1381 | struct inode *target_inode = file_inode(dst_file); |
| 1382 | 1382 | struct cifsInodeInfo *src_cifsi = CIFS_I(src_inode); |
| 1383 | + struct cifsInodeInfo *target_cifsi = CIFS_I(target_inode); | |
| 1383 | 1384 | struct cifsFileInfo *smb_file_src; |
| 1384 | 1385 | struct cifsFileInfo *smb_file_target; |
| 1385 | 1386 | struct cifs_tcon *src_tcon; |
| @@ -1428,7 +1429,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, · 42 unmodified lines | ||
| 1428 | 1429 | * Advance the EOF marker after the flush above to the end of the range |
| 1429 | 1430 | * if it's short of that. |
| 1430 | 1431 | */ |
| 1431 | − if (src_cifsi->server_eof < off + len) { | |
| 1432 | + if (src_cifsi->netfs.remote_i_size < off + len) { | |
| 1432 | 1433 | rc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len); |
| 1433 | 1434 | if (rc < 0) |
| 1434 | 1435 | goto unlock; |
| @@ -1452,12 +1453,22 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, · 17 unmodified lines | ||
| 1452 | 1453 | /* Discard all the folios that overlap the destination region. */ |
| 1453 | 1454 | truncate_inode_pages_range(&target_inode->i_data, fstart, fend); |
| 1454 | 1455 | |
| 1456 | + fscache_invalidate(cifs_inode_cookie(target_inode), NULL, | |
| 1457 | + i_size_read(target_inode), 0); | |
| 1458 | + | |
| 1455 | 1459 | rc = file_modified(dst_file); |
| 1456 | 1460 | if (!rc) { |
| 1457 | 1461 | rc = target_tcon->ses->server->ops->copychunk_range(xid, |
| 1458 | 1462 | smb_file_src, smb_file_target, off, len, destoff); |
| 1459 | − if (rc > 0 && destoff + rc > i_size_read(target_inode)) | |
| 1463 | + if (rc > 0 && destoff + rc > i_size_read(target_inode)) { | |
| 1460 | 1464 | truncate_setsize(target_inode, destoff + rc); |
| 1465 | + netfs_resize_file(&target_cifsi->netfs, | |
| 1466 | + i_size_read(target_inode), true); | |
| 1467 | + fscache_resize_cookie(cifs_inode_cookie(target_inode), | |
| 1468 | + i_size_read(target_inode)); | |
| 1469 | + } | |
| 1470 | + if (rc > 0 && destoff + rc > target_cifsi->netfs.zero_point) | |
| 1471 | + target_cifsi->netfs.zero_point = destoff + rc; | |
| 1461 | 1472 | } |
| 1462 | 1473 | |
| 1463 | 1474 | file_accessed(src_file); |
| @@ -49,6 +49,11 @@ · 48 unmodified lines | ||
| 49 | 49 | */ |
| 50 | 50 | #define CIFS_DEF_ACTIMEO (1 * HZ) |
| 51 | 51 | |
| 52 | +/* | |
| 53 | + * max sleep time before retry to server | |
| 54 | + */ | |
| 55 | +#define CIFS_MAX_SLEEP 2000 | |
| 56 | + | |
| 52 | 57 | /* |
| 53 | 58 | * max attribute cache timeout (jiffies) - 2^30 |
| 54 | 59 | */ |
| @@ -1501,6 +1506,7 @@ struct cifs_writedata { · 1446 unmodified lines | ||
| 1501 | 1506 | struct smbd_mr *mr; |
| 1502 | 1507 | #endif |
| 1503 | 1508 | struct cifs_credits credits; |
| 1509 | + bool replay; | |
| 1504 | 1510 | }; |
| 1505 | 1511 | |
| 1506 | 1512 | /* |
| @@ -1561,7 +1567,6 @@ struct cifsInodeInfo { · 54 unmodified lines | ||
| 1561 | 1567 | spinlock_t writers_lock; |
| 1562 | 1568 | unsigned int writers; /* Number of writers on this inode */ |
| 1563 | 1569 | unsigned long time; /* jiffies of last update of inode */ |
| 1564 | − u64 server_eof; /* current file size on server -- protected by i_lock */ | |
| 1565 | 1570 | u64 uniqueid; /* server inode number */ |
| 1566 | 1571 | u64 createtime; /* creation time on server */ |
| 1567 | 1572 | __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for this inode */ |
| @@ -1831,6 +1836,13 @@ static inline bool is_retryable_error(int error) · 263 unmodified lines | ||
| 1831 | 1836 | return false; |
| 1832 | 1837 | } |
| 1833 | 1838 | |
| 1839 | +static inline bool is_replayable_error(int error) | |
| 1840 | +{ | |
| 1841 | + if (error == -EAGAIN || error == -ECONNABORTED) | |
| 1842 | + return true; | |
| 1843 | + return false; | |
| 1844 | +} | |
| 1845 | + | |
| 1834 | 1846 | |
| 1835 | 1847 | /* cifs_get_writable_file() flags */ |
| 1836 | 1848 | #define FIND_WR_ANY 0 |
| @@ -2120,8 +2120,8 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, · 2119 unmodified lines | ||
| 2120 | 2120 | { |
| 2121 | 2121 | loff_t end_of_write = offset + bytes_written; |
| 2122 | 2122 | |
| 2123 | − if (end_of_write > cifsi->server_eof) | |
| 2124 | − cifsi->server_eof = end_of_write; | |
| 2123 | + if (end_of_write > cifsi->netfs.remote_i_size) | |
| 2124 | + netfs_resize_file(&cifsi->netfs, end_of_write, true); | |
| 2125 | 2125 | } |
| 2126 | 2126 | |
| 2127 | 2127 | static ssize_t |
| @@ -3247,8 +3247,8 @@ cifs_uncached_writev_complete(struct work_struct *work) · 1119 unmodified lines | ||
| 3247 | 3247 | |
| 3248 | 3248 | spin_lock(&inode->i_lock); |
| 3249 | 3249 | cifs_update_eof(cifsi, wdata->offset, wdata->bytes); |
| 3250 | − if (cifsi->server_eof > inode->i_size) | |
| 3251 | − i_size_write(inode, cifsi->server_eof); | |
| 3250 | + if (cifsi->netfs.remote_i_size > inode->i_size) | |
| 3251 | + i_size_write(inode, cifsi->netfs.remote_i_size); | |
| 3252 | 3252 | spin_unlock(&inode->i_lock); |
| 3253 | 3253 | |
| 3254 | 3254 | complete(&wdata->done); |
| @@ -3300,6 +3300,7 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, · 45 unmodified lines | ||
| 3300 | 3300 | if (wdata->cfile->invalidHandle) |
| 3301 | 3301 | rc = -EAGAIN; |
| 3302 | 3302 | else { |
| 3303 | + wdata->replay = true; | |
| 3303 | 3304 | #ifdef CONFIG_CIFS_SMB_DIRECT |
| 3304 | 3305 | if (wdata->mr) { |
| 3305 | 3306 | wdata->mr->need_invalidate = true; |
| @@ -104,7 +104,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr) · 103 unmodified lines | ||
| 104 | 104 | fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode); |
| 105 | 105 | mtime = inode_get_mtime(inode); |
| 106 | 106 | if (timespec64_equal(&mtime, &fattr->cf_mtime) && |
| 107 | − cifs_i->server_eof == fattr->cf_eof) { | |
| 107 | + cifs_i->netfs.remote_i_size == fattr->cf_eof) { | |
| 108 | 108 | cifs_dbg(FYI, "%s: inode %llu is unchanged\n", |
| 109 | 109 | __func__, cifs_i->uniqueid); |
| 110 | 110 | return; |
| @@ -194,7 +194,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) · 83 unmodified lines | ||
| 194 | 194 | else |
| 195 | 195 | clear_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags); |
| 196 | 196 | |
| 197 | − cifs_i->server_eof = fattr->cf_eof; | |
| 197 | + cifs_i->netfs.remote_i_size = fattr->cf_eof; | |
| 198 | 198 | /* |
| 199 | 199 | * Can't safely change the file size here if the client is writing to |
| 200 | 200 | * it due to potential races. |
| @@ -2858,7 +2858,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, · 2657 unmodified lines | ||
| 2858 | 2858 | |
| 2859 | 2859 | set_size_out: |
| 2860 | 2860 | if (rc == 0) { |
| 2861 | − cifsInode->server_eof = attrs->ia_size; | |
| 2861 | + netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true); | |
| 2862 | 2862 | cifs_setsize(inode, attrs->ia_size); |
| 2863 | 2863 | /* |
| 2864 | 2864 | * i_blocks is not related to (i_size / i_blksize), but instead |
| @@ -3011,6 +3011,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) · 146 unmodified lines | ||
| 3011 | 3011 | if ((attrs->ia_valid & ATTR_SIZE) && |
| 3012 | 3012 | attrs->ia_size != i_size_read(inode)) { |
| 3013 | 3013 | truncate_setsize(inode, attrs->ia_size); |
| 3014 | + netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true); | |
| 3014 | 3015 | fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); |
| 3015 | 3016 | } |
| 3016 | 3017 | |
| @@ -3210,6 +3211,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) · 193 unmodified lines | ||
| 3210 | 3211 | if ((attrs->ia_valid & ATTR_SIZE) && |
| 3211 | 3212 | attrs->ia_size != i_size_read(inode)) { |
| 3212 | 3213 | truncate_setsize(inode, attrs->ia_size); |
| 3214 | + netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true); | |
| 3213 | 3215 | fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); |
| 3214 | 3216 | } |
| 3215 | 3217 | |
| @@ -141,7 +141,7 @@ retry: · 140 unmodified lines | ||
| 141 | 141 | if (likely(reparse_inode_match(inode, fattr))) { |
| 142 | 142 | fattr->cf_mode = inode->i_mode; |
| 143 | 143 | fattr->cf_rdev = inode->i_rdev; |
| 144 | − fattr->cf_eof = CIFS_I(inode)->server_eof; | |
| 144 | + fattr->cf_eof = CIFS_I(inode)->netfs.remote_i_size; | |
| 145 | 145 | fattr->cf_symlink_target = NULL; |
| 146 | 146 | } else { |
| 147 | 147 | CIFS_I(inode)->time = 0; |
| @@ -120,6 +120,14 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, · 119 unmodified lines | ||
| 120 | 120 | unsigned int size[2]; |
| 121 | 121 | void *data[2]; |
| 122 | 122 | int len; |
| 123 | + int retries = 0, cur_sleep = 1; | |
| 124 | + | |
| 125 | +replay_again: | |
| 126 | + /* reinitialize for possible replay */ | |
| 127 | + flags = 0; | |
| 128 | + oplock = SMB2_OPLOCK_LEVEL_NONE; | |
| 129 | + num_rqst = 0; | |
| 130 | + server = cifs_pick_channel(ses); | |
| 123 | 131 | |
| 124 | 132 | vars = kzalloc(sizeof(*vars), GFP_ATOMIC); |
| 125 | 133 | if (vars == NULL) |
| @@ -127,8 +135,6 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, · 1 unmodified line | ||
| 127 | 135 | rqst = &vars->rqst[0]; |
| 128 | 136 | rsp_iov = &vars->rsp_iov[0]; |
| 129 | 137 | |
| 130 | − server = cifs_pick_channel(ses); | |
| 131 | − | |
| 132 | 138 | if (smb3_encryption_required(tcon)) |
| 133 | 139 | flags |= CIFS_TRANSFORM_REQ; |
| 134 | 140 | |
| @@ -463,15 +469,24 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, · 328 unmodified lines | ||
| 463 | 469 | num_rqst++; |
| 464 | 470 | |
| 465 | 471 | if (cfile) { |
| 472 | + if (retries) | |
| 473 | + for (i = 1; i < num_rqst - 2; i++) | |
| 474 | + smb2_set_replay(server, &rqst[i]); | |
| 475 | + | |
| 466 | 476 | rc = compound_send_recv(xid, ses, server, |
| 467 | 477 | flags, num_rqst - 2, |
| 468 | 478 | &rqst[1], &resp_buftype[1], |
| 469 | 479 | &rsp_iov[1]); |
| 470 | − } else | |
| 480 | + } else { | |
| 481 | + if (retries) | |
| 482 | + for (i = 0; i < num_rqst; i++) | |
| 483 | + smb2_set_replay(server, &rqst[i]); | |
| 484 | + | |
| 471 | 485 | rc = compound_send_recv(xid, ses, server, |
| 472 | 486 | flags, num_rqst, |
| 473 | 487 | rqst, resp_buftype, |
| 474 | 488 | rsp_iov); |
| 489 | + } | |
| 475 | 490 | |
| 476 | 491 | finished: |
| 477 | 492 | num_rqst = 0; |
| @@ -620,9 +635,6 @@ finished: · 142 unmodified lines | ||
| 620 | 635 | } |
| 621 | 636 | SMB2_close_free(&rqst[num_rqst]); |
| 622 | 637 | |
| 623 | − if (cfile) | |
| 624 | − cifsFileInfo_put(cfile); | |
| 625 | − | |
| 626 | 638 | num_cmds += 2; |
| 627 | 639 | if (out_iov && out_buftype) { |
| 628 | 640 | memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov)); |
| @@ -632,7 +644,16 @@ finished: · 3 unmodified lines | ||
| 632 | 644 | for (i = 0; i < num_cmds; i++) |
| 633 | 645 | free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base); |
| 634 | 646 | } |
| 647 | + num_cmds -= 2; /* correct num_cmds as there could be a retry */ | |
| 635 | 648 | kfree(vars); |
| 649 | + | |
| 650 | + if (is_replayable_error(rc) && | |
| 651 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 652 | + goto replay_again; | |
| 653 | + | |
| 654 | + if (cfile) | |
| 655 | + cifsFileInfo_put(cfile); | |
| 656 | + | |
| 636 | 657 | return rc; |
| 637 | 658 | } |
| 638 | 659 | |
| @@ -1108,7 +1108,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, · 1107 unmodified lines | ||
| 1108 | 1108 | { |
| 1109 | 1109 | struct smb2_compound_vars *vars; |
| 1110 | 1110 | struct cifs_ses *ses = tcon->ses; |
| 1111 | − struct TCP_Server_Info *server = cifs_pick_channel(ses); | |
| 1111 | + struct TCP_Server_Info *server; | |
| 1112 | 1112 | struct smb_rqst *rqst; |
| 1113 | 1113 | struct kvec *rsp_iov; |
| 1114 | 1114 | __le16 *utf16_path = NULL; |
| @@ -1124,6 +1124,13 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, · 9 unmodified lines | ||
| 1124 | 1124 | struct smb2_file_full_ea_info *ea = NULL; |
| 1125 | 1125 | struct smb2_query_info_rsp *rsp; |
| 1126 | 1126 | int rc, used_len = 0; |
| 1127 | + int retries = 0, cur_sleep = 1; | |
| 1128 | + | |
| 1129 | +replay_again: | |
| 1130 | + /* reinitialize for possible replay */ | |
| 1131 | + flags = CIFS_CP_CREATE_CLOSE_OP; | |
| 1132 | + oplock = SMB2_OPLOCK_LEVEL_NONE; | |
| 1133 | + server = cifs_pick_channel(ses); | |
| 1127 | 1134 | |
| 1128 | 1135 | if (smb3_encryption_required(tcon)) |
| 1129 | 1136 | flags |= CIFS_TRANSFORM_REQ; |
| @@ -1244,6 +1251,12 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, · 114 unmodified lines | ||
| 1244 | 1251 | goto sea_exit; |
| 1245 | 1252 | smb2_set_related(&rqst[2]); |
| 1246 | 1253 | |
| 1254 | + if (retries) { | |
| 1255 | + smb2_set_replay(server, &rqst[0]); | |
| 1256 | + smb2_set_replay(server, &rqst[1]); | |
| 1257 | + smb2_set_replay(server, &rqst[2]); | |
| 1258 | + } | |
| 1259 | + | |
| 1247 | 1260 | rc = compound_send_recv(xid, ses, server, |
| 1248 | 1261 | flags, 3, rqst, |
| 1249 | 1262 | resp_buftype, rsp_iov); |
| @@ -1260,6 +1273,11 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, · 10 unmodified lines | ||
| 1260 | 1273 | kfree(vars); |
| 1261 | 1274 | out_free_path: |
| 1262 | 1275 | kfree(utf16_path); |
| 1276 | + | |
| 1277 | + if (is_replayable_error(rc) && | |
| 1278 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 1279 | + goto replay_again; | |
| 1280 | + | |
| 1263 | 1281 | return rc; |
| 1264 | 1282 | } |
| 1265 | 1283 | #endif |
| @@ -1484,7 +1502,7 @@ smb2_ioctl_query_info(const unsigned int xid, · 218 unmodified lines | ||
| 1484 | 1502 | struct smb_rqst *rqst; |
| 1485 | 1503 | struct kvec *rsp_iov; |
| 1486 | 1504 | struct cifs_ses *ses = tcon->ses; |
| 1487 | − struct TCP_Server_Info *server = cifs_pick_channel(ses); | |
| 1505 | + struct TCP_Server_Info *server; | |
| 1488 | 1506 | char __user *arg = (char __user *)p; |
| 1489 | 1507 | struct smb_query_info qi; |
| 1490 | 1508 | struct smb_query_info __user *pqi; |
| @@ -1501,6 +1519,13 @@ smb2_ioctl_query_info(const unsigned int xid, · 10 unmodified lines | ||
| 1501 | 1519 | void *data[2]; |
| 1502 | 1520 | int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR; |
| 1503 | 1521 | void (*free_req1_func)(struct smb_rqst *r); |
| 1522 | + int retries = 0, cur_sleep = 1; | |
| 1523 | + | |
| 1524 | +replay_again: | |
| 1525 | + /* reinitialize for possible replay */ | |
| 1526 | + flags = CIFS_CP_CREATE_CLOSE_OP; | |
| 1527 | + oplock = SMB2_OPLOCK_LEVEL_NONE; | |
| 1528 | + server = cifs_pick_channel(ses); | |
| 1504 | 1529 | |
| 1505 | 1530 | vars = kzalloc(sizeof(*vars), GFP_ATOMIC); |
| 1506 | 1531 | if (vars == NULL) |
| @@ -1641,6 +1666,12 @@ smb2_ioctl_query_info(const unsigned int xid, · 134 unmodified lines | ||
| 1641 | 1666 | goto free_req_1; |
| 1642 | 1667 | smb2_set_related(&rqst[2]); |
| 1643 | 1668 | |
| 1669 | + if (retries) { | |
| 1670 | + smb2_set_replay(server, &rqst[0]); | |
| 1671 | + smb2_set_replay(server, &rqst[1]); | |
| 1672 | + smb2_set_replay(server, &rqst[2]); | |
| 1673 | + } | |
| 1674 | + | |
| 1644 | 1675 | rc = compound_send_recv(xid, ses, server, |
| 1645 | 1676 | flags, 3, rqst, |
| 1646 | 1677 | resp_buftype, rsp_iov); |
| @@ -1701,6 +1732,11 @@ free_output_buffer: · 54 unmodified lines | ||
| 1701 | 1732 | kfree(buffer); |
| 1702 | 1733 | free_vars: |
| 1703 | 1734 | kfree(vars); |
| 1735 | + | |
| 1736 | + if (is_replayable_error(rc) && | |
| 1737 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 1738 | + goto replay_again; | |
| 1739 | + | |
| 1704 | 1740 | return rc; |
| 1705 | 1741 | } |
| 1706 | 1742 | |
| @@ -2227,8 +2263,14 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, · 520 unmodified lines | ||
| 2227 | 2263 | struct cifs_open_parms oparms; |
| 2228 | 2264 | struct smb2_query_directory_rsp *qd_rsp = NULL; |
| 2229 | 2265 | struct smb2_create_rsp *op_rsp = NULL; |
| 2230 | − struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses); | |
| 2231 | − int retry_count = 0; | |
| 2266 | + struct TCP_Server_Info *server; | |
| 2267 | + int retries = 0, cur_sleep = 1; | |
| 2268 | + | |
| 2269 | +replay_again: | |
| 2270 | + /* reinitialize for possible replay */ | |
| 2271 | + flags = 0; | |
| 2272 | + oplock = SMB2_OPLOCK_LEVEL_NONE; | |
| 2273 | + server = cifs_pick_channel(tcon->ses); | |
| 2232 | 2274 | |
| 2233 | 2275 | utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); |
| 2234 | 2276 | if (!utf16_path) |
| @@ -2278,14 +2320,15 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, · 43 unmodified lines | ||
| 2278 | 2320 | |
| 2279 | 2321 | smb2_set_related(&rqst[1]); |
| 2280 | 2322 | |
| 2281 | −again: | |
| 2323 | + if (retries) { | |
| 2324 | + smb2_set_replay(server, &rqst[0]); | |
| 2325 | + smb2_set_replay(server, &rqst[1]); | |
| 2326 | + } | |
| 2327 | + | |
| 2282 | 2328 | rc = compound_send_recv(xid, tcon->ses, server, |
| 2283 | 2329 | flags, 2, rqst, |
| 2284 | 2330 | resp_buftype, rsp_iov); |
| 2285 | 2331 | |
| 2286 | − if (rc == -EAGAIN && retry_count++ < 10) | |
| 2287 | − goto again; | |
| 2288 | − | |
| 2289 | 2332 | /* If the open failed there is nothing to do */ |
| 2290 | 2333 | op_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base; |
| 2291 | 2334 | if (op_rsp == NULL || op_rsp->hdr.Status != STATUS_SUCCESS) { |
| @@ -2333,6 +2376,11 @@ again: · 41 unmodified lines | ||
| 2333 | 2376 | SMB2_query_directory_free(&rqst[1]); |
| 2334 | 2377 | free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); |
| 2335 | 2378 | free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); |
| 2379 | + | |
| 2380 | + if (is_replayable_error(rc) && | |
| 2381 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 2382 | + goto replay_again; | |
| 2383 | + | |
| 2336 | 2384 | return rc; |
| 2337 | 2385 | } |
| 2338 | 2386 | |
| @@ -2457,6 +2505,22 @@ smb2_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid, · 118 unmodified lines | ||
| 2457 | 2505 | CIFS_CACHE_READ(cinode) ? 1 : 0); |
| 2458 | 2506 | } |
| 2459 | 2507 | |
| 2508 | +void | |
| 2509 | +smb2_set_replay(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |
| 2510 | +{ | |
| 2511 | + struct smb2_hdr *shdr; | |
| 2512 | + | |
| 2513 | + if (server->dialect < SMB30_PROT_ID) | |
| 2514 | + return; | |
| 2515 | + | |
| 2516 | + shdr = (struct smb2_hdr *)(rqst->rq_iov[0].iov_base); | |
| 2517 | + if (shdr == NULL) { | |
| 2518 | + cifs_dbg(FYI, "shdr NULL in smb2_set_related\n"); | |
| 2519 | + return; | |
| 2520 | + } | |
| 2521 | + shdr->Flags |= SMB2_FLAGS_REPLAY_OPERATION; | |
| 2522 | +} | |
| 2523 | + | |
| 2460 | 2524 | void |
| 2461 | 2525 | smb2_set_related(struct smb_rqst *rqst) |
| 2462 | 2526 | { |
| @@ -2529,6 +2593,27 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst) · 66 unmodified lines | ||
| 2529 | 2593 | shdr->NextCommand = cpu_to_le32(len); |
| 2530 | 2594 | } |
| 2531 | 2595 | |
| 2596 | +/* | |
| 2597 | + * helper function for exponential backoff and check if replayable | |
| 2598 | + */ | |
| 2599 | +bool smb2_should_replay(struct cifs_tcon *tcon, | |
| 2600 | + int *pretries, | |
| 2601 | + int *pcur_sleep) | |
| 2602 | +{ | |
| 2603 | + if (!pretries || !pcur_sleep) | |
| 2604 | + return false; | |
| 2605 | + | |
| 2606 | + if (tcon->retry || (*pretries)++ < tcon->ses->server->retrans) { | |
| 2607 | + msleep(*pcur_sleep); | |
| 2608 | + (*pcur_sleep) = ((*pcur_sleep) << 1); | |
| 2609 | + if ((*pcur_sleep) > CIFS_MAX_SLEEP) | |
| 2610 | + (*pcur_sleep) = CIFS_MAX_SLEEP; | |
| 2611 | + return true; | |
| 2612 | + } | |
| 2613 | + | |
| 2614 | + return false; | |
| 2615 | +} | |
| 2616 | + | |
| 2532 | 2617 | /* |
| 2533 | 2618 | * Passes the query info response back to the caller on success. |
| 2534 | 2619 | * Caller need to free this with free_rsp_buf(). |
| @@ -2542,7 +2627,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, · 7 unmodified lines | ||
| 2542 | 2627 | { |
| 2543 | 2628 | struct smb2_compound_vars *vars; |
| 2544 | 2629 | struct cifs_ses *ses = tcon->ses; |
| 2545 | − struct TCP_Server_Info *server = cifs_pick_channel(ses); | |
| 2630 | + struct TCP_Server_Info *server; | |
| 2546 | 2631 | int flags = CIFS_CP_CREATE_CLOSE_OP; |
| 2547 | 2632 | struct smb_rqst *rqst; |
| 2548 | 2633 | int resp_buftype[3]; |
| @@ -2553,6 +2638,13 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, · 4 unmodified lines | ||
| 2553 | 2638 | int rc; |
| 2554 | 2639 | __le16 *utf16_path; |
| 2555 | 2640 | struct cached_fid *cfid = NULL; |
| 2641 | + int retries = 0, cur_sleep = 1; | |
| 2642 | + | |
| 2643 | +replay_again: | |
| 2644 | + /* reinitialize for possible replay */ | |
| 2645 | + flags = CIFS_CP_CREATE_CLOSE_OP; | |
| 2646 | + oplock = SMB2_OPLOCK_LEVEL_NONE; | |
| 2647 | + server = cifs_pick_channel(ses); | |
| 2556 | 2648 | |
| 2557 | 2649 | if (!path) |
| 2558 | 2650 | path = ""; |
| @@ -2633,6 +2725,14 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, · 74 unmodified lines | ||
| 2633 | 2725 | goto qic_exit; |
| 2634 | 2726 | smb2_set_related(&rqst[2]); |
| 2635 | 2727 | |
| 2728 | + if (retries) { | |
| 2729 | + if (!cfid) { | |
| 2730 | + smb2_set_replay(server, &rqst[0]); | |
| 2731 | + smb2_set_replay(server, &rqst[2]); | |
| 2732 | + } | |
| 2733 | + smb2_set_replay(server, &rqst[1]); | |
| 2734 | + } | |
| 2735 | + | |
| 2636 | 2736 | if (cfid) { |
| 2637 | 2737 | rc = compound_send_recv(xid, ses, server, |
| 2638 | 2738 | flags, 1, &rqst[1], |
| @@ -2665,6 +2765,11 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, · 26 unmodified lines | ||
| 2665 | 2765 | kfree(vars); |
| 2666 | 2766 | out_free_path: |
| 2667 | 2767 | kfree(utf16_path); |
| 2768 | + | |
| 2769 | + if (is_replayable_error(rc) && | |
| 2770 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 2771 | + goto replay_again; | |
| 2772 | + | |
| 2668 | 2773 | return rc; |
| 2669 | 2774 | } |
| 2670 | 2775 | |
| @@ -3213,6 +3318,9 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, · 542 unmodified lines | ||
| 3213 | 3318 | cfile->fid.volatile_fid, cfile->pid, new_size); |
| 3214 | 3319 | if (rc >= 0) { |
| 3215 | 3320 | truncate_setsize(inode, new_size); |
| 3321 | + netfs_resize_file(&cifsi->netfs, new_size, true); | |
| 3322 | + if (offset < cifsi->netfs.zero_point) | |
| 3323 | + cifsi->netfs.zero_point = offset; | |
| 3216 | 3324 | fscache_resize_cookie(cifs_inode_cookie(inode), new_size); |
| 3217 | 3325 | } |
| 3218 | 3326 | } |
| @@ -3436,7 +3544,7 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, · 217 unmodified lines | ||
| 3436 | 3544 | rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, |
| 3437 | 3545 | cfile->fid.volatile_fid, cfile->pid, new_eof); |
| 3438 | 3546 | if (rc == 0) { |
| 3439 | − cifsi->server_eof = new_eof; | |
| 3547 | + netfs_resize_file(&cifsi->netfs, new_eof, true); | |
| 3440 | 3548 | cifs_setsize(inode, new_eof); |
| 3441 | 3549 | cifs_truncate_page(inode->i_mapping, inode->i_size); |
| 3442 | 3550 | truncate_setsize(inode, new_eof); |
| @@ -3528,8 +3636,9 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon, · 85 unmodified lines | ||
| 3528 | 3636 | int rc; |
| 3529 | 3637 | unsigned int xid; |
| 3530 | 3638 | struct inode *inode = file_inode(file); |
| 3531 | − struct cifsFileInfo *cfile = file->private_data; | |
| 3532 | 3639 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
| 3640 | + struct cifsFileInfo *cfile = file->private_data; | |
| 3641 | + struct netfs_inode *ictx = &cifsi->netfs; | |
| 3533 | 3642 | loff_t old_eof, new_eof; |
| 3534 | 3643 | |
| 3535 | 3644 | xid = get_xid(); |
| @@ -3549,6 +3658,7 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon, · 13 unmodified lines | ||
| 3549 | 3658 | goto out_2; |
| 3550 | 3659 | |
| 3551 | 3660 | truncate_pagecache_range(inode, off, old_eof); |
| 3661 | + ictx->zero_point = old_eof; | |
| 3552 | 3662 | |
| 3553 | 3663 | rc = smb2_copychunk_range(xid, cfile, cfile, off + len, |
| 3554 | 3664 | old_eof - off - len, off); |
| @@ -3563,9 +3673,10 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon, · 8 unmodified lines | ||
| 3563 | 3673 | |
| 3564 | 3674 | rc = 0; |
| 3565 | 3675 | |
| 3566 | − cifsi->server_eof = i_size_read(inode) - len; | |
| 3567 | − truncate_setsize(inode, cifsi->server_eof); | |
| 3568 | − fscache_resize_cookie(cifs_inode_cookie(inode), cifsi->server_eof); | |
| 3676 | + truncate_setsize(inode, new_eof); | |
| 3677 | + netfs_resize_file(&cifsi->netfs, new_eof, true); | |
| 3678 | + ictx->zero_point = new_eof; | |
| 3679 | + fscache_resize_cookie(cifs_inode_cookie(inode), new_eof); | |
| 3569 | 3680 | out_2: |
| 3570 | 3681 | filemap_invalidate_unlock(inode->i_mapping); |
| 3571 | 3682 | out: |
| @@ -3581,6 +3692,7 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon, · 9 unmodified lines | ||
| 3581 | 3692 | unsigned int xid; |
| 3582 | 3693 | struct cifsFileInfo *cfile = file->private_data; |
| 3583 | 3694 | struct inode *inode = file_inode(file); |
| 3695 | + struct cifsInodeInfo *cifsi = CIFS_I(inode); | |
| 3584 | 3696 | __u64 count, old_eof, new_eof; |
| 3585 | 3697 | |
| 3586 | 3698 | xid = get_xid(); |
| @@ -3608,6 +3720,7 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon, · 21 unmodified lines | ||
| 3608 | 3720 | goto out_2; |
| 3609 | 3721 | |
| 3610 | 3722 | truncate_setsize(inode, new_eof); |
| 3723 | + netfs_resize_file(&cifsi->netfs, i_size_read(inode), true); | |
| 3611 | 3724 | fscache_resize_cookie(cifs_inode_cookie(inode), i_size_read(inode)); |
| 3612 | 3725 | |
| 3613 | 3726 | rc = smb2_copychunk_range(xid, cfile, cfile, off, count, off + len); |
| @@ -195,7 +195,6 @@ cifs_chan_skip_or_disable(struct cifs_ses *ses, · 194 unmodified lines | ||
| 195 | 195 | pserver = server->primary_server; |
| 196 | 196 | cifs_signal_cifsd_for_reconnect(pserver, false); |
| 197 | 197 | skip_terminate: |
| 198 | − mutex_unlock(&ses->session_mutex); | |
| 199 | 198 | return -EHOSTDOWN; |
| 200 | 199 | } |
| 201 | 200 | |
| @@ -2765,7 +2764,14 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, · 2563 unmodified lines | ||
| 2765 | 2764 | int flags = 0; |
| 2766 | 2765 | unsigned int total_len; |
| 2767 | 2766 | __le16 *utf16_path = NULL; |
| 2768 | − struct TCP_Server_Info *server = cifs_pick_channel(ses); | |
| 2767 | + struct TCP_Server_Info *server; | |
| 2768 | + int retries = 0, cur_sleep = 1; | |
| 2769 | + | |
| 2770 | +replay_again: | |
| 2771 | + /* reinitialize for possible replay */ | |
| 2772 | + flags = 0; | |
| 2773 | + n_iov = 2; | |
| 2774 | + server = cifs_pick_channel(ses); | |
| 2769 | 2775 | |
| 2770 | 2776 | cifs_dbg(FYI, "mkdir\n"); |
| 2771 | 2777 | |
| @@ -2869,6 +2875,10 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, · 97 unmodified lines | ||
| 2869 | 2875 | /* no need to inc num_remote_opens because we close it just below */ |
| 2870 | 2876 | trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, full_path, CREATE_NOT_FILE, |
| 2871 | 2877 | FILE_WRITE_ATTRIBUTES); |
| 2878 | + | |
| 2879 | + if (retries) | |
| 2880 | + smb2_set_replay(server, &rqst); | |
| 2881 | + | |
| 2872 | 2882 | /* resource #4: response buffer */ |
| 2873 | 2883 | rc = cifs_send_recv(xid, ses, server, |
| 2874 | 2884 | &rqst, &resp_buftype, flags, &rsp_iov); |
| @@ -2906,6 +2916,11 @@ err_free_req: · 31 unmodified lines | ||
| 2906 | 2916 | cifs_small_buf_release(req); |
| 2907 | 2917 | err_free_path: |
| 2908 | 2918 | kfree(utf16_path); |
| 2919 | + | |
| 2920 | + if (is_replayable_error(rc) && | |
| 2921 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 2922 | + goto replay_again; | |
| 2923 | + | |
| 2909 | 2924 | return rc; |
| 2910 | 2925 | } |
| 2911 | 2926 | |
| @@ -3101,12 +3116,18 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, · 189 unmodified lines | ||
| 3101 | 3116 | struct smb2_create_rsp *rsp = NULL; |
| 3102 | 3117 | struct cifs_tcon *tcon = oparms->tcon; |
| 3103 | 3118 | struct cifs_ses *ses = tcon->ses; |
| 3104 | − struct TCP_Server_Info *server = cifs_pick_channel(ses); | |
| 3119 | + struct TCP_Server_Info *server; | |
| 3105 | 3120 | struct kvec iov[SMB2_CREATE_IOV_SIZE]; |
| 3106 | 3121 | struct kvec rsp_iov = {NULL, 0}; |
| 3107 | 3122 | int resp_buftype = CIFS_NO_BUFFER; |
| 3108 | 3123 | int rc = 0; |
| 3109 | 3124 | int flags = 0; |
| 3125 | + int retries = 0, cur_sleep = 1; | |
| 3126 | + | |
| 3127 | +replay_again: | |
| 3128 | + /* reinitialize for possible replay */ | |
| 3129 | + flags = 0; | |
| 3130 | + server = cifs_pick_channel(ses); | |
| 3110 | 3131 | |
| 3111 | 3132 | cifs_dbg(FYI, "create/open\n"); |
| 3112 | 3133 | if (!ses || !server) |
| @@ -3128,6 +3149,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, · 15 unmodified lines | ||
| 3128 | 3149 | trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, oparms->path, |
| 3129 | 3150 | oparms->create_options, oparms->desired_access); |
| 3130 | 3151 | |
| 3152 | + if (retries) | |
| 3153 | + smb2_set_replay(server, &rqst); | |
| 3154 | + | |
| 3131 | 3155 | rc = cifs_send_recv(xid, ses, server, |
| 3132 | 3156 | &rqst, &resp_buftype, flags, |
| 3133 | 3157 | &rsp_iov); |
| @@ -3181,6 +3205,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, · 47 unmodified lines | ||
| 3181 | 3205 | creat_exit: |
| 3182 | 3206 | SMB2_open_free(&rqst); |
| 3183 | 3207 | free_rsp_buf(resp_buftype, rsp); |
| 3208 | + | |
| 3209 | + if (is_replayable_error(rc) && | |
| 3210 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 3211 | + goto replay_again; | |
| 3212 | + | |
| 3184 | 3213 | return rc; |
| 3185 | 3214 | } |
| 3186 | 3215 | |
| @@ -3305,15 +3334,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, · 118 unmodified lines | ||
| 3305 | 3334 | int resp_buftype = CIFS_NO_BUFFER; |
| 3306 | 3335 | int rc = 0; |
| 3307 | 3336 | int flags = 0; |
| 3308 | − | |
| 3309 | − cifs_dbg(FYI, "SMB2 IOCTL\n"); | |
| 3310 | − | |
| 3311 | − if (out_data != NULL) | |
| 3312 | − *out_data = NULL; | |
| 3313 | − | |
| 3314 | − /* zero out returned data len, in case of error */ | |
| 3315 | − if (plen) | |
| 3316 | − *plen = 0; | |
| 3337 | + int retries = 0, cur_sleep = 1; | |
| 3317 | 3338 | |
| 3318 | 3339 | if (!tcon) |
| 3319 | 3340 | return -EIO; |
| @@ -3322,10 +3343,23 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, · 2 unmodified lines | ||
| 3322 | 3343 | if (!ses) |
| 3323 | 3344 | return -EIO; |
| 3324 | 3345 | |
| 3346 | +replay_again: | |
| 3347 | + /* reinitialize for possible replay */ | |
| 3348 | + flags = 0; | |
| 3325 | 3349 | server = cifs_pick_channel(ses); |
| 3350 | + | |
| 3326 | 3351 | if (!server) |
| 3327 | 3352 | return -EIO; |
| 3328 | 3353 | |
| 3354 | + cifs_dbg(FYI, "SMB2 IOCTL\n"); | |
| 3355 | + | |
| 3356 | + if (out_data != NULL) | |
| 3357 | + *out_data = NULL; | |
| 3358 | + | |
| 3359 | + /* zero out returned data len, in case of error */ | |
| 3360 | + if (plen) | |
| 3361 | + *plen = 0; | |
| 3362 | + | |
| 3329 | 3363 | if (smb3_encryption_required(tcon)) |
| 3330 | 3364 | flags |= CIFS_TRANSFORM_REQ; |
| 3331 | 3365 | |
| @@ -3340,6 +3374,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, · 8 unmodified lines | ||
| 3340 | 3374 | if (rc) |
| 3341 | 3375 | goto ioctl_exit; |
| 3342 | 3376 | |
| 3377 | + if (retries) | |
| 3378 | + smb2_set_replay(server, &rqst); | |
| 3379 | + | |
| 3343 | 3380 | rc = cifs_send_recv(xid, ses, server, |
| 3344 | 3381 | &rqst, &resp_buftype, flags, |
| 3345 | 3382 | &rsp_iov); |
| @@ -3409,6 +3446,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, · 63 unmodified lines | ||
| 3409 | 3446 | ioctl_exit: |
| 3410 | 3447 | SMB2_ioctl_free(&rqst); |
| 3411 | 3448 | free_rsp_buf(resp_buftype, rsp); |
| 3449 | + | |
| 3450 | + if (is_replayable_error(rc) && | |
| 3451 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 3452 | + goto replay_again; | |
| 3453 | + | |
| 3412 | 3454 | return rc; |
| 3413 | 3455 | } |
| 3414 | 3456 | |
| @@ -3480,13 +3522,20 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, · 65 unmodified lines | ||
| 3480 | 3522 | struct smb_rqst rqst; |
| 3481 | 3523 | struct smb2_close_rsp *rsp = NULL; |
| 3482 | 3524 | struct cifs_ses *ses = tcon->ses; |
| 3483 | − struct TCP_Server_Info *server = cifs_pick_channel(ses); | |
| 3525 | + struct TCP_Server_Info *server; | |
| 3484 | 3526 | struct kvec iov[1]; |
| 3485 | 3527 | struct kvec rsp_iov; |
| 3486 | 3528 | int resp_buftype = CIFS_NO_BUFFER; |
| 3487 | 3529 | int rc = 0; |
| 3488 | 3530 | int flags = 0; |
| 3489 | 3531 | bool query_attrs = false; |
| 3532 | + int retries = 0, cur_sleep = 1; | |
| 3533 | + | |
| 3534 | +replay_again: | |
| 3535 | + /* reinitialize for possible replay */ | |
| 3536 | + flags = 0; | |
| 3537 | + query_attrs = false; | |
| 3538 | + server = cifs_pick_channel(ses); | |
| 3490 | 3539 | |
| 3491 | 3540 | cifs_dbg(FYI, "Close\n"); |
| 3492 | 3541 | |
| @@ -3512,6 +3561,9 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, · 19 unmodified lines | ||
| 3512 | 3561 | if (rc) |
| 3513 | 3562 | goto close_exit; |
| 3514 | 3563 | |
| 3564 | + if (retries) | |
| 3565 | + smb2_set_replay(server, &rqst); | |
| 3566 | + | |
| 3515 | 3567 | rc = cifs_send_recv(xid, ses, server, |
| 3516 | 3568 | &rqst, &resp_buftype, flags, &rsp_iov); |
| 3517 | 3569 | rsp = (struct smb2_close_rsp *)rsp_iov.iov_base; |
| @@ -3545,6 +3597,11 @@ close_exit: · 27 unmodified lines | ||
| 3545 | 3597 | cifs_dbg(VFS, "handle cancelled close fid 0x%llx returned error %d\n", |
| 3546 | 3598 | persistent_fid, tmp_rc); |
| 3547 | 3599 | } |
| 3600 | + | |
| 3601 | + if (is_replayable_error(rc) && | |
| 3602 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 3603 | + goto replay_again; | |
| 3604 | + | |
| 3548 | 3605 | return rc; |
| 3549 | 3606 | } |
| 3550 | 3607 | |
| @@ -3675,12 +3732,19 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, · 124 unmodified lines | ||
| 3675 | 3732 | struct TCP_Server_Info *server; |
| 3676 | 3733 | int flags = 0; |
| 3677 | 3734 | bool allocated = false; |
| 3735 | + int retries = 0, cur_sleep = 1; | |
| 3678 | 3736 | |
| 3679 | 3737 | cifs_dbg(FYI, "Query Info\n"); |
| 3680 | 3738 | |
| 3681 | 3739 | if (!ses) |
| 3682 | 3740 | return -EIO; |
| 3741 | + | |
| 3742 | +replay_again: | |
| 3743 | + /* reinitialize for possible replay */ | |
| 3744 | + flags = 0; | |
| 3745 | + allocated = false; | |
| 3683 | 3746 | server = cifs_pick_channel(ses); |
| 3747 | + | |
| 3684 | 3748 | if (!server) |
| 3685 | 3749 | return -EIO; |
| 3686 | 3750 | |
| @@ -3702,6 +3766,9 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, · 15 unmodified lines | ||
| 3702 | 3766 | trace_smb3_query_info_enter(xid, persistent_fid, tcon->tid, |
| 3703 | 3767 | ses->Suid, info_class, (__u32)info_type); |
| 3704 | 3768 | |
| 3769 | + if (retries) | |
| 3770 | + smb2_set_replay(server, &rqst); | |
| 3771 | + | |
| 3705 | 3772 | rc = cifs_send_recv(xid, ses, server, |
| 3706 | 3773 | &rqst, &resp_buftype, flags, &rsp_iov); |
| 3707 | 3774 | rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; |
| @@ -3744,6 +3811,11 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, · 36 unmodified lines | ||
| 3744 | 3811 | qinf_exit: |
| 3745 | 3812 | SMB2_query_info_free(&rqst); |
| 3746 | 3813 | free_rsp_buf(resp_buftype, rsp); |
| 3814 | + | |
| 3815 | + if (is_replayable_error(rc) && | |
| 3816 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 3817 | + goto replay_again; | |
| 3818 | + | |
| 3747 | 3819 | return rc; |
| 3748 | 3820 | } |
| 3749 | 3821 | |
| @@ -3844,7 +3916,7 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon, · 94 unmodified lines | ||
| 3844 | 3916 | u32 *plen /* returned data len */) |
| 3845 | 3917 | { |
| 3846 | 3918 | struct cifs_ses *ses = tcon->ses; |
| 3847 | − struct TCP_Server_Info *server = cifs_pick_channel(ses); | |
| 3919 | + struct TCP_Server_Info *server; | |
| 3848 | 3920 | struct smb_rqst rqst; |
| 3849 | 3921 | struct smb2_change_notify_rsp *smb_rsp; |
| 3850 | 3922 | struct kvec iov[1]; |
| @@ -3852,6 +3924,12 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon, · 1 unmodified line | ||
| 3852 | 3924 | int resp_buftype = CIFS_NO_BUFFER; |
| 3853 | 3925 | int flags = 0; |
| 3854 | 3926 | int rc = 0; |
| 3927 | + int retries = 0, cur_sleep = 1; | |
| 3928 | + | |
| 3929 | +replay_again: | |
| 3930 | + /* reinitialize for possible replay */ | |
| 3931 | + flags = 0; | |
| 3932 | + server = cifs_pick_channel(ses); | |
| 3855 | 3933 | |
| 3856 | 3934 | cifs_dbg(FYI, "change notify\n"); |
| 3857 | 3935 | if (!ses || !server) |
| @@ -3876,6 +3954,10 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon, · 18 unmodified lines | ||
| 3876 | 3954 | |
| 3877 | 3955 | trace_smb3_notify_enter(xid, persistent_fid, tcon->tid, ses->Suid, |
| 3878 | 3956 | (u8)watch_tree, completion_filter); |
| 3957 | + | |
| 3958 | + if (retries) | |
| 3959 | + smb2_set_replay(server, &rqst); | |
| 3960 | + | |
| 3879 | 3961 | rc = cifs_send_recv(xid, ses, server, |
| 3880 | 3962 | &rqst, &resp_buftype, flags, &rsp_iov); |
| 3881 | 3963 | |
| @@ -3910,6 +3992,11 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon, · 28 unmodified lines | ||
| 3910 | 3992 | if (rqst.rq_iov) |
| 3911 | 3993 | cifs_small_buf_release(rqst.rq_iov[0].iov_base); /* request */ |
| 3912 | 3994 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); |
| 3995 | + | |
| 3996 | + if (is_replayable_error(rc) && | |
| 3997 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 3998 | + goto replay_again; | |
| 3999 | + | |
| 3913 | 4000 | return rc; |
| 3914 | 4001 | } |
| 3915 | 4002 | |
| @@ -4152,10 +4239,16 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, · 236 unmodified lines | ||
| 4152 | 4239 | struct smb_rqst rqst; |
| 4153 | 4240 | struct kvec iov[1]; |
| 4154 | 4241 | struct kvec rsp_iov = {NULL, 0}; |
| 4155 | − struct TCP_Server_Info *server = cifs_pick_channel(ses); | |
| 4242 | + struct TCP_Server_Info *server; | |
| 4156 | 4243 | int resp_buftype = CIFS_NO_BUFFER; |
| 4157 | 4244 | int flags = 0; |
| 4158 | 4245 | int rc = 0; |
| 4246 | + int retries = 0, cur_sleep = 1; | |
| 4247 | + | |
| 4248 | +replay_again: | |
| 4249 | + /* reinitialize for possible replay */ | |
| 4250 | + flags = 0; | |
| 4251 | + server = cifs_pick_channel(ses); | |
| 4159 | 4252 | |
| 4160 | 4253 | cifs_dbg(FYI, "flush\n"); |
| 4161 | 4254 | if (!ses || !(ses->server)) |
| @@ -4175,6 +4268,10 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, · 13 unmodified lines | ||
| 4175 | 4268 | goto flush_exit; |
| 4176 | 4269 | |
| 4177 | 4270 | trace_smb3_flush_enter(xid, persistent_fid, tcon->tid, ses->Suid); |
| 4271 | + | |
| 4272 | + if (retries) | |
| 4273 | + smb2_set_replay(server, &rqst); | |
| 4274 | + | |
| 4178 | 4275 | rc = cifs_send_recv(xid, ses, server, |
| 4179 | 4276 | &rqst, &resp_buftype, flags, &rsp_iov); |
| 4180 | 4277 | |
| @@ -4189,6 +4286,11 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, · 8 unmodified lines | ||
| 4189 | 4286 | flush_exit: |
| 4190 | 4287 | SMB2_flush_free(&rqst); |
| 4191 | 4288 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); |
| 4289 | + | |
| 4290 | + if (is_replayable_error(rc) && | |
| 4291 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 4292 | + goto replay_again; | |
| 4293 | + | |
| 4192 | 4294 | return rc; |
| 4193 | 4295 | } |
| 4194 | 4296 | |
| @@ -4668,7 +4770,7 @@ smb2_async_writev(struct cifs_writedata *wdata, · 473 unmodified lines | ||
| 4668 | 4770 | struct cifs_io_parms *io_parms = NULL; |
| 4669 | 4771 | int credit_request; |
| 4670 | 4772 | |
| 4671 | − if (!wdata->server) | |
| 4773 | + if (!wdata->server || wdata->replay) | |
| 4672 | 4774 | server = wdata->server = cifs_pick_channel(tcon->ses); |
| 4673 | 4775 | |
| 4674 | 4776 | /* |
| @@ -4753,6 +4855,8 @@ smb2_async_writev(struct cifs_writedata *wdata, · 78 unmodified lines | ||
| 4753 | 4855 | rqst.rq_nvec = 1; |
| 4754 | 4856 | rqst.rq_iter = wdata->iter; |
| 4755 | 4857 | rqst.rq_iter_size = iov_iter_count(&rqst.rq_iter); |
| 4858 | + if (wdata->replay) | |
| 4859 | + smb2_set_replay(server, &rqst); | |
| 4756 | 4860 | #ifdef CONFIG_CIFS_SMB_DIRECT |
| 4757 | 4861 | if (wdata->mr) |
| 4758 | 4862 | iov[0].iov_len += sizeof(struct smbd_buffer_descriptor_v1); |
| @@ -4826,18 +4930,21 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, · 67 unmodified lines | ||
| 4826 | 4930 | int flags = 0; |
| 4827 | 4931 | unsigned int total_len; |
| 4828 | 4932 | struct TCP_Server_Info *server; |
| 4933 | + int retries = 0, cur_sleep = 1; | |
| 4829 | 4934 | |
| 4935 | +replay_again: | |
| 4936 | + /* reinitialize for possible replay */ | |
| 4937 | + flags = 0; | |
| 4830 | 4938 | *nbytes = 0; |
| 4831 | − | |
| 4832 | − if (n_vec < 1) | |
| 4833 | − return rc; | |
| 4834 | − | |
| 4835 | 4939 | if (!io_parms->server) |
| 4836 | 4940 | io_parms->server = cifs_pick_channel(io_parms->tcon->ses); |
| 4837 | 4941 | server = io_parms->server; |
| 4838 | 4942 | if (server == NULL) |
| 4839 | 4943 | return -ECONNABORTED; |
| 4840 | 4944 | |
| 4945 | + if (n_vec < 1) | |
| 4946 | + return rc; | |
| 4947 | + | |
| 4841 | 4948 | rc = smb2_plain_req_init(SMB2_WRITE, io_parms->tcon, server, |
| 4842 | 4949 | (void **) &req, &total_len); |
| 4843 | 4950 | if (rc) |
| @@ -4871,6 +4978,9 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, · 27 unmodified lines | ||
| 4871 | 4978 | rqst.rq_iov = iov; |
| 4872 | 4979 | rqst.rq_nvec = n_vec + 1; |
| 4873 | 4980 | |
| 4981 | + if (retries) | |
| 4982 | + smb2_set_replay(server, &rqst); | |
| 4983 | + | |
| 4874 | 4984 | rc = cifs_send_recv(xid, io_parms->tcon->ses, server, |
| 4875 | 4985 | &rqst, |
| 4876 | 4986 | &resp_buftype, flags, &rsp_iov); |
| @@ -4895,6 +5005,11 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, · 18 unmodified lines | ||
| 4895 | 5005 | |
| 4896 | 5006 | cifs_small_buf_release(req); |
| 4897 | 5007 | free_rsp_buf(resp_buftype, rsp); |
| 5008 | + | |
| 5009 | + if (is_replayable_error(rc) && | |
| 5010 | + smb2_should_replay(io_parms->tcon, &retries, &cur_sleep)) | |
| 5011 | + goto replay_again; | |
| 5012 | + | |
| 4898 | 5013 | return rc; |
| 4899 | 5014 | } |
| 4900 | 5015 | |
| @@ -5206,8 +5321,14 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, · 305 unmodified lines | ||
| 5206 | 5321 | struct kvec rsp_iov; |
| 5207 | 5322 | int rc = 0; |
| 5208 | 5323 | struct cifs_ses *ses = tcon->ses; |
| 5209 | − struct TCP_Server_Info *server = cifs_pick_channel(ses); | |
| 5324 | + struct TCP_Server_Info *server; | |
| 5210 | 5325 | int flags = 0; |
| 5326 | + int retries = 0, cur_sleep = 1; | |
| 5327 | + | |
| 5328 | +replay_again: | |
| 5329 | + /* reinitialize for possible replay */ | |
| 5330 | + flags = 0; | |
| 5331 | + server = cifs_pick_channel(ses); | |
| 5211 | 5332 | |
| 5212 | 5333 | if (!ses || !(ses->server)) |
| 5213 | 5334 | return -EIO; |
| @@ -5227,6 +5348,9 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, · 13 unmodified lines | ||
| 5227 | 5348 | if (rc) |
| 5228 | 5349 | goto qdir_exit; |
| 5229 | 5350 | |
| 5351 | + if (retries) | |
| 5352 | + smb2_set_replay(server, &rqst); | |
| 5353 | + | |
| 5230 | 5354 | rc = cifs_send_recv(xid, ses, server, |
| 5231 | 5355 | &rqst, &resp_buftype, flags, &rsp_iov); |
| 5232 | 5356 | rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base; |
| @@ -5261,6 +5385,11 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, · 28 unmodified lines | ||
| 5261 | 5385 | qdir_exit: |
| 5262 | 5386 | SMB2_query_directory_free(&rqst); |
| 5263 | 5387 | free_rsp_buf(resp_buftype, rsp); |
| 5388 | + | |
| 5389 | + if (is_replayable_error(rc) && | |
| 5390 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 5391 | + goto replay_again; | |
| 5392 | + | |
| 5264 | 5393 | return rc; |
| 5265 | 5394 | } |
| 5266 | 5395 | |
| @@ -5327,8 +5456,14 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, · 60 unmodified lines | ||
| 5327 | 5456 | int rc = 0; |
| 5328 | 5457 | int resp_buftype; |
| 5329 | 5458 | struct cifs_ses *ses = tcon->ses; |
| 5330 | − struct TCP_Server_Info *server = cifs_pick_channel(ses); | |
| 5459 | + struct TCP_Server_Info *server; | |
| 5331 | 5460 | int flags = 0; |
| 5461 | + int retries = 0, cur_sleep = 1; | |
| 5462 | + | |
| 5463 | +replay_again: | |
| 5464 | + /* reinitialize for possible replay */ | |
| 5465 | + flags = 0; | |
| 5466 | + server = cifs_pick_channel(ses); | |
| 5332 | 5467 | |
| 5333 | 5468 | if (!ses || !server) |
| 5334 | 5469 | return -EIO; |
| @@ -5356,6 +5491,8 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, · 21 unmodified lines | ||
| 5356 | 5491 | return rc; |
| 5357 | 5492 | } |
| 5358 | 5493 | |
| 5494 | + if (retries) | |
| 5495 | + smb2_set_replay(server, &rqst); | |
| 5359 | 5496 | |
| 5360 | 5497 | rc = cifs_send_recv(xid, ses, server, |
| 5361 | 5498 | &rqst, &resp_buftype, flags, |
| @@ -5371,6 +5508,11 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, · 9 unmodified lines | ||
| 5371 | 5508 | |
| 5372 | 5509 | free_rsp_buf(resp_buftype, rsp); |
| 5373 | 5510 | kfree(iov); |
| 5511 | + | |
| 5512 | + if (is_replayable_error(rc) && | |
| 5513 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 5514 | + goto replay_again; | |
| 5515 | + | |
| 5374 | 5516 | return rc; |
| 5375 | 5517 | } |
| 5376 | 5518 | |
| @@ -5423,12 +5565,18 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, · 46 unmodified lines | ||
| 5423 | 5565 | int rc; |
| 5424 | 5566 | struct smb2_oplock_break *req = NULL; |
| 5425 | 5567 | struct cifs_ses *ses = tcon->ses; |
| 5426 | − struct TCP_Server_Info *server = cifs_pick_channel(ses); | |
| 5568 | + struct TCP_Server_Info *server; | |
| 5427 | 5569 | int flags = CIFS_OBREAK_OP; |
| 5428 | 5570 | unsigned int total_len; |
| 5429 | 5571 | struct kvec iov[1]; |
| 5430 | 5572 | struct kvec rsp_iov; |
| 5431 | 5573 | int resp_buf_type; |
| 5574 | + int retries = 0, cur_sleep = 1; | |
| 5575 | + | |
| 5576 | +replay_again: | |
| 5577 | + /* reinitialize for possible replay */ | |
| 5578 | + flags = CIFS_OBREAK_OP; | |
| 5579 | + server = cifs_pick_channel(ses); | |
| 5432 | 5580 | |
| 5433 | 5581 | cifs_dbg(FYI, "SMB2_oplock_break\n"); |
| 5434 | 5582 | rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, server, |
| @@ -5453,15 +5601,21 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, · 18 unmodified lines | ||
| 5453 | 5601 | rqst.rq_iov = iov; |
| 5454 | 5602 | rqst.rq_nvec = 1; |
| 5455 | 5603 | |
| 5604 | + if (retries) | |
| 5605 | + smb2_set_replay(server, &rqst); | |
| 5606 | + | |
| 5456 | 5607 | rc = cifs_send_recv(xid, ses, server, |
| 5457 | 5608 | &rqst, &resp_buf_type, flags, &rsp_iov); |
| 5458 | 5609 | cifs_small_buf_release(req); |
| 5459 | − | |
| 5460 | 5610 | if (rc) { |
| 5461 | 5611 | cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE); |
| 5462 | 5612 | cifs_dbg(FYI, "Send error in Oplock Break = %d\n", rc); |
| 5463 | 5613 | } |
| 5464 | 5614 | |
| 5615 | + if (is_replayable_error(rc) && | |
| 5616 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 5617 | + goto replay_again; | |
| 5618 | + | |
| 5465 | 5619 | return rc; |
| 5466 | 5620 | } |
| 5467 | 5621 | |
| @@ -5547,9 +5701,15 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, · 79 unmodified lines | ||
| 5547 | 5701 | int rc = 0; |
| 5548 | 5702 | int resp_buftype; |
| 5549 | 5703 | struct cifs_ses *ses = tcon->ses; |
| 5550 | − struct TCP_Server_Info *server = cifs_pick_channel(ses); | |
| 5704 | + struct TCP_Server_Info *server; | |
| 5551 | 5705 | FILE_SYSTEM_POSIX_INFO *info = NULL; |
| 5552 | 5706 | int flags = 0; |
| 5707 | + int retries = 0, cur_sleep = 1; | |
| 5708 | + | |
| 5709 | +replay_again: | |
| 5710 | + /* reinitialize for possible replay */ | |
| 5711 | + flags = 0; | |
| 5712 | + server = cifs_pick_channel(ses); | |
| 5553 | 5713 | |
| 5554 | 5714 | rc = build_qfs_info_req(&iov, tcon, server, |
| 5555 | 5715 | FS_POSIX_INFORMATION, |
| @@ -5565,6 +5725,9 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, · 9 unmodified lines | ||
| 5565 | 5725 | rqst.rq_iov = &iov; |
| 5566 | 5726 | rqst.rq_nvec = 1; |
| 5567 | 5727 | |
| 5728 | + if (retries) | |
| 5729 | + smb2_set_replay(server, &rqst); | |
| 5730 | + | |
| 5568 | 5731 | rc = cifs_send_recv(xid, ses, server, |
| 5569 | 5732 | &rqst, &resp_buftype, flags, &rsp_iov); |
| 5570 | 5733 | free_qfs_info_req(&iov); |
| @@ -5584,6 +5747,11 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, · 13 unmodified lines | ||
| 5584 | 5747 | |
| 5585 | 5748 | posix_qfsinf_exit: |
| 5586 | 5749 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); |
| 5750 | + | |
| 5751 | + if (is_replayable_error(rc) && | |
| 5752 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 5753 | + goto replay_again; | |
| 5754 | + | |
| 5587 | 5755 | return rc; |
| 5588 | 5756 | } |
| 5589 | 5757 | |
| @@ -5598,9 +5766,15 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, · 8 unmodified lines | ||
| 5598 | 5766 | int rc = 0; |
| 5599 | 5767 | int resp_buftype; |
| 5600 | 5768 | struct cifs_ses *ses = tcon->ses; |
| 5601 | − struct TCP_Server_Info *server = cifs_pick_channel(ses); | |
| 5769 | + struct TCP_Server_Info *server; | |
| 5602 | 5770 | struct smb2_fs_full_size_info *info = NULL; |
| 5603 | 5771 | int flags = 0; |
| 5772 | + int retries = 0, cur_sleep = 1; | |
| 5773 | + | |
| 5774 | +replay_again: | |
| 5775 | + /* reinitialize for possible replay */ | |
| 5776 | + flags = 0; | |
| 5777 | + server = cifs_pick_channel(ses); | |
| 5604 | 5778 | |
| 5605 | 5779 | rc = build_qfs_info_req(&iov, tcon, server, |
| 5606 | 5780 | FS_FULL_SIZE_INFORMATION, |
| @@ -5616,6 +5790,9 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, · 9 unmodified lines | ||
| 5616 | 5790 | rqst.rq_iov = &iov; |
| 5617 | 5791 | rqst.rq_nvec = 1; |
| 5618 | 5792 | |
| 5793 | + if (retries) | |
| 5794 | + smb2_set_replay(server, &rqst); | |
| 5795 | + | |
| 5619 | 5796 | rc = cifs_send_recv(xid, ses, server, |
| 5620 | 5797 | &rqst, &resp_buftype, flags, &rsp_iov); |
| 5621 | 5798 | free_qfs_info_req(&iov); |
| @@ -5635,6 +5812,11 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, · 13 unmodified lines | ||
| 5635 | 5812 | |
| 5636 | 5813 | qfsinf_exit: |
| 5637 | 5814 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); |
| 5815 | + | |
| 5816 | + if (is_replayable_error(rc) && | |
| 5817 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 5818 | + goto replay_again; | |
| 5819 | + | |
| 5638 | 5820 | return rc; |
| 5639 | 5821 | } |
| 5640 | 5822 | |
| @@ -5649,9 +5831,15 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, · 8 unmodified lines | ||
| 5649 | 5831 | int rc = 0; |
| 5650 | 5832 | int resp_buftype, max_len, min_len; |
| 5651 | 5833 | struct cifs_ses *ses = tcon->ses; |
| 5652 | − struct TCP_Server_Info *server = cifs_pick_channel(ses); | |
| 5834 | + struct TCP_Server_Info *server; | |
| 5653 | 5835 | unsigned int rsp_len, offset; |
| 5654 | 5836 | int flags = 0; |
| 5837 | + int retries = 0, cur_sleep = 1; | |
| 5838 | + | |
| 5839 | +replay_again: | |
| 5840 | + /* reinitialize for possible replay */ | |
| 5841 | + flags = 0; | |
| 5842 | + server = cifs_pick_channel(ses); | |
| 5655 | 5843 | |
| 5656 | 5844 | if (level == FS_DEVICE_INFORMATION) { |
| 5657 | 5845 | max_len = sizeof(FILE_SYSTEM_DEVICE_INFO); |
| @@ -5683,6 +5871,9 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, · 25 unmodified lines | ||
| 5683 | 5871 | rqst.rq_iov = &iov; |
| 5684 | 5872 | rqst.rq_nvec = 1; |
| 5685 | 5873 | |
| 5874 | + if (retries) | |
| 5875 | + smb2_set_replay(server, &rqst); | |
| 5876 | + | |
| 5686 | 5877 | rc = cifs_send_recv(xid, ses, server, |
| 5687 | 5878 | &rqst, &resp_buftype, flags, &rsp_iov); |
| 5688 | 5879 | free_qfs_info_req(&iov); |
| @@ -5720,6 +5911,11 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, · 31 unmodified lines | ||
| 5720 | 5911 | |
| 5721 | 5912 | qfsattr_exit: |
| 5722 | 5913 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); |
| 5914 | + | |
| 5915 | + if (is_replayable_error(rc) && | |
| 5916 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 5917 | + goto replay_again; | |
| 5918 | + | |
| 5723 | 5919 | return rc; |
| 5724 | 5920 | } |
| 5725 | 5921 | |
| @@ -5737,7 +5933,13 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, · 11 unmodified lines | ||
| 5737 | 5933 | unsigned int count; |
| 5738 | 5934 | int flags = CIFS_NO_RSP_BUF; |
| 5739 | 5935 | unsigned int total_len; |
| 5740 | − struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses); | |
| 5936 | + struct TCP_Server_Info *server; | |
| 5937 | + int retries = 0, cur_sleep = 1; | |
| 5938 | + | |
| 5939 | +replay_again: | |
| 5940 | + /* reinitialize for possible replay */ | |
| 5941 | + flags = CIFS_NO_RSP_BUF; | |
| 5942 | + server = cifs_pick_channel(tcon->ses); | |
| 5741 | 5943 | |
| 5742 | 5944 | cifs_dbg(FYI, "smb2_lockv num lock %d\n", num_lock); |
| 5743 | 5945 | |
| @@ -5768,6 +5970,9 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, · 24 unmodified lines | ||
| 5768 | 5970 | rqst.rq_iov = iov; |
| 5769 | 5971 | rqst.rq_nvec = 2; |
| 5770 | 5972 | |
| 5973 | + if (retries) | |
| 5974 | + smb2_set_replay(server, &rqst); | |
| 5975 | + | |
| 5771 | 5976 | rc = cifs_send_recv(xid, tcon->ses, server, |
| 5772 | 5977 | &rqst, &resp_buf_type, flags, |
| 5773 | 5978 | &rsp_iov); |
| @@ -5779,6 +5984,10 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, · 5 unmodified lines | ||
| 5779 | 5984 | tcon->ses->Suid, rc); |
| 5780 | 5985 | } |
| 5781 | 5986 | |
| 5987 | + if (is_replayable_error(rc) && | |
| 5988 | + smb2_should_replay(tcon, &retries, &cur_sleep)) | |
| 5989 | + goto replay_again; | |
| 5990 | + | |
| 5782 | 5991 | return rc; |
| 5783 | 5992 | } |
| 5784 | 5993 | |
| @@ -122,6 +122,11 @@ extern unsigned long smb_rqst_len(struct TCP_Server_Info *server, · 121 unmodified lines | ||
| 122 | 122 | extern void smb2_set_next_command(struct cifs_tcon *tcon, |
| 123 | 123 | struct smb_rqst *rqst); |
| 124 | 124 | extern void smb2_set_related(struct smb_rqst *rqst); |
| 125 | +extern void smb2_set_replay(struct TCP_Server_Info *server, | |
| 126 | + struct smb_rqst *rqst); | |
| 127 | +extern bool smb2_should_replay(struct cifs_tcon *tcon, | |
| 128 | + int *pretries, | |
| 129 | + int *pcur_sleep); | |
| 125 | 130 | |
| 126 | 131 | /* |
| 127 | 132 | * SMB2 Worker functions - most of protocol specific implementation details |
| @@ -26,13 +26,6 @@ · 25 unmodified lines | ||
| 26 | 26 | #include "cifsproto.h" |
| 27 | 27 | #include "../common/md4.h" |
| 28 | 28 | |
| 29 | −#ifndef false | |
| 30 | −#define false 0 | |
| 31 | −#endif | |
| 32 | −#ifndef true | |
| 33 | −#define true 1 | |
| 34 | −#endif | |
| 35 | − | |
| 36 | 29 | /* following came from the other byteorder.h to avoid include conflicts */ |
| 37 | 30 | #define CVAL(buf,pos) (((unsigned char *)(buf))[pos]) |
| 38 | 31 | #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) |
| @@ -400,10 +400,17 @@ unmask: · 399 unmodified lines | ||
| 400 | 400 | server->conn_id, server->hostname); |
| 401 | 401 | } |
| 402 | 402 | smbd_done: |
| 403 | − if (rc < 0 && rc != -EINTR) | |
| 403 | + /* | |
| 404 | + * there's hardly any use for the layers above to know the | |
| 405 | + * actual error code here. All they should do at this point is | |
| 406 | + * to retry the connection and hope it goes away. | |
| 407 | + */ | |
| 408 | + if (rc < 0 && rc != -EINTR && rc != -EAGAIN) { | |
| 404 | 409 | cifs_server_dbg(VFS, "Error %d sending data on socket to server\n", |
| 405 | 410 | rc); |
| 406 | − else if (rc > 0) | |
| 411 | + rc = -ECONNABORTED; | |
| 412 | + cifs_signal_cifsd_for_reconnect(server, false); | |
| 413 | + } else if (rc > 0) | |
| 407 | 414 | rc = 0; |
| 408 | 415 | out: |
| 409 | 416 | cifs_in_send_dec(server); |
| @@ -1026,6 +1033,9 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses) · 616 unmodified lines | ||
| 1026 | 1033 | if (!server || server->terminate) |
| 1027 | 1034 | continue; |
| 1028 | 1035 | |
| 1036 | + if (CIFS_CHAN_NEEDS_RECONNECT(ses, i)) | |
| 1037 | + continue; | |
| 1038 | + | |
| 1029 | 1039 | /* |
| 1030 | 1040 | * strictly speaking, we should pick up req_lock to read |
| 1031 | 1041 | * server->in_flight. But it shouldn't matter much here if we |
| @@ -304,7 +304,8 @@ enum ksmbd_event { · 303 unmodified lines | ||
| 304 | 304 | KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST, |
| 305 | 305 | KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE = 15, |
| 306 | 306 | |
| 307 | − KSMBD_EVENT_MAX | |
| 307 | + __KSMBD_EVENT_MAX, | |
| 308 | + KSMBD_EVENT_MAX = __KSMBD_EVENT_MAX - 1 | |
| 308 | 309 | }; |
| 309 | 310 | |
| 310 | 311 | /* |
| @@ -74,7 +74,7 @@ static int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info) · 73 unmodified lines | ||
| 74 | 74 | static int handle_generic_event(struct sk_buff *skb, struct genl_info *info); |
| 75 | 75 | static int ksmbd_ipc_heartbeat_request(void); |
| 76 | 76 | |
| 77 | −static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX] = { | |
| 77 | +static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX + 1] = { | |
| 78 | 78 | [KSMBD_EVENT_UNSPEC] = { |
| 79 | 79 | .len = 0, |
| 80 | 80 | }, |
| @@ -403,7 +403,7 @@ static int handle_generic_event(struct sk_buff *skb, struct genl_info *info) · 322 unmodified lines | ||
| 403 | 403 | return -EPERM; |
| 404 | 404 | #endif |
| 405 | 405 | |
| 406 | − if (type >= KSMBD_EVENT_MAX) { | |
| 406 | + if (type > KSMBD_EVENT_MAX) { | |
| 407 | 407 | WARN_ON(1); |
| 408 | 408 | return -EINVAL; |
| 409 | 409 | } |
| @@ -365,6 +365,7 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig, · 364 unmodified lines | ||
| 365 | 365 | * @t: TCP transport instance |
| 366 | 366 | * @buf: buffer to store read data from socket |
| 367 | 367 | * @to_read: number of bytes to read from socket |
| 368 | + * @max_retries: number of retries if reading from socket fails | |
| 368 | 369 | * |
| 369 | 370 | * Return: on success return number of bytes read from socket, |
| 370 | 371 | * otherwise return error number |
| @@ -416,6 +417,7 @@ static void tcp_destroy_socket(struct socket *ksmbd_socket) · 45 unmodified lines | ||
| 416 | 417 | |
| 417 | 418 | /** |
| 418 | 419 | * create_socket - create socket for ksmbd/0 |
| 420 | + * @iface: interface to bind the created socket to | |
| 419 | 421 | * |
| 420 | 422 | * Return: 0 on success, error number otherwise |
| 421 | 423 | */ |
| @@ -281,44 +281,6 @@ static void update_inode_attr(struct dentry *dentry, struct inode *inode, · 280 unmodified lines | ||
| 281 | 281 | inode->i_gid = attr->gid; |
| 282 | 282 | } |
| 283 | 283 | |
| 284 | −static void update_gid(struct eventfs_inode *ei, kgid_t gid, int level) | |
| 285 | −{ | |
| 286 | − struct eventfs_inode *ei_child; | |
| 287 | − | |
| 288 | − /* at most we have events/system/event */ | |
| 289 | − if (WARN_ON_ONCE(level > 3)) | |
| 290 | − return; | |
| 291 | − | |
| 292 | − ei->attr.gid = gid; | |
| 293 | − | |
| 294 | − if (ei->entry_attrs) { | |
| 295 | − for (int i = 0; i < ei->nr_entries; i++) { | |
| 296 | − ei->entry_attrs[i].gid = gid; | |
| 297 | − } | |
| 298 | − } | |
| 299 | − | |
| 300 | − /* | |
| 301 | − * Only eventfs_inode with dentries are updated, make sure | |
| 302 | − * all eventfs_inodes are updated. If one of the children | |
| 303 | − * do not have a dentry, this function must traverse it. | |
| 304 | − */ | |
| 305 | − list_for_each_entry_srcu(ei_child, &ei->children, list, | |
| 306 | − srcu_read_lock_held(&eventfs_srcu)) { | |
| 307 | − if (!ei_child->dentry) | |
| 308 | − update_gid(ei_child, gid, level + 1); | |
| 309 | − } | |
| 310 | −} | |
| 311 | − | |
| 312 | −void eventfs_update_gid(struct dentry *dentry, kgid_t gid) | |
| 313 | −{ | |
| 314 | − struct eventfs_inode *ei = dentry->d_fsdata; | |
| 315 | − int idx; | |
| 316 | − | |
| 317 | − idx = srcu_read_lock(&eventfs_srcu); | |
| 318 | − update_gid(ei, gid, 0); | |
| 319 | − srcu_read_unlock(&eventfs_srcu, idx); | |
| 320 | −} | |
| 321 | − | |
| 322 | 284 | /** |
| 323 | 285 | * create_file - create a file in the tracefs filesystem |
| 324 | 286 | * @name: the name of the file to create. |
| @@ -82,7 +82,6 @@ struct inode *tracefs_get_inode(struct super_block *sb); · 81 unmodified lines | ||
| 82 | 82 | struct dentry *eventfs_start_creating(const char *name, struct dentry *parent); |
| 83 | 83 | struct dentry *eventfs_failed_creating(struct dentry *dentry); |
| 84 | 84 | struct dentry *eventfs_end_creating(struct dentry *dentry); |
| 85 | −void eventfs_update_gid(struct dentry *dentry, kgid_t gid); | |
| 86 | 85 | void eventfs_set_ei_status_free(struct tracefs_inode *ti, struct dentry *dentry); |
| 87 | 86 | |
| 88 | 87 | #endif /* _TRACEFS_INTERNAL_H */ |
| @@ -1496,6 +1496,18 @@ xfs_fs_fill_super( · 1495 unmodified lines | ||
| 1496 | 1496 | |
| 1497 | 1497 | mp->m_super = sb; |
| 1498 | 1498 | |
| 1499 | + /* | |
| 1500 | + * Copy VFS mount flags from the context now that all parameter parsing | |
| 1501 | + * is guaranteed to have been completed by either the old mount API or | |
| 1502 | + * the newer fsopen/fsconfig API. | |
| 1503 | + */ | |
| 1504 | + if (fc->sb_flags & SB_RDONLY) | |
| 1505 | + set_bit(XFS_OPSTATE_READONLY, &mp->m_opstate); | |
| 1506 | + if (fc->sb_flags & SB_DIRSYNC) | |
| 1507 | + mp->m_features |= XFS_FEAT_DIRSYNC; | |
| 1508 | + if (fc->sb_flags & SB_SYNCHRONOUS) | |
| 1509 | + mp->m_features |= XFS_FEAT_WSYNC; | |
| 1510 | + | |
| 1499 | 1511 | error = xfs_fs_validate_params(mp); |
| 1500 | 1512 | if (error) |
| 1501 | 1513 | return error; |
| @@ -1965,6 +1977,11 @@ static const struct fs_context_operations xfs_context_ops = { · 463 unmodified lines | ||
| 1965 | 1977 | .free = xfs_fs_free, |
| 1966 | 1978 | }; |
| 1967 | 1979 | |
| 1980 | +/* | |
| 1981 | + * WARNING: do not initialise any parameters in this function that depend on | |
| 1982 | + * mount option parsing having already been performed as this can be called from | |
| 1983 | + * fsopen() before any parameters have been set. | |
| 1984 | + */ | |
| 1968 | 1985 | static int xfs_init_fs_context( |
| 1969 | 1986 | struct fs_context *fc) |
| 1970 | 1987 | { |
| @@ -1996,16 +2013,6 @@ static int xfs_init_fs_context( · 25 unmodified lines | ||
| 1996 | 2013 | mp->m_logbsize = -1; |
| 1997 | 2014 | mp->m_allocsize_log = 16; /* 64k */ |
| 1998 | 2015 | |
| 1999 | − /* | |
| 2000 | − * Copy binary VFS mount flags we are interested in. | |
| 2001 | − */ | |
| 2002 | − if (fc->sb_flags & SB_RDONLY) | |
| 2003 | − set_bit(XFS_OPSTATE_READONLY, &mp->m_opstate); | |
| 2004 | − if (fc->sb_flags & SB_DIRSYNC) | |
| 2005 | − mp->m_features |= XFS_FEAT_DIRSYNC; | |
| 2006 | − if (fc->sb_flags & SB_SYNCHRONOUS) | |
| 2007 | − mp->m_features |= XFS_FEAT_WSYNC; | |
| 2008 | − | |
| 2009 | 2016 | fc->s_fs_info = mp; |
| 2010 | 2017 | fc->ops = &xfs_context_ops; |
| 2011 | 2018 | |
| @@ -77,17 +77,6 @@ enum hid_bpf_attach_flags { · 76 unmodified lines | ||
| 77 | 77 | int hid_bpf_device_event(struct hid_bpf_ctx *ctx); |
| 78 | 78 | int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx); |
| 79 | 79 | |
| 80 | −/* Following functions are kfunc that we export to BPF programs */ | |
| 81 | −/* available everywhere in HID-BPF */ | |
| 82 | −__u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t __sz); | |
| 83 | − | |
| 84 | −/* only available in syscall */ | |
| 85 | −int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags); | |
| 86 | −int hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, | |
| 87 | − enum hid_report_type rtype, enum hid_class_request reqtype); | |
| 88 | −struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id); | |
| 89 | −void hid_bpf_release_context(struct hid_bpf_ctx *ctx); | |
| 90 | − | |
| 91 | 80 | /* |
| 92 | 81 | * Below is HID internal |
| 93 | 82 | */ |
| @@ -471,7 +471,7 @@ enum ata_completion_errors { · 470 unmodified lines | ||
| 471 | 471 | |
| 472 | 472 | /* |
| 473 | 473 | * Link power management policy: If you alter this, you also need to |
| 474 | − * alter libata-scsi.c (for the ascii descriptions) | |
| 474 | + * alter libata-sata.c (for the ascii descriptions) | |
| 475 | 475 | */ |
| 476 | 476 | enum ata_lpm_policy { |
| 477 | 477 | ATA_LPM_UNKNOWN, |
| @@ -315,9 +315,9 @@ LSM_HOOK(int, 0, socket_getsockopt, struct socket *sock, int level, int optname) · 314 unmodified lines | ||
| 315 | 315 | LSM_HOOK(int, 0, socket_setsockopt, struct socket *sock, int level, int optname) |
| 316 | 316 | LSM_HOOK(int, 0, socket_shutdown, struct socket *sock, int how) |
| 317 | 317 | LSM_HOOK(int, 0, socket_sock_rcv_skb, struct sock *sk, struct sk_buff *skb) |
| 318 | −LSM_HOOK(int, 0, socket_getpeersec_stream, struct socket *sock, | |
| 318 | +LSM_HOOK(int, -ENOPROTOOPT, socket_getpeersec_stream, struct socket *sock, | |
| 319 | 319 | sockptr_t optval, sockptr_t optlen, unsigned int len) |
| 320 | −LSM_HOOK(int, 0, socket_getpeersec_dgram, struct socket *sock, | |
| 320 | +LSM_HOOK(int, -ENOPROTOOPT, socket_getpeersec_dgram, struct socket *sock, | |
| 321 | 321 | struct sk_buff *skb, u32 *secid) |
| 322 | 322 | LSM_HOOK(int, 0, sk_alloc_security, struct sock *sk, int family, gfp_t priority) |
| 323 | 323 | LSM_HOOK(void, LSM_RET_VOID, sk_free_security, struct sock *sk) |
| @@ -156,6 +156,7 @@ calc_vm_flag_bits(unsigned long flags) · 155 unmodified lines | ||
| 156 | 156 | return _calc_vm_trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN ) | |
| 157 | 157 | _calc_vm_trans(flags, MAP_LOCKED, VM_LOCKED ) | |
| 158 | 158 | _calc_vm_trans(flags, MAP_SYNC, VM_SYNC ) | |
| 159 | + _calc_vm_trans(flags, MAP_STACK, VM_NOHUGEPAGE) | | |
| 159 | 160 | arch_calc_vm_flag_bits(flags); |
| 160 | 161 | } |
| 161 | 162 | |
| @@ -2013,9 +2013,9 @@ static inline int pfn_valid(unsigned long pfn) · 2012 unmodified lines | ||
| 2013 | 2013 | if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS) |
| 2014 | 2014 | return 0; |
| 2015 | 2015 | ms = __pfn_to_section(pfn); |
| 2016 | − rcu_read_lock(); | |
| 2016 | + rcu_read_lock_sched(); | |
| 2017 | 2017 | if (!valid_section(ms)) { |
| 2018 | − rcu_read_unlock(); | |
| 2018 | + rcu_read_unlock_sched(); | |
| 2019 | 2019 | return 0; |
| 2020 | 2020 | } |
| 2021 | 2021 | /* |
| @@ -2023,7 +2023,7 @@ static inline int pfn_valid(unsigned long pfn) · 1 unmodified line | ||
| 2023 | 2023 | * the entire section-sized span. |
| 2024 | 2024 | */ |
| 2025 | 2025 | ret = early_section(ms) || pfn_section_valid(ms, pfn); |
| 2026 | − rcu_read_unlock(); | |
| 2026 | + rcu_read_unlock_sched(); | |
| 2027 | 2027 | |
| 2028 | 2028 | return ret; |
| 2029 | 2029 | } |
| @@ -186,6 +186,8 @@ struct ip_set_type_variant { · 185 unmodified lines | ||
| 186 | 186 | /* Return true if "b" set is the same as "a" |
| 187 | 187 | * according to the create set parameters */ |
| 188 | 188 | bool (*same_set)(const struct ip_set *a, const struct ip_set *b); |
| 189 | + /* Cancel ongoing garbage collectors before destroying the set*/ | |
| 190 | + void (*cancel_gc)(struct ip_set *set); | |
| 189 | 191 | /* Region-locking is used */ |
| 190 | 192 | bool region_lock; |
| 191 | 193 | }; |
| @@ -242,6 +244,8 @@ extern void ip_set_type_unregister(struct ip_set_type *set_type); · 50 unmodified lines | ||
| 242 | 244 | |
| 243 | 245 | /* A generic IP set */ |
| 244 | 246 | struct ip_set { |
| 247 | + /* For call_cru in destroy */ | |
| 248 | + struct rcu_head rcu; | |
| 245 | 249 | /* The name of the set */ |
| 246 | 250 | char name[IPSET_MAXNAMELEN]; |
| 247 | 251 | /* Lock protecting the set data */ |
| @@ -21,7 +21,7 @@ · 20 unmodified lines | ||
| 21 | 21 | #include <uapi/linux/spi/spi.h> |
| 22 | 22 | |
| 23 | 23 | /* Max no. of CS supported per spi device */ |
| 24 | −#define SPI_CS_CNT_MAX 4 | |
| 24 | +#define SPI_CS_CNT_MAX 16 | |
| 25 | 25 | |
| 26 | 26 | struct dma_chan; |
| 27 | 27 | struct software_node; |
| @@ -128,6 +128,7 @@ struct mnt_id_req; · 127 unmodified lines | ||
| 128 | 128 | #define __TYPE_IS_LL(t) (__TYPE_AS(t, 0LL) || __TYPE_AS(t, 0ULL)) |
| 129 | 129 | #define __SC_LONG(t, a) __typeof(__builtin_choose_expr(__TYPE_IS_LL(t), 0LL, 0L)) a |
| 130 | 130 | #define __SC_CAST(t, a) (__force t) a |
| 131 | +#define __SC_TYPE(t, a) t | |
| 131 | 132 | #define __SC_ARGS(t, a) a |
| 132 | 133 | #define __SC_TEST(t, a) (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(t) && sizeof(t) > sizeof(long)) |
| 133 | 134 | |
| @@ -54,12 +54,6 @@ struct scm_stat { · 53 unmodified lines | ||
| 54 | 54 | |
| 55 | 55 | #define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb)) |
| 56 | 56 | |
| 57 | −#define unix_state_lock(s) spin_lock(&unix_sk(s)->lock) | |
| 58 | −#define unix_state_unlock(s) spin_unlock(&unix_sk(s)->lock) | |
| 59 | −#define unix_state_lock_nested(s) \ | |
| 60 | − spin_lock_nested(&unix_sk(s)->lock, \ | |
| 61 | − SINGLE_DEPTH_NESTING) | |
| 62 | − | |
| 63 | 57 | /* The AF_UNIX socket */ |
| 64 | 58 | struct unix_sock { |
| 65 | 59 | /* WARNING: sk has to be the first member */ |
| @@ -85,6 +79,20 @@ struct unix_sock { · 19 unmodified lines | ||
| 85 | 79 | #define unix_sk(ptr) container_of_const(ptr, struct unix_sock, sk) |
| 86 | 80 | #define unix_peer(sk) (unix_sk(sk)->peer) |
| 87 | 81 | |
| 82 | +#define unix_state_lock(s) spin_lock(&unix_sk(s)->lock) | |
| 83 | +#define unix_state_unlock(s) spin_unlock(&unix_sk(s)->lock) | |
| 84 | +enum unix_socket_lock_class { | |
| 85 | + U_LOCK_NORMAL, | |
| 86 | + U_LOCK_SECOND, /* for double locking, see unix_state_double_lock(). */ | |
| 87 | + U_LOCK_DIAG, /* used while dumping icons, see sk_diag_dump_icons(). */ | |
| 88 | +}; | |
| 89 | + | |
| 90 | +static inline void unix_state_lock_nested(struct sock *sk, | |
| 91 | + enum unix_socket_lock_class subclass) | |
| 92 | +{ | |
| 93 | + spin_lock_nested(&unix_sk(sk)->lock, subclass); | |
| 94 | +} | |
| 95 | + | |
| 88 | 96 | #define peer_wait peer_wq.wait |
| 89 | 97 | |
| 90 | 98 | long unix_inq_len(struct sock *sk); |
| @@ -767,7 +767,7 @@ int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev); · 766 unmodified lines | ||
| 767 | 767 | * Functions provided by ip_sockglue.c |
| 768 | 768 | */ |
| 769 | 769 | |
| 770 | −void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb); | |
| 770 | +void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb, bool drop_dst); | |
| 771 | 771 | void ip_cmsg_recv_offset(struct msghdr *msg, struct sock *sk, |
| 772 | 772 | struct sk_buff *skb, int tlen, int offset); |
| 773 | 773 | int ip_cmsg_send(struct sock *sk, struct msghdr *msg, |
| @@ -1357,6 +1357,7 @@ void nft_obj_notify(struct net *net, const struct nft_table *table, · 1356 unmodified lines | ||
| 1357 | 1357 | * @type: stateful object numeric type |
| 1358 | 1358 | * @owner: module owner |
| 1359 | 1359 | * @maxattr: maximum netlink attribute |
| 1360 | + * @family: address family for AF-specific object types | |
| 1360 | 1361 | * @policy: netlink attribute policy |
| 1361 | 1362 | */ |
| 1362 | 1363 | struct nft_object_type { |
| @@ -1366,6 +1367,7 @@ struct nft_object_type { · 3 unmodified lines | ||
| 1366 | 1367 | struct list_head list; |
| 1367 | 1368 | u32 type; |
| 1368 | 1369 | unsigned int maxattr; |
| 1370 | + u8 family; | |
| 1369 | 1371 | struct module *owner; |
| 1370 | 1372 | const struct nla_policy *policy; |
| 1371 | 1373 | }; |
| @@ -53,7 +53,7 @@ extern "C" { · 52 unmodified lines | ||
| 53 | 53 | #define DRM_IVPU_PARAM_CORE_CLOCK_RATE 3 |
| 54 | 54 | #define DRM_IVPU_PARAM_NUM_CONTEXTS 4 |
| 55 | 55 | #define DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS 5 |
| 56 | −#define DRM_IVPU_PARAM_CONTEXT_PRIORITY 6 | |
| 56 | +#define DRM_IVPU_PARAM_CONTEXT_PRIORITY 6 /* Deprecated */ | |
| 57 | 57 | #define DRM_IVPU_PARAM_CONTEXT_ID 7 |
| 58 | 58 | #define DRM_IVPU_PARAM_FW_API_VERSION 8 |
| 59 | 59 | #define DRM_IVPU_PARAM_ENGINE_HEARTBEAT 9 |
| @@ -64,11 +64,18 @@ extern "C" { · 4 unmodified lines | ||
| 64 | 64 | |
| 65 | 65 | #define DRM_IVPU_PLATFORM_TYPE_SILICON 0 |
| 66 | 66 | |
| 67 | +/* Deprecated, use DRM_IVPU_JOB_PRIORITY */ | |
| 67 | 68 | #define DRM_IVPU_CONTEXT_PRIORITY_IDLE 0 |
| 68 | 69 | #define DRM_IVPU_CONTEXT_PRIORITY_NORMAL 1 |
| 69 | 70 | #define DRM_IVPU_CONTEXT_PRIORITY_FOCUS 2 |
| 70 | 71 | #define DRM_IVPU_CONTEXT_PRIORITY_REALTIME 3 |
| 71 | 72 | |
| 73 | +#define DRM_IVPU_JOB_PRIORITY_DEFAULT 0 | |
| 74 | +#define DRM_IVPU_JOB_PRIORITY_IDLE 1 | |
| 75 | +#define DRM_IVPU_JOB_PRIORITY_NORMAL 2 | |
| 76 | +#define DRM_IVPU_JOB_PRIORITY_FOCUS 3 | |
| 77 | +#define DRM_IVPU_JOB_PRIORITY_REALTIME 4 | |
| 78 | + | |
| 72 | 79 | /** |
| 73 | 80 | * DRM_IVPU_CAP_METRIC_STREAMER |
| 74 | 81 | * |
| @@ -112,10 +119,6 @@ struct drm_ivpu_param { · 37 unmodified lines | ||
| 112 | 119 | * %DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS: |
| 113 | 120 | * Lowest VPU virtual address available in the current context (read-only) |
| 114 | 121 | * |
| 115 | − * %DRM_IVPU_PARAM_CONTEXT_PRIORITY: | |
| 116 | − * Value of current context scheduling priority (read-write). | |
| 117 | − * See DRM_IVPU_CONTEXT_PRIORITY_* for possible values. | |
| 118 | − * | |
| 119 | 122 | * %DRM_IVPU_PARAM_CONTEXT_ID: |
| 120 | 123 | * Current context ID, always greater than 0 (read-only) |
| 121 | 124 | * |
| @@ -286,6 +289,18 @@ struct drm_ivpu_submit { · 164 unmodified lines | ||
| 286 | 289 | * to be executed. The offset has to be 8-byte aligned. |
| 287 | 290 | */ |
| 288 | 291 | __u32 commands_offset; |
| 292 | + | |
| 293 | + /** | |
| 294 | + * @priority: | |
| 295 | + * | |
| 296 | + * Priority to be set for related job command queue, can be one of the following: | |
| 297 | + * %DRM_IVPU_JOB_PRIORITY_DEFAULT | |
| 298 | + * %DRM_IVPU_JOB_PRIORITY_IDLE | |
| 299 | + * %DRM_IVPU_JOB_PRIORITY_NORMAL | |
| 300 | + * %DRM_IVPU_JOB_PRIORITY_FOCUS | |
| 301 | + * %DRM_IVPU_JOB_PRIORITY_REALTIME | |
| 302 | + */ | |
| 303 | + __u32 priority; | |
| 289 | 304 | }; |
| 290 | 305 | |
| 291 | 306 | /* drm_ivpu_bo_wait job status codes */ |
| @@ -471,7 +471,6 @@ const struct io_issue_def io_issue_defs[] = { · 470 unmodified lines | ||
| 471 | 471 | }, |
| 472 | 472 | [IORING_OP_FIXED_FD_INSTALL] = { |
| 473 | 473 | .needs_file = 1, |
| 474 | − .audit_skip = 1, | |
| 475 | 474 | .prep = io_install_fixed_fd_prep, |
| 476 | 475 | .issue = io_install_fixed_fd, |
| 477 | 476 | }, |
| @@ -277,6 +277,10 @@ int io_install_fixed_fd_prep(struct io_kiocb *req, const struct io_uring_sqe *sq · 276 unmodified lines | ||
| 277 | 277 | if (flags & ~IORING_FIXED_FD_NO_CLOEXEC) |
| 278 | 278 | return -EINVAL; |
| 279 | 279 | |
| 280 | + /* ensure the task's creds are used when installing/receiving fds */ | |
| 281 | + if (req->flags & REQ_F_CREDS) | |
| 282 | + return -EPERM; | |
| 283 | + | |
| 280 | 284 | /* default to O_CLOEXEC, disable if IORING_FIXED_FD_NO_CLOEXEC is set */ |
| 281 | 285 | ifi = io_kiocb_to_cmd(req, struct io_fixed_install); |
| 282 | 286 | ifi->o_flags = O_CLOEXEC; |
| @@ -537,7 +537,7 @@ retry: · 536 unmodified lines | ||
| 537 | 537 | } |
| 538 | 538 | } |
| 539 | 539 | |
| 540 | − ret = __replace_page(vma, vaddr, old_page, new_page); | |
| 540 | + ret = __replace_page(vma, vaddr & PAGE_MASK, old_page, new_page); | |
| 541 | 541 | if (new_page) |
| 542 | 542 | put_page(new_page); |
| 543 | 543 | put_old: |
| @@ -627,12 +627,21 @@ retry: · 626 unmodified lines | ||
| 627 | 627 | } |
| 628 | 628 | |
| 629 | 629 | /* |
| 630 | − * PI futexes can not be requeued and must remove themselves from the | |
| 631 | − * hash bucket. The hash bucket lock (i.e. lock_ptr) is held. | |
| 630 | + * PI futexes can not be requeued and must remove themselves from the hash | |
| 631 | + * bucket. The hash bucket lock (i.e. lock_ptr) is held. | |
| 632 | 632 | */ |
| 633 | 633 | void futex_unqueue_pi(struct futex_q *q) |
| 634 | 634 | { |
| 635 | − __futex_unqueue(q); | |
| 635 | + /* | |
| 636 | + * If the lock was not acquired (due to timeout or signal) then the | |
| 637 | + * rt_waiter is removed before futex_q is. If this is observed by | |
| 638 | + * an unlocker after dropping the rtmutex wait lock and before | |
| 639 | + * acquiring the hash bucket lock, then the unlocker dequeues the | |
| 640 | + * futex_q from the hash bucket list to guarantee consistent state | |
| 641 | + * vs. userspace. Therefore the dequeue here must be conditional. | |
| 642 | + */ | |
| 643 | + if (!plist_node_empty(&q->list)) | |
| 644 | + __futex_unqueue(q); | |
| 636 | 645 | |
| 637 | 646 | BUG_ON(!q->pi_state); |
| 638 | 647 | put_pi_state(q->pi_state); |
| @@ -1135,6 +1135,7 @@ retry: · 1134 unmodified lines | ||
| 1135 | 1135 | |
| 1136 | 1136 | hb = futex_hash(&key); |
| 1137 | 1137 | spin_lock(&hb->lock); |
| 1138 | +retry_hb: | |
| 1138 | 1139 | |
| 1139 | 1140 | /* |
| 1140 | 1141 | * Check waiters first. We do not trust user space values at |
| @@ -1177,12 +1178,17 @@ retry: · 36 unmodified lines | ||
| 1177 | 1178 | /* |
| 1178 | 1179 | * Futex vs rt_mutex waiter state -- if there are no rt_mutex |
| 1179 | 1180 | * waiters even though futex thinks there are, then the waiter |
| 1180 | − * is leaving and the uncontended path is safe to take. | |
| 1181 | + * is leaving. The entry needs to be removed from the list so a | |
| 1182 | + * new futex_lock_pi() is not using this stale PI-state while | |
| 1183 | + * the futex is available in user space again. | |
| 1184 | + * There can be more than one task on its way out so it needs | |
| 1185 | + * to retry. | |
| 1181 | 1186 | */ |
| 1182 | 1187 | rt_waiter = rt_mutex_top_waiter(&pi_state->pi_mutex); |
| 1183 | 1188 | if (!rt_waiter) { |
| 1189 | + __futex_unqueue(top_waiter); | |
| 1184 | 1190 | raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock); |
| 1185 | − goto do_uncontended; | |
| 1191 | + goto retry_hb; | |
| 1186 | 1192 | } |
| 1187 | 1193 | |
| 1188 | 1194 | get_pi_state(pi_state); |
| @@ -1217,7 +1223,6 @@ retry: · 28 unmodified lines | ||
| 1217 | 1223 | return ret; |
| 1218 | 1224 | } |
| 1219 | 1225 | |
| 1220 | −do_uncontended: | |
| 1221 | 1226 | /* |
| 1222 | 1227 | * We have no kernel internal state, i.e. no waiters in the |
| 1223 | 1228 | * kernel. Waiters which are about to queue themselves are stuck |
| @@ -600,7 +600,7 @@ int __init early_irq_init(void) · 599 unmodified lines | ||
| 600 | 600 | mutex_init(&desc[i].request_mutex); |
| 601 | 601 | init_waitqueue_head(&desc[i].wait_for_threads); |
| 602 | 602 | desc_set_defaults(i, &desc[i], node, NULL, NULL); |
| 603 | − irq_resend_init(desc); | |
| 603 | + irq_resend_init(&desc[i]); | |
| 604 | 604 | } |
| 605 | 605 | return arch_early_irq_init(); |
| 606 | 606 | } |
| @@ -99,6 +99,7 @@ static u64 suspend_start; · 98 unmodified lines | ||
| 99 | 99 | * Interval: 0.5sec. |
| 100 | 100 | */ |
| 101 | 101 | #define WATCHDOG_INTERVAL (HZ >> 1) |
| 102 | +#define WATCHDOG_INTERVAL_MAX_NS ((2 * WATCHDOG_INTERVAL) * (NSEC_PER_SEC / HZ)) | |
| 102 | 103 | |
| 103 | 104 | /* |
| 104 | 105 | * Threshold: 0.0312s, when doubled: 0.0625s. |
| @@ -134,6 +135,7 @@ static DECLARE_WORK(watchdog_work, clocksource_watchdog_work); · 29 unmodified lines | ||
| 134 | 135 | static DEFINE_SPINLOCK(watchdog_lock); |
| 135 | 136 | static int watchdog_running; |
| 136 | 137 | static atomic_t watchdog_reset_pending; |
| 138 | +static int64_t watchdog_max_interval; | |
| 137 | 139 | |
| 138 | 140 | static inline void clocksource_watchdog_lock(unsigned long *flags) |
| 139 | 141 | { |
| @@ -399,8 +401,8 @@ static inline void clocksource_reset_watchdog(void) · 259 unmodified lines | ||
| 399 | 401 | static void clocksource_watchdog(struct timer_list *unused) |
| 400 | 402 | { |
| 401 | 403 | u64 csnow, wdnow, cslast, wdlast, delta; |
| 404 | + int64_t wd_nsec, cs_nsec, interval; | |
| 402 | 405 | int next_cpu, reset_pending; |
| 403 | − int64_t wd_nsec, cs_nsec; | |
| 404 | 406 | struct clocksource *cs; |
| 405 | 407 | enum wd_read_status read_ret; |
| 406 | 408 | unsigned long extra_wait = 0; |
| @@ -470,6 +472,27 @@ static void clocksource_watchdog(struct timer_list *unused) · 63 unmodified lines | ||
| 470 | 472 | if (atomic_read(&watchdog_reset_pending)) |
| 471 | 473 | continue; |
| 472 | 474 | |
| 475 | + /* | |
| 476 | + * The processing of timer softirqs can get delayed (usually | |
| 477 | + * on account of ksoftirqd not getting to run in a timely | |
| 478 | + * manner), which causes the watchdog interval to stretch. | |
| 479 | + * Skew detection may fail for longer watchdog intervals | |
| 480 | + * on account of fixed margins being used. | |
| 481 | + * Some clocksources, e.g. acpi_pm, cannot tolerate | |
| 482 | + * watchdog intervals longer than a few seconds. | |
| 483 | + */ | |
| 484 | + interval = max(cs_nsec, wd_nsec); | |
| 485 | + if (unlikely(interval > WATCHDOG_INTERVAL_MAX_NS)) { | |
| 486 | + if (system_state > SYSTEM_SCHEDULING && | |
| 487 | + interval > 2 * watchdog_max_interval) { | |
| 488 | + watchdog_max_interval = interval; | |
| 489 | + pr_warn("Long readout interval, skipping watchdog check: cs_nsec: %lld wd_nsec: %lld\n", | |
| 490 | + cs_nsec, wd_nsec); | |
| 491 | + } | |
| 492 | + watchdog_timer.expires = jiffies; | |
| 493 | + continue; | |
| 494 | + } | |
| 495 | + | |
| 473 | 496 | /* Check the deviation from the watchdog clocksource. */ |
| 474 | 497 | md = cs->uncertainty_margin + watchdog->uncertainty_margin; |
| 475 | 498 | if (abs(cs_nsec - wd_nsec) > md) { |
| @@ -1577,6 +1577,7 @@ void tick_cancel_sched_timer(int cpu) · 1576 unmodified lines | ||
| 1577 | 1577 | { |
| 1578 | 1578 | struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); |
| 1579 | 1579 | ktime_t idle_sleeptime, iowait_sleeptime; |
| 1580 | + unsigned long idle_calls, idle_sleeps; | |
| 1580 | 1581 | |
| 1581 | 1582 | # ifdef CONFIG_HIGH_RES_TIMERS |
| 1582 | 1583 | if (ts->sched_timer.base) |
| @@ -1585,9 +1586,13 @@ void tick_cancel_sched_timer(int cpu) · 2 unmodified lines | ||
| 1585 | 1586 | |
| 1586 | 1587 | idle_sleeptime = ts->idle_sleeptime; |
| 1587 | 1588 | iowait_sleeptime = ts->iowait_sleeptime; |
| 1589 | + idle_calls = ts->idle_calls; | |
| 1590 | + idle_sleeps = ts->idle_sleeps; | |
| 1588 | 1591 | memset(ts, 0, sizeof(*ts)); |
| 1589 | 1592 | ts->idle_sleeptime = idle_sleeptime; |
| 1590 | 1593 | ts->iowait_sleeptime = iowait_sleeptime; |
| 1594 | + ts->idle_calls = idle_calls; | |
| 1595 | + ts->idle_sleeps = idle_sleeps; | |
| 1591 | 1596 | } |
| 1592 | 1597 | #endif |
| 1593 | 1598 | |
| @@ -1470,8 +1470,10 @@ register_snapshot_trigger(char *glob, · 1469 unmodified lines | ||
| 1470 | 1470 | struct event_trigger_data *data, |
| 1471 | 1471 | struct trace_event_file *file) |
| 1472 | 1472 | { |
| 1473 | − if (tracing_alloc_snapshot_instance(file->tr) != 0) | |
| 1474 | − return 0; | |
| 1473 | + int ret = tracing_alloc_snapshot_instance(file->tr); | |
| 1474 | + | |
| 1475 | + if (ret < 0) | |
| 1476 | + return ret; | |
| 1475 | 1477 | |
| 1476 | 1478 | return register_trigger(glob, data, file); |
| 1477 | 1479 | } |
| @@ -45,8 +45,8 @@ int kunit_bus_init(void) · 44 unmodified lines | ||
| 45 | 45 | int error; |
| 46 | 46 | |
| 47 | 47 | kunit_bus_device = root_device_register("kunit"); |
| 48 | − if (!kunit_bus_device) | |
| 49 | − return -ENOMEM; | |
| 48 | + if (IS_ERR(kunit_bus_device)) | |
| 49 | + return PTR_ERR(kunit_bus_device); | |
| 50 | 50 | |
| 51 | 51 | error = bus_register(&kunit_bus_type); |
| 52 | 52 | if (error) |
| @@ -146,6 +146,10 @@ void kunit_free_suite_set(struct kunit_suite_set suite_set) · 145 unmodified lines | ||
| 146 | 146 | kfree(suite_set.start); |
| 147 | 147 | } |
| 148 | 148 | |
| 149 | +/* | |
| 150 | + * Filter and reallocate test suites. Must return the filtered test suites set | |
| 151 | + * allocated at a valid virtual address or NULL in case of error. | |
| 152 | + */ | |
| 149 | 153 | struct kunit_suite_set |
| 150 | 154 | kunit_filter_suites(const struct kunit_suite_set *suite_set, |
| 151 | 155 | const char *filter_glob, |
| @@ -720,7 +720,7 @@ static void kunit_device_cleanup_test(struct kunit *test) · 719 unmodified lines | ||
| 720 | 720 | long action_was_run = 0; |
| 721 | 721 | |
| 722 | 722 | test_device = kunit_device_register(test, "my_device"); |
| 723 | − KUNIT_ASSERT_NOT_NULL(test, test_device); | |
| 723 | + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_device); | |
| 724 | 724 | |
| 725 | 725 | /* Add an action to verify cleanup. */ |
| 726 | 726 | devm_add_action(test_device, test_dev_action, &action_was_run); |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/panic.h> |
| 18 | 18 | #include <linux/sched/debug.h> |
| 19 | 19 | #include <linux/sched.h> |
| 20 | +#include <linux/mm.h> | |
| 20 | 21 | |
| 21 | 22 | #include "debugfs.h" |
| 22 | 23 | #include "device-impl.h" |
| @@ -801,12 +802,19 @@ static void kunit_module_exit(struct module *mod) · 778 unmodified lines | ||
| 801 | 802 | }; |
| 802 | 803 | const char *action = kunit_action(); |
| 803 | 804 | |
| 805 | + /* | |
| 806 | + * Check if the start address is a valid virtual address to detect | |
| 807 | + * if the module load sequence has failed and the suite set has not | |
| 808 | + * been initialized and filtered. | |
| 809 | + */ | |
| 810 | + if (!suite_set.start || !virt_addr_valid(suite_set.start)) | |
| 811 | + return; | |
| 812 | + | |
| 804 | 813 | if (!action) |
| 805 | 814 | __kunit_test_suites_exit(mod->kunit_suites, |
| 806 | 815 | mod->num_kunit_suites); |
| 807 | 816 | |
| 808 | − if (suite_set.start) | |
| 809 | − kunit_free_suite_set(suite_set); | |
| 817 | + kunit_free_suite_set(suite_set); | |
| 810 | 818 | } |
| 811 | 819 | |
| 812 | 820 | static int kunit_module_notify(struct notifier_block *nb, unsigned long val, |
| @@ -816,12 +824,12 @@ static int kunit_module_notify(struct notifier_block *nb, unsigned long val, · 3 unmodified lines | ||
| 816 | 824 | |
| 817 | 825 | switch (val) { |
| 818 | 826 | case MODULE_STATE_LIVE: |
| 827 | + kunit_module_init(mod); | |
| 819 | 828 | break; |
| 820 | 829 | case MODULE_STATE_GOING: |
| 821 | 830 | kunit_module_exit(mod); |
| 822 | 831 | break; |
| 823 | 832 | case MODULE_STATE_COMING: |
| 824 | − kunit_module_init(mod); | |
| 825 | 833 | break; |
| 826 | 834 | case MODULE_STATE_UNFORMED: |
| 827 | 835 | break; |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | |
| 15 | 15 | #define pr_fmt(fmt) "stackdepot: " fmt |
| 16 | 16 | |
| 17 | +#include <linux/debugfs.h> | |
| 17 | 18 | #include <linux/gfp.h> |
| 18 | 19 | #include <linux/jhash.h> |
| 19 | 20 | #include <linux/kernel.h> |
| @@ -21,8 +22,9 @@ · 1 unmodified line | ||
| 21 | 22 | #include <linux/list.h> |
| 22 | 23 | #include <linux/mm.h> |
| 23 | 24 | #include <linux/mutex.h> |
| 24 | −#include <linux/percpu.h> | |
| 25 | 25 | #include <linux/printk.h> |
| 26 | +#include <linux/rculist.h> | |
| 27 | +#include <linux/rcupdate.h> | |
| 26 | 28 | #include <linux/refcount.h> |
| 27 | 29 | #include <linux/slab.h> |
| 28 | 30 | #include <linux/spinlock.h> |
| @@ -67,12 +69,28 @@ union handle_parts { · 38 unmodified lines | ||
| 67 | 69 | }; |
| 68 | 70 | |
| 69 | 71 | struct stack_record { |
| 70 | − struct list_head list; /* Links in hash table or freelist */ | |
| 72 | + struct list_head hash_list; /* Links in the hash table */ | |
| 71 | 73 | u32 hash; /* Hash in hash table */ |
| 72 | 74 | u32 size; /* Number of stored frames */ |
| 73 | − union handle_parts handle; | |
| 75 | + union handle_parts handle; /* Constant after initialization */ | |
| 74 | 76 | refcount_t count; |
| 75 | − unsigned long entries[CONFIG_STACKDEPOT_MAX_FRAMES]; /* Frames */ | |
| 77 | + union { | |
| 78 | + unsigned long entries[CONFIG_STACKDEPOT_MAX_FRAMES]; /* Frames */ | |
| 79 | + struct { | |
| 80 | + /* | |
| 81 | + * An important invariant of the implementation is to | |
| 82 | + * only place a stack record onto the freelist iff its | |
| 83 | + * refcount is zero. Because stack records with a zero | |
| 84 | + * refcount are never considered as valid, it is safe to | |
| 85 | + * union @entries and freelist management state below. | |
| 86 | + * Conversely, as soon as an entry is off the freelist | |
| 87 | + * and its refcount becomes non-zero, the below must not | |
| 88 | + * be accessed until being placed back on the freelist. | |
| 89 | + */ | |
| 90 | + struct list_head free_list; /* Links in the freelist */ | |
| 91 | + unsigned long rcu_state; /* RCU cookie */ | |
| 92 | + }; | |
| 93 | + }; | |
| 76 | 94 | }; |
| 77 | 95 | |
| 78 | 96 | #define DEPOT_STACK_RECORD_SIZE \ |
| @@ -112,8 +130,25 @@ static LIST_HEAD(free_stacks); · 33 unmodified lines | ||
| 112 | 130 | * yet allocated or if the limit on the number of pools is reached. |
| 113 | 131 | */ |
| 114 | 132 | static bool new_pool_required = true; |
| 115 | −/* Lock that protects the variables above. */ | |
| 116 | −static DEFINE_RWLOCK(pool_rwlock); | |
| 133 | +/* The lock must be held when performing pool or freelist modifications. */ | |
| 134 | +static DEFINE_RAW_SPINLOCK(pool_lock); | |
| 135 | + | |
| 136 | +/* Statistics counters for debugfs. */ | |
| 137 | +enum depot_counter_id { | |
| 138 | + DEPOT_COUNTER_ALLOCS, | |
| 139 | + DEPOT_COUNTER_FREES, | |
| 140 | + DEPOT_COUNTER_INUSE, | |
| 141 | + DEPOT_COUNTER_FREELIST_SIZE, | |
| 142 | + DEPOT_COUNTER_COUNT, | |
| 143 | +}; | |
| 144 | +static long counters[DEPOT_COUNTER_COUNT]; | |
| 145 | +static const char *const counter_names[] = { | |
| 146 | + [DEPOT_COUNTER_ALLOCS] = "allocations", | |
| 147 | + [DEPOT_COUNTER_FREES] = "frees", | |
| 148 | + [DEPOT_COUNTER_INUSE] = "in_use", | |
| 149 | + [DEPOT_COUNTER_FREELIST_SIZE] = "freelist_size", | |
| 150 | +}; | |
| 151 | +static_assert(ARRAY_SIZE(counter_names) == DEPOT_COUNTER_COUNT); | |
| 117 | 152 | |
| 118 | 153 | static int __init disable_stack_depot(char *str) |
| 119 | 154 | { |
| @@ -258,14 +293,15 @@ out_unlock: · 138 unmodified lines | ||
| 258 | 293 | } |
| 259 | 294 | EXPORT_SYMBOL_GPL(stack_depot_init); |
| 260 | 295 | |
| 261 | −/* Initializes a stack depol pool. */ | |
| 296 | +/* | |
| 297 | + * Initializes new stack depot @pool, release all its entries to the freelist, | |
| 298 | + * and update the list of pools. | |
| 299 | + */ | |
| 262 | 300 | static void depot_init_pool(void *pool) |
| 263 | 301 | { |
| 264 | 302 | int offset; |
| 265 | 303 | |
| 266 | − lockdep_assert_held_write(&pool_rwlock); | |
| 267 | − | |
| 268 | − WARN_ON(!list_empty(&free_stacks)); | |
| 304 | + lockdep_assert_held(&pool_lock); | |
| 269 | 305 | |
| 270 | 306 | /* Initialize handles and link stack records into the freelist. */ |
| 271 | 307 | for (offset = 0; offset <= DEPOT_POOL_SIZE - DEPOT_STACK_RECORD_SIZE; |
| @@ -276,18 +312,36 @@ static void depot_init_pool(void *pool) · 4 unmodified lines | ||
| 276 | 312 | stack->handle.offset = offset >> DEPOT_STACK_ALIGN; |
| 277 | 313 | stack->handle.extra = 0; |
| 278 | 314 | |
| 279 | − list_add(&stack->list, &free_stacks); | |
| 315 | + /* | |
| 316 | + * Stack traces of size 0 are never saved, and we can simply use | |
| 317 | + * the size field as an indicator if this is a new unused stack | |
| 318 | + * record in the freelist. | |
| 319 | + */ | |
| 320 | + stack->size = 0; | |
| 321 | + | |
| 322 | + INIT_LIST_HEAD(&stack->hash_list); | |
| 323 | + /* | |
| 324 | + * Add to the freelist front to prioritize never-used entries: | |
| 325 | + * required in case there are entries in the freelist, but their | |
| 326 | + * RCU cookie still belongs to the current RCU grace period | |
| 327 | + * (there can still be concurrent readers). | |
| 328 | + */ | |
| 329 | + list_add(&stack->free_list, &free_stacks); | |
| 330 | + counters[DEPOT_COUNTER_FREELIST_SIZE]++; | |
| 280 | 331 | } |
| 281 | 332 | |
| 282 | 333 | /* Save reference to the pool to be used by depot_fetch_stack(). */ |
| 283 | 334 | stack_pools[pools_num] = pool; |
| 284 | − pools_num++; | |
| 335 | + | |
| 336 | + /* Pairs with concurrent READ_ONCE() in depot_fetch_stack(). */ | |
| 337 | + WRITE_ONCE(pools_num, pools_num + 1); | |
| 338 | + ASSERT_EXCLUSIVE_WRITER(pools_num); | |
| 285 | 339 | } |
| 286 | 340 | |
| 287 | 341 | /* Keeps the preallocated memory to be used for a new stack depot pool. */ |
| 288 | 342 | static void depot_keep_new_pool(void **prealloc) |
| 289 | 343 | { |
| 290 | − lockdep_assert_held_write(&pool_rwlock); | |
| 344 | + lockdep_assert_held(&pool_lock); | |
| 291 | 345 | |
| 292 | 346 | /* |
| 293 | 347 | * If a new pool is already saved or the maximum number of |
| @@ -310,17 +364,16 @@ static void depot_keep_new_pool(void **prealloc) · 16 unmodified lines | ||
| 310 | 364 | * number of pools is reached. In either case, take note that |
| 311 | 365 | * keeping another pool is not required. |
| 312 | 366 | */ |
| 313 | − new_pool_required = false; | |
| 367 | + WRITE_ONCE(new_pool_required, false); | |
| 314 | 368 | } |
| 315 | 369 | |
| 316 | −/* Updates references to the current and the next stack depot pools. */ | |
| 317 | −static bool depot_update_pools(void **prealloc) | |
| 370 | +/* | |
| 371 | + * Try to initialize a new stack depot pool from either a previous or the | |
| 372 | + * current pre-allocation, and release all its entries to the freelist. | |
| 373 | + */ | |
| 374 | +static bool depot_try_init_pool(void **prealloc) | |
| 318 | 375 | { |
| 319 | − lockdep_assert_held_write(&pool_rwlock); | |
| 320 | − | |
| 321 | − /* Check if we still have objects in the freelist. */ | |
| 322 | − if (!list_empty(&free_stacks)) | |
| 323 | − goto out_keep_prealloc; | |
| 376 | + lockdep_assert_held(&pool_lock); | |
| 324 | 377 | |
| 325 | 378 | /* Check if we have a new pool saved and use it. */ |
| 326 | 379 | if (new_pool) { |
| @@ -329,10 +382,9 @@ static bool depot_update_pools(void **prealloc) · 2 unmodified lines | ||
| 329 | 382 | |
| 330 | 383 | /* Take note that we might need a new new_pool. */ |
| 331 | 384 | if (pools_num < DEPOT_MAX_POOLS) |
| 332 | − new_pool_required = true; | |
| 385 | + WRITE_ONCE(new_pool_required, true); | |
| 333 | 386 | |
| 334 | − /* Try keeping the preallocated memory for new_pool. */ | |
| 335 | − goto out_keep_prealloc; | |
| 387 | + return true; | |
| 336 | 388 | } |
| 337 | 389 | |
| 338 | 390 | /* Bail out if we reached the pool limit. */ |
| @@ -349,12 +401,32 @@ static bool depot_update_pools(void **prealloc) · 10 unmodified lines | ||
| 349 | 401 | } |
| 350 | 402 | |
| 351 | 403 | return false; |
| 404 | +} | |
| 405 | + | |
| 406 | +/* Try to find next free usable entry. */ | |
| 407 | +static struct stack_record *depot_pop_free(void) | |
| 408 | +{ | |
| 409 | + struct stack_record *stack; | |
| 410 | + | |
| 411 | + lockdep_assert_held(&pool_lock); | |
| 412 | + | |
| 413 | + if (list_empty(&free_stacks)) | |
| 414 | + return NULL; | |
| 415 | + | |
| 416 | + /* | |
| 417 | + * We maintain the invariant that the elements in front are least | |
| 418 | + * recently used, and are therefore more likely to be associated with an | |
| 419 | + * RCU grace period in the past. Consequently it is sufficient to only | |
| 420 | + * check the first entry. | |
| 421 | + */ | |
| 422 | + stack = list_first_entry(&free_stacks, struct stack_record, free_list); | |
| 423 | + if (stack->size && !poll_state_synchronize_rcu(stack->rcu_state)) | |
| 424 | + return NULL; | |
| 425 | + | |
| 426 | + list_del(&stack->free_list); | |
| 427 | + counters[DEPOT_COUNTER_FREELIST_SIZE]--; | |
| 352 | 428 | |
| 353 | −out_keep_prealloc: | |
| 354 | − /* Keep the preallocated memory for a new pool if required. */ | |
| 355 | − if (*prealloc) | |
| 356 | − depot_keep_new_pool(prealloc); | |
| 357 | − return true; | |
| 429 | + return stack; | |
| 358 | 430 | } |
| 359 | 431 | |
| 360 | 432 | /* Allocates a new stack in a stack depot pool. */ |
| @@ -363,19 +435,22 @@ depot_alloc_stack(unsigned long *entries, int size, u32 hash, void **prealloc) · 2 unmodified lines | ||
| 363 | 435 | { |
| 364 | 436 | struct stack_record *stack; |
| 365 | 437 | |
| 366 | − lockdep_assert_held_write(&pool_rwlock); | |
| 438 | + lockdep_assert_held(&pool_lock); | |
| 367 | 439 | |
| 368 | − /* Update current and new pools if required and possible. */ | |
| 369 | − if (!depot_update_pools(prealloc)) | |
| 440 | + /* This should already be checked by public API entry points. */ | |
| 441 | + if (WARN_ON_ONCE(!size)) | |
| 370 | 442 | return NULL; |
| 371 | 443 | |
| 372 | 444 | /* Check if we have a stack record to save the stack trace. */ |
| 373 | − if (list_empty(&free_stacks)) | |
| 374 | − return NULL; | |
| 375 | − | |
| 376 | − /* Get and unlink the first entry from the freelist. */ | |
| 377 | − stack = list_first_entry(&free_stacks, struct stack_record, list); | |
| 378 | − list_del(&stack->list); | |
| 445 | + stack = depot_pop_free(); | |
| 446 | + if (!stack) { | |
| 447 | + /* No usable entries on the freelist - try to refill the freelist. */ | |
| 448 | + if (!depot_try_init_pool(prealloc)) | |
| 449 | + return NULL; | |
| 450 | + stack = depot_pop_free(); | |
| 451 | + if (WARN_ON(!stack)) | |
| 452 | + return NULL; | |
| 453 | + } | |
| 379 | 454 | |
| 380 | 455 | /* Limit number of saved frames to CONFIG_STACKDEPOT_MAX_FRAMES. */ |
| 381 | 456 | if (size > CONFIG_STACKDEPOT_MAX_FRAMES) |
| @@ -394,38 +469,80 @@ depot_alloc_stack(unsigned long *entries, int size, u32 hash, void **prealloc) · 12 unmodified lines | ||
| 394 | 469 | */ |
| 395 | 470 | kmsan_unpoison_memory(stack, DEPOT_STACK_RECORD_SIZE); |
| 396 | 471 | |
| 472 | + counters[DEPOT_COUNTER_ALLOCS]++; | |
| 473 | + counters[DEPOT_COUNTER_INUSE]++; | |
| 397 | 474 | return stack; |
| 398 | 475 | } |
| 399 | 476 | |
| 400 | 477 | static struct stack_record *depot_fetch_stack(depot_stack_handle_t handle) |
| 401 | 478 | { |
| 479 | + const int pools_num_cached = READ_ONCE(pools_num); | |
| 402 | 480 | union handle_parts parts = { .handle = handle }; |
| 403 | 481 | void *pool; |
| 404 | 482 | size_t offset = parts.offset << DEPOT_STACK_ALIGN; |
| 405 | 483 | struct stack_record *stack; |
| 406 | 484 | |
| 407 | − lockdep_assert_held(&pool_rwlock); | |
| 485 | + lockdep_assert_not_held(&pool_lock); | |
| 408 | 486 | |
| 409 | − if (parts.pool_index > pools_num) { | |
| 487 | + if (parts.pool_index > pools_num_cached) { | |
| 410 | 488 | WARN(1, "pool index %d out of bounds (%d) for stack id %08x\n", |
| 411 | − parts.pool_index, pools_num, handle); | |
| 489 | + parts.pool_index, pools_num_cached, handle); | |
| 412 | 490 | return NULL; |
| 413 | 491 | } |
| 414 | 492 | |
| 415 | 493 | pool = stack_pools[parts.pool_index]; |
| 416 | − if (!pool) | |
| 494 | + if (WARN_ON(!pool)) | |
| 417 | 495 | return NULL; |
| 418 | 496 | |
| 419 | 497 | stack = pool + offset; |
| 498 | + if (WARN_ON(!refcount_read(&stack->count))) | |
| 499 | + return NULL; | |
| 500 | + | |
| 420 | 501 | return stack; |
| 421 | 502 | } |
| 422 | 503 | |
| 423 | 504 | /* Links stack into the freelist. */ |
| 424 | 505 | static void depot_free_stack(struct stack_record *stack) |
| 425 | 506 | { |
| 426 | − lockdep_assert_held_write(&pool_rwlock); | |
| 507 | + unsigned long flags; | |
| 508 | + | |
| 509 | + lockdep_assert_not_held(&pool_lock); | |
| 427 | 510 | |
| 428 | − list_add(&stack->list, &free_stacks); | |
| 511 | + raw_spin_lock_irqsave(&pool_lock, flags); | |
| 512 | + printk_deferred_enter(); | |
| 513 | + | |
| 514 | + /* | |
| 515 | + * Remove the entry from the hash list. Concurrent list traversal may | |
| 516 | + * still observe the entry, but since the refcount is zero, this entry | |
| 517 | + * will no longer be considered as valid. | |
| 518 | + */ | |
| 519 | + list_del_rcu(&stack->hash_list); | |
| 520 | + | |
| 521 | + /* | |
| 522 | + * Due to being used from constrained contexts such as the allocators, | |
| 523 | + * NMI, or even RCU itself, stack depot cannot rely on primitives that | |
| 524 | + * would sleep (such as synchronize_rcu()) or recursively call into | |
| 525 | + * stack depot again (such as call_rcu()). | |
| 526 | + * | |
| 527 | + * Instead, get an RCU cookie, so that we can ensure this entry isn't | |
| 528 | + * moved onto another list until the next grace period, and concurrent | |
| 529 | + * RCU list traversal remains safe. | |
| 530 | + */ | |
| 531 | + stack->rcu_state = get_state_synchronize_rcu(); | |
| 532 | + | |
| 533 | + /* | |
| 534 | + * Add the entry to the freelist tail, so that older entries are | |
| 535 | + * considered first - their RCU cookie is more likely to no longer be | |
| 536 | + * associated with the current grace period. | |
| 537 | + */ | |
| 538 | + list_add_tail(&stack->free_list, &free_stacks); | |
| 539 | + | |
| 540 | + counters[DEPOT_COUNTER_FREELIST_SIZE]++; | |
| 541 | + counters[DEPOT_COUNTER_FREES]++; | |
| 542 | + counters[DEPOT_COUNTER_INUSE]--; | |
| 543 | + | |
| 544 | + printk_deferred_exit(); | |
| 545 | + raw_spin_unlock_irqrestore(&pool_lock, flags); | |
| 429 | 546 | } |
| 430 | 547 | |
| 431 | 548 | /* Calculates the hash for a stack. */ |
| @@ -453,22 +570,52 @@ int stackdepot_memcmp(const unsigned long *u1, const unsigned long *u2, · 21 unmodified lines | ||
| 453 | 570 | |
| 454 | 571 | /* Finds a stack in a bucket of the hash table. */ |
| 455 | 572 | static inline struct stack_record *find_stack(struct list_head *bucket, |
| 456 | − unsigned long *entries, int size, | |
| 457 | − u32 hash) | |
| 573 | + unsigned long *entries, int size, | |
| 574 | + u32 hash, depot_flags_t flags) | |
| 458 | 575 | { |
| 459 | − struct list_head *pos; | |
| 460 | − struct stack_record *found; | |
| 576 | + struct stack_record *stack, *ret = NULL; | |
| 577 | + | |
| 578 | + /* | |
| 579 | + * Stack depot may be used from instrumentation that instruments RCU or | |
| 580 | + * tracing itself; use variant that does not call into RCU and cannot be | |
| 581 | + * traced. | |
| 582 | + * | |
| 583 | + * Note: Such use cases must take care when using refcounting to evict | |
| 584 | + * unused entries, because the stack record free-then-reuse code paths | |
| 585 | + * do call into RCU. | |
| 586 | + */ | |
| 587 | + rcu_read_lock_sched_notrace(); | |
| 461 | 588 | |
| 462 | − lockdep_assert_held(&pool_rwlock); | |
| 589 | + list_for_each_entry_rcu(stack, bucket, hash_list) { | |
| 590 | + if (stack->hash != hash || stack->size != size) | |
| 591 | + continue; | |
| 592 | + | |
| 593 | + /* | |
| 594 | + * This may race with depot_free_stack() accessing the freelist | |
| 595 | + * management state unioned with @entries. The refcount is zero | |
| 596 | + * in that case and the below refcount_inc_not_zero() will fail. | |
| 597 | + */ | |
| 598 | + if (data_race(stackdepot_memcmp(entries, stack->entries, size))) | |
| 599 | + continue; | |
| 600 | + | |
| 601 | + /* | |
| 602 | + * Try to increment refcount. If this succeeds, the stack record | |
| 603 | + * is valid and has not yet been freed. | |
| 604 | + * | |
| 605 | + * If STACK_DEPOT_FLAG_GET is not used, it is undefined behavior | |
| 606 | + * to then call stack_depot_put() later, and we can assume that | |
| 607 | + * a stack record is never placed back on the freelist. | |
| 608 | + */ | |
| 609 | + if ((flags & STACK_DEPOT_FLAG_GET) && !refcount_inc_not_zero(&stack->count)) | |
| 610 | + continue; | |
| 463 | 611 | |
| 464 | − list_for_each(pos, bucket) { | |
| 465 | − found = list_entry(pos, struct stack_record, list); | |
| 466 | − if (found->hash == hash && | |
| 467 | − found->size == size && | |
| 468 | − !stackdepot_memcmp(entries, found->entries, size)) | |
| 469 | − return found; | |
| 612 | + ret = stack; | |
| 613 | + break; | |
| 470 | 614 | } |
| 471 | − return NULL; | |
| 615 | + | |
| 616 | + rcu_read_unlock_sched_notrace(); | |
| 617 | + | |
| 618 | + return ret; | |
| 472 | 619 | } |
| 473 | 620 | |
| 474 | 621 | depot_stack_handle_t stack_depot_save_flags(unsigned long *entries, |
| @@ -482,7 +629,6 @@ depot_stack_handle_t stack_depot_save_flags(unsigned long *entries, · 7 unmodified lines | ||
| 482 | 629 | struct page *page = NULL; |
| 483 | 630 | void *prealloc = NULL; |
| 484 | 631 | bool can_alloc = depot_flags & STACK_DEPOT_FLAG_CAN_ALLOC; |
| 485 | − bool need_alloc = false; | |
| 486 | 632 | unsigned long flags; |
| 487 | 633 | u32 hash; |
| 488 | 634 | |
| @@ -505,31 +651,16 @@ depot_stack_handle_t stack_depot_save_flags(unsigned long *entries, · 16 unmodified lines | ||
| 505 | 651 | hash = hash_stack(entries, nr_entries); |
| 506 | 652 | bucket = &stack_table[hash & stack_hash_mask]; |
| 507 | 653 | |
| 508 | − read_lock_irqsave(&pool_rwlock, flags); | |
| 509 | − printk_deferred_enter(); | |
| 510 | − | |
| 511 | − /* Fast path: look the stack trace up without full locking. */ | |
| 512 | − found = find_stack(bucket, entries, nr_entries, hash); | |
| 513 | − if (found) { | |
| 514 | − if (depot_flags & STACK_DEPOT_FLAG_GET) | |
| 515 | − refcount_inc(&found->count); | |
| 516 | − printk_deferred_exit(); | |
| 517 | − read_unlock_irqrestore(&pool_rwlock, flags); | |
| 654 | + /* Fast path: look the stack trace up without locking. */ | |
| 655 | + found = find_stack(bucket, entries, nr_entries, hash, depot_flags); | |
| 656 | + if (found) | |
| 518 | 657 | goto exit; |
| 519 | − } | |
| 520 | − | |
| 521 | − /* Take note if another stack pool needs to be allocated. */ | |
| 522 | − if (new_pool_required) | |
| 523 | − need_alloc = true; | |
| 524 | − | |
| 525 | − printk_deferred_exit(); | |
| 526 | − read_unlock_irqrestore(&pool_rwlock, flags); | |
| 527 | 658 | |
| 528 | 659 | /* |
| 529 | 660 | * Allocate memory for a new pool if required now: |
| 530 | 661 | * we won't be able to do that under the lock. |
| 531 | 662 | */ |
| 532 | − if (unlikely(can_alloc && need_alloc)) { | |
| 663 | + if (unlikely(can_alloc && READ_ONCE(new_pool_required))) { | |
| 533 | 664 | /* |
| 534 | 665 | * Zero out zone modifiers, as we don't have specific zone |
| 535 | 666 | * requirements. Keep the flags related to allocation in atomic |
| @@ -543,31 +674,36 @@ depot_stack_handle_t stack_depot_save_flags(unsigned long *entries, · 7 unmodified lines | ||
| 543 | 674 | prealloc = page_address(page); |
| 544 | 675 | } |
| 545 | 676 | |
| 546 | − write_lock_irqsave(&pool_rwlock, flags); | |
| 677 | + raw_spin_lock_irqsave(&pool_lock, flags); | |
| 547 | 678 | printk_deferred_enter(); |
| 548 | 679 | |
| 549 | − found = find_stack(bucket, entries, nr_entries, hash); | |
| 680 | + /* Try to find again, to avoid concurrently inserting duplicates. */ | |
| 681 | + found = find_stack(bucket, entries, nr_entries, hash, depot_flags); | |
| 550 | 682 | if (!found) { |
| 551 | 683 | struct stack_record *new = |
| 552 | 684 | depot_alloc_stack(entries, nr_entries, hash, &prealloc); |
| 553 | 685 | |
| 554 | 686 | if (new) { |
| 555 | − list_add(&new->list, bucket); | |
| 687 | + /* | |
| 688 | + * This releases the stack record into the bucket and | |
| 689 | + * makes it visible to readers in find_stack(). | |
| 690 | + */ | |
| 691 | + list_add_rcu(&new->hash_list, bucket); | |
| 556 | 692 | found = new; |
| 557 | 693 | } |
| 558 | − } else { | |
| 559 | − if (depot_flags & STACK_DEPOT_FLAG_GET) | |
| 560 | − refcount_inc(&found->count); | |
| 694 | + } | |
| 695 | + | |
| 696 | + if (prealloc) { | |
| 561 | 697 | /* |
| 562 | − * Stack depot already contains this stack trace, but let's | |
| 563 | − * keep the preallocated memory for future. | |
| 698 | + * Either stack depot already contains this stack trace, or | |
| 699 | + * depot_alloc_stack() did not consume the preallocated memory. | |
| 700 | + * Try to keep the preallocated memory for future. | |
| 564 | 701 | */ |
| 565 | − if (prealloc) | |
| 566 | − depot_keep_new_pool(&prealloc); | |
| 702 | + depot_keep_new_pool(&prealloc); | |
| 567 | 703 | } |
| 568 | 704 | |
| 569 | 705 | printk_deferred_exit(); |
| 570 | − write_unlock_irqrestore(&pool_rwlock, flags); | |
| 706 | + raw_spin_unlock_irqrestore(&pool_lock, flags); | |
| 571 | 707 | exit: |
| 572 | 708 | if (prealloc) { |
| 573 | 709 | /* Stack depot didn't use this memory, free it. */ |
| @@ -592,7 +728,6 @@ unsigned int stack_depot_fetch(depot_stack_handle_t handle, · 18 unmodified lines | ||
| 592 | 728 | unsigned long **entries) |
| 593 | 729 | { |
| 594 | 730 | struct stack_record *stack; |
| 595 | − unsigned long flags; | |
| 596 | 731 | |
| 597 | 732 | *entries = NULL; |
| 598 | 733 | /* |
| @@ -604,13 +739,13 @@ unsigned int stack_depot_fetch(depot_stack_handle_t handle, · 5 unmodified lines | ||
| 604 | 739 | if (!handle || stack_depot_disabled) |
| 605 | 740 | return 0; |
| 606 | 741 | |
| 607 | − read_lock_irqsave(&pool_rwlock, flags); | |
| 608 | − printk_deferred_enter(); | |
| 609 | − | |
| 610 | 742 | stack = depot_fetch_stack(handle); |
| 611 | − | |
| 612 | − printk_deferred_exit(); | |
| 613 | − read_unlock_irqrestore(&pool_rwlock, flags); | |
| 743 | + /* | |
| 744 | + * Should never be NULL, otherwise this is a use-after-put (or just a | |
| 745 | + * corrupt handle). | |
| 746 | + */ | |
| 747 | + if (WARN(!stack, "corrupt handle or use after stack_depot_put()")) | |
| 748 | + return 0; | |
| 614 | 749 | |
| 615 | 750 | *entries = stack->entries; |
| 616 | 751 | return stack->size; |
| @@ -620,29 +755,20 @@ EXPORT_SYMBOL_GPL(stack_depot_fetch); · 3 unmodified lines | ||
| 620 | 755 | void stack_depot_put(depot_stack_handle_t handle) |
| 621 | 756 | { |
| 622 | 757 | struct stack_record *stack; |
| 623 | − unsigned long flags; | |
| 624 | 758 | |
| 625 | 759 | if (!handle || stack_depot_disabled) |
| 626 | 760 | return; |
| 627 | 761 | |
| 628 | − write_lock_irqsave(&pool_rwlock, flags); | |
| 629 | − printk_deferred_enter(); | |
| 630 | − | |
| 631 | 762 | stack = depot_fetch_stack(handle); |
| 632 | − if (WARN_ON(!stack)) | |
| 633 | − goto out; | |
| 634 | − | |
| 635 | − if (refcount_dec_and_test(&stack->count)) { | |
| 636 | − /* Unlink stack from the hash table. */ | |
| 637 | − list_del(&stack->list); | |
| 763 | + /* | |
| 764 | + * Should always be able to find the stack record, otherwise this is an | |
| 765 | + * unbalanced put attempt (or corrupt handle). | |
| 766 | + */ | |
| 767 | + if (WARN(!stack, "corrupt handle or unbalanced stack_depot_put()")) | |
| 768 | + return; | |
| 638 | 769 | |
| 639 | − /* Free stack. */ | |
| 770 | + if (refcount_dec_and_test(&stack->count)) | |
| 640 | 771 | depot_free_stack(stack); |
| 641 | − } | |
| 642 | − | |
| 643 | −out: | |
| 644 | − printk_deferred_exit(); | |
| 645 | − write_unlock_irqrestore(&pool_rwlock, flags); | |
| 646 | 772 | } |
| 647 | 773 | EXPORT_SYMBOL_GPL(stack_depot_put); |
| 648 | 774 | |
| @@ -690,3 +816,30 @@ unsigned int stack_depot_get_extra_bits(depot_stack_handle_t handle) · 41 unmodified lines | ||
| 690 | 816 | return parts.extra; |
| 691 | 817 | } |
| 692 | 818 | EXPORT_SYMBOL(stack_depot_get_extra_bits); |
| 819 | + | |
| 820 | +static int stats_show(struct seq_file *seq, void *v) | |
| 821 | +{ | |
| 822 | + /* | |
| 823 | + * data race ok: These are just statistics counters, and approximate | |
| 824 | + * statistics are ok for debugging. | |
| 825 | + */ | |
| 826 | + seq_printf(seq, "pools: %d\n", data_race(pools_num)); | |
| 827 | + for (int i = 0; i < DEPOT_COUNTER_COUNT; i++) | |
| 828 | + seq_printf(seq, "%s: %ld\n", counter_names[i], data_race(counters[i])); | |
| 829 | + | |
| 830 | + return 0; | |
| 831 | +} | |
| 832 | +DEFINE_SHOW_ATTRIBUTE(stats); | |
| 833 | + | |
| 834 | +static int depot_debugfs_init(void) | |
| 835 | +{ | |
| 836 | + struct dentry *dir; | |
| 837 | + | |
| 838 | + if (stack_depot_disabled) | |
| 839 | + return 0; | |
| 840 | + | |
| 841 | + dir = debugfs_create_dir("stackdepot", NULL); | |
| 842 | + debugfs_create_file("stats", 0444, dir, NULL, &stats_fops); | |
| 843 | + return 0; | |
| 844 | +} | |
| 845 | +late_initcall(depot_debugfs_init); | |
| @@ -37,6 +37,7 @@ · 36 unmodified lines | ||
| 37 | 37 | #include <linux/page_owner.h> |
| 38 | 38 | #include <linux/sched/sysctl.h> |
| 39 | 39 | #include <linux/memory-tiers.h> |
| 40 | +#include <linux/compat.h> | |
| 40 | 41 | |
| 41 | 42 | #include <asm/tlb.h> |
| 42 | 43 | #include <asm/pgalloc.h> |
| @@ -809,7 +810,10 @@ static unsigned long __thp_get_unmapped_area(struct file *filp, · 766 unmodified lines | ||
| 809 | 810 | { |
| 810 | 811 | loff_t off_end = off + len; |
| 811 | 812 | loff_t off_align = round_up(off, size); |
| 812 | − unsigned long len_pad, ret; | |
| 813 | + unsigned long len_pad, ret, off_sub; | |
| 814 | + | |
| 815 | + if (IS_ENABLED(CONFIG_32BIT) || in_compat_syscall()) | |
| 816 | + return 0; | |
| 813 | 817 | |
| 814 | 818 | if (off_end <= off_align || (off_end - off_align) < size) |
| 815 | 819 | return 0; |
| @@ -835,7 +839,13 @@ static unsigned long __thp_get_unmapped_area(struct file *filp, · 19 unmodified lines | ||
| 835 | 839 | if (ret == addr) |
| 836 | 840 | return addr; |
| 837 | 841 | |
| 838 | − ret += (off - ret) & (size - 1); | |
| 842 | + off_sub = (off - ret) & (size - 1); | |
| 843 | + | |
| 844 | + if (current->mm->get_unmapped_area == arch_get_unmapped_area_topdown && | |
| 845 | + !off_sub) | |
| 846 | + return ret + size; | |
| 847 | + | |
| 848 | + ret += off_sub; | |
| 839 | 849 | return ret; |
| 840 | 850 | } |
| 841 | 851 | |
| @@ -2437,7 +2447,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, · 1595 unmodified lines | ||
| 2437 | 2447 | page = pmd_page(old_pmd); |
| 2438 | 2448 | folio = page_folio(page); |
| 2439 | 2449 | if (!folio_test_dirty(folio) && pmd_dirty(old_pmd)) |
| 2440 | − folio_set_dirty(folio); | |
| 2450 | + folio_mark_dirty(folio); | |
| 2441 | 2451 | if (!folio_test_referenced(folio) && pmd_young(old_pmd)) |
| 2442 | 2452 | folio_set_referenced(folio); |
| 2443 | 2453 | folio_remove_rmap_pmd(folio, page, vma); |
| @@ -3563,7 +3573,7 @@ int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw, · 1119 unmodified lines | ||
| 3563 | 3573 | } |
| 3564 | 3574 | |
| 3565 | 3575 | if (pmd_dirty(pmdval)) |
| 3566 | − folio_set_dirty(folio); | |
| 3576 | + folio_mark_dirty(folio); | |
| 3567 | 3577 | if (pmd_write(pmdval)) |
| 3568 | 3578 | entry = make_writable_migration_entry(page_to_pfn(page)); |
| 3569 | 3579 | else if (anon_exclusive) |
| @@ -2176,6 +2176,9 @@ static void __init memmap_init_reserved_pages(void) · 2175 unmodified lines | ||
| 2176 | 2176 | start = region->base; |
| 2177 | 2177 | end = start + region->size; |
| 2178 | 2178 | |
| 2179 | + if (nid == NUMA_NO_NODE || nid >= MAX_NUMNODES) | |
| 2180 | + nid = early_pfn_to_nid(PFN_DOWN(start)); | |
| 2181 | + | |
| 2179 | 2182 | reserve_bootmem_region(start, end, nid); |
| 2180 | 2183 | } |
| 2181 | 2184 | } |
| @@ -2623,8 +2623,9 @@ static unsigned long calculate_high_delay(struct mem_cgroup *memcg, · 2622 unmodified lines | ||
| 2623 | 2623 | } |
| 2624 | 2624 | |
| 2625 | 2625 | /* |
| 2626 | − * Scheduled by try_charge() to be executed from the userland return path | |
| 2627 | − * and reclaims memory over the high limit. | |
| 2626 | + * Reclaims memory over the high limit. Called directly from | |
| 2627 | + * try_charge() (context permitting), as well as from the userland | |
| 2628 | + * return path where reclaim is always able to block. | |
| 2628 | 2629 | */ |
| 2629 | 2630 | void mem_cgroup_handle_over_high(gfp_t gfp_mask) |
| 2630 | 2631 | { |
| @@ -2643,6 +2644,17 @@ void mem_cgroup_handle_over_high(gfp_t gfp_mask) · 12 unmodified lines | ||
| 2643 | 2644 | current->memcg_nr_pages_over_high = 0; |
| 2644 | 2645 | |
| 2645 | 2646 | retry_reclaim: |
| 2647 | + /* | |
| 2648 | + * Bail if the task is already exiting. Unlike memory.max, | |
| 2649 | + * memory.high enforcement isn't as strict, and there is no | |
| 2650 | + * OOM killer involved, which means the excess could already | |
| 2651 | + * be much bigger (and still growing) than it could for | |
| 2652 | + * memory.max; the dying task could get stuck in fruitless | |
| 2653 | + * reclaim for a long time, which isn't desirable. | |
| 2654 | + */ | |
| 2655 | + if (task_is_dying()) | |
| 2656 | + goto out; | |
| 2657 | + | |
| 2646 | 2658 | /* |
| 2647 | 2659 | * The allocating task should reclaim at least the batch size, but for |
| 2648 | 2660 | * subsequent retries we only want to do what's necessary to prevent oom |
| @@ -2693,6 +2705,9 @@ retry_reclaim: · 44 unmodified lines | ||
| 2693 | 2705 | } |
| 2694 | 2706 | |
| 2695 | 2707 | /* |
| 2708 | + * Reclaim didn't manage to push usage below the limit, slow | |
| 2709 | + * this allocating task down. | |
| 2710 | + * | |
| 2696 | 2711 | * If we exit early, we're guaranteed to die (since |
| 2697 | 2712 | * schedule_timeout_killable sets TASK_KILLABLE). This means we don't |
| 2698 | 2713 | * need to account for any ill-begotten jiffies to pay them off later. |
| @@ -2887,11 +2902,17 @@ done_restock: · 188 unmodified lines | ||
| 2887 | 2902 | } |
| 2888 | 2903 | } while ((memcg = parent_mem_cgroup(memcg))); |
| 2889 | 2904 | |
| 2905 | + /* | |
| 2906 | + * Reclaim is set up above to be called from the userland | |
| 2907 | + * return path. But also attempt synchronous reclaim to avoid | |
| 2908 | + * excessive overrun while the task is still inside the | |
| 2909 | + * kernel. If this is successful, the return path will see it | |
| 2910 | + * when it rechecks the overage and simply bail out. | |
| 2911 | + */ | |
| 2890 | 2912 | if (current->memcg_nr_pages_over_high > MEMCG_CHARGE_BATCH && |
| 2891 | 2913 | !(current->flags & PF_MEMALLOC) && |
| 2892 | − gfpflags_allow_blocking(gfp_mask)) { | |
| 2914 | + gfpflags_allow_blocking(gfp_mask)) | |
| 2893 | 2915 | mem_cgroup_handle_over_high(gfp_mask); |
| 2894 | − } | |
| 2895 | 2916 | return 0; |
| 2896 | 2917 | } |
| 2897 | 2918 | |
| @@ -982,7 +982,7 @@ static bool has_extra_refcount(struct page_state *ps, struct page *p, · 981 unmodified lines | ||
| 982 | 982 | int count = page_count(p) - 1; |
| 983 | 983 | |
| 984 | 984 | if (extra_pins) |
| 985 | − count -= 1; | |
| 985 | + count -= folio_nr_pages(page_folio(p)); | |
| 986 | 986 | |
| 987 | 987 | if (count > 0) { |
| 988 | 988 | pr_err("%#lx: %s still referenced by %d users\n", |
| @@ -1464,7 +1464,7 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb, · 1463 unmodified lines | ||
| 1464 | 1464 | delay_rmap = 0; |
| 1465 | 1465 | if (!folio_test_anon(folio)) { |
| 1466 | 1466 | if (pte_dirty(ptent)) { |
| 1467 | − folio_set_dirty(folio); | |
| 1467 | + folio_mark_dirty(folio); | |
| 1468 | 1468 | if (tlb_delay_rmap(tlb)) { |
| 1469 | 1469 | delay_rmap = 1; |
| 1470 | 1470 | force_flush = 1; |
| @@ -1825,15 +1825,17 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, · 1824 unmodified lines | ||
| 1825 | 1825 | /* |
| 1826 | 1826 | * mmap_region() will call shmem_zero_setup() to create a file, |
| 1827 | 1827 | * so use shmem's get_unmapped_area in case it can be huge. |
| 1828 | − * do_mmap() will clear pgoff, so match alignment. | |
| 1829 | 1828 | */ |
| 1830 | − pgoff = 0; | |
| 1831 | 1829 | get_area = shmem_get_unmapped_area; |
| 1832 | 1830 | } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { |
| 1833 | 1831 | /* Ensures that larger anonymous mappings are THP aligned. */ |
| 1834 | 1832 | get_area = thp_get_unmapped_area; |
| 1835 | 1833 | } |
| 1836 | 1834 | |
| 1835 | + /* Always treat pgoff as zero for anonymous memory. */ | |
| 1836 | + if (!file) | |
| 1837 | + pgoff = 0; | |
| 1838 | + | |
| 1837 | 1839 | addr = get_area(file, addr, len, pgoff, flags); |
| 1838 | 1840 | if (IS_ERR_VALUE(addr)) |
| 1839 | 1841 | return addr; |
| @@ -1638,7 +1638,7 @@ static inline void wb_dirty_limits(struct dirty_throttle_control *dtc) · 1637 unmodified lines | ||
| 1638 | 1638 | */ |
| 1639 | 1639 | dtc->wb_thresh = __wb_calc_thresh(dtc); |
| 1640 | 1640 | dtc->wb_bg_thresh = dtc->thresh ? |
| 1641 | − div_u64((u64)dtc->wb_thresh * dtc->bg_thresh, dtc->thresh) : 0; | |
| 1641 | + div64_u64(dtc->wb_thresh * dtc->bg_thresh, dtc->thresh) : 0; | |
| 1642 | 1642 | |
| 1643 | 1643 | /* |
| 1644 | 1644 | * In order to avoid the stacked BDI deadlock we need |
| @@ -469,7 +469,7 @@ static inline int ra_alloc_folio(struct readahead_control *ractl, pgoff_t index, · 468 unmodified lines | ||
| 469 | 469 | |
| 470 | 470 | if (!folio) |
| 471 | 471 | return -ENOMEM; |
| 472 | − mark = round_up(mark, 1UL << order); | |
| 472 | + mark = round_down(mark, 1UL << order); | |
| 473 | 473 | if (index == mark) |
| 474 | 474 | folio_set_readahead(folio); |
| 475 | 475 | err = filemap_add_folio(ractl->mapping, folio, index, gfp); |
| @@ -575,7 +575,7 @@ static void ondemand_readahead(struct readahead_control *ractl, · 99 unmodified lines | ||
| 575 | 575 | * It's the expected callback index, assume sequential access. |
| 576 | 576 | * Ramp up sizes, and push forward the readahead window. |
| 577 | 577 | */ |
| 578 | − expected = round_up(ra->start + ra->size - ra->async_size, | |
| 578 | + expected = round_down(ra->start + ra->size - ra->async_size, | |
| 579 | 579 | 1UL << order); |
| 580 | 580 | if (index == expected || index == (ra->start + ra->size)) { |
| 581 | 581 | ra->start += ra->size; |
| @@ -357,6 +357,7 @@ static __always_inline ssize_t mfill_atomic_hugetlb( · 356 unmodified lines | ||
| 357 | 357 | unsigned long dst_start, |
| 358 | 358 | unsigned long src_start, |
| 359 | 359 | unsigned long len, |
| 360 | + atomic_t *mmap_changing, | |
| 360 | 361 | uffd_flags_t flags) |
| 361 | 362 | { |
| 362 | 363 | struct mm_struct *dst_mm = dst_vma->vm_mm; |
| @@ -472,6 +473,15 @@ retry: · 109 unmodified lines | ||
| 472 | 473 | goto out; |
| 473 | 474 | } |
| 474 | 475 | mmap_read_lock(dst_mm); |
| 476 | + /* | |
| 477 | + * If memory mappings are changing because of non-cooperative | |
| 478 | + * operation (e.g. mremap) running in parallel, bail out and | |
| 479 | + * request the user to retry later | |
| 480 | + */ | |
| 481 | + if (mmap_changing && atomic_read(mmap_changing)) { | |
| 482 | + err = -EAGAIN; | |
| 483 | + break; | |
| 484 | + } | |
| 475 | 485 | |
| 476 | 486 | dst_vma = NULL; |
| 477 | 487 | goto retry; |
| @@ -506,6 +516,7 @@ extern ssize_t mfill_atomic_hugetlb(struct vm_area_struct *dst_vma, · 28 unmodified lines | ||
| 506 | 516 | unsigned long dst_start, |
| 507 | 517 | unsigned long src_start, |
| 508 | 518 | unsigned long len, |
| 519 | + atomic_t *mmap_changing, | |
| 509 | 520 | uffd_flags_t flags); |
| 510 | 521 | #endif /* CONFIG_HUGETLB_PAGE */ |
| 511 | 522 | |
| @@ -622,8 +633,8 @@ retry: · 110 unmodified lines | ||
| 622 | 633 | * If this is a HUGETLB vma, pass off to appropriate routine |
| 623 | 634 | */ |
| 624 | 635 | if (is_vm_hugetlb_page(dst_vma)) |
| 625 | − return mfill_atomic_hugetlb(dst_vma, dst_start, | |
| 626 | − src_start, len, flags); | |
| 636 | + return mfill_atomic_hugetlb(dst_vma, dst_start, src_start, | |
| 637 | + len, mmap_changing, flags); | |
| 627 | 638 | |
| 628 | 639 | if (!vma_is_anonymous(dst_vma) && !vma_is_shmem(dst_vma)) |
| 629 | 640 | goto out_unlock; |
| @@ -2175,6 +2175,7 @@ void batadv_mcast_free(struct batadv_priv *bat_priv) · 2174 unmodified lines | ||
| 2175 | 2175 | cancel_delayed_work_sync(&bat_priv->mcast.work); |
| 2176 | 2176 | |
| 2177 | 2177 | batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 2); |
| 2178 | + batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST_TRACKER, 1); | |
| 2178 | 2179 | batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 2); |
| 2179 | 2180 | |
| 2180 | 2181 | /* safely calling outside of worker, as worker was canceled above */ |
| @@ -2198,6 +2199,8 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig) · 17 unmodified lines | ||
| 2198 | 2199 | BATADV_MCAST_WANT_NO_RTR4); |
| 2199 | 2200 | batadv_mcast_want_rtr6_update(bat_priv, orig, |
| 2200 | 2201 | BATADV_MCAST_WANT_NO_RTR6); |
| 2202 | + batadv_mcast_have_mc_ptype_update(bat_priv, orig, | |
| 2203 | + BATADV_MCAST_HAVE_MC_PTYPE_CAPA); | |
| 2201 | 2204 | |
| 2202 | 2205 | spin_unlock_bh(&orig->mcast_handler_lock); |
| 2203 | 2206 | } |
| @@ -1762,6 +1762,10 @@ static void br_ip6_multicast_querier_expired(struct timer_list *t) · 1761 unmodified lines | ||
| 1762 | 1762 | } |
| 1763 | 1763 | #endif |
| 1764 | 1764 | |
| 1765 | +static void br_multicast_query_delay_expired(struct timer_list *t) | |
| 1766 | +{ | |
| 1767 | +} | |
| 1768 | + | |
| 1765 | 1769 | static void br_multicast_select_own_querier(struct net_bridge_mcast *brmctx, |
| 1766 | 1770 | struct br_ip *ip, |
| 1767 | 1771 | struct sk_buff *skb) |
| @@ -3198,7 +3202,7 @@ br_multicast_update_query_timer(struct net_bridge_mcast *brmctx, · 1430 unmodified lines | ||
| 3198 | 3202 | unsigned long max_delay) |
| 3199 | 3203 | { |
| 3200 | 3204 | if (!timer_pending(&query->timer)) |
| 3201 | − query->delay_time = jiffies + max_delay; | |
| 3205 | + mod_timer(&query->delay_timer, jiffies + max_delay); | |
| 3202 | 3206 | |
| 3203 | 3207 | mod_timer(&query->timer, jiffies + brmctx->multicast_querier_interval); |
| 3204 | 3208 | } |
| @@ -4041,13 +4045,11 @@ void br_multicast_ctx_init(struct net_bridge *br, · 836 unmodified lines | ||
| 4041 | 4045 | brmctx->multicast_querier_interval = 255 * HZ; |
| 4042 | 4046 | brmctx->multicast_membership_interval = 260 * HZ; |
| 4043 | 4047 | |
| 4044 | − brmctx->ip4_other_query.delay_time = 0; | |
| 4045 | 4048 | brmctx->ip4_querier.port_ifidx = 0; |
| 4046 | 4049 | seqcount_spinlock_init(&brmctx->ip4_querier.seq, &br->multicast_lock); |
| 4047 | 4050 | brmctx->multicast_igmp_version = 2; |
| 4048 | 4051 | #if IS_ENABLED(CONFIG_IPV6) |
| 4049 | 4052 | brmctx->multicast_mld_version = 1; |
| 4050 | − brmctx->ip6_other_query.delay_time = 0; | |
| 4051 | 4053 | brmctx->ip6_querier.port_ifidx = 0; |
| 4052 | 4054 | seqcount_spinlock_init(&brmctx->ip6_querier.seq, &br->multicast_lock); |
| 4053 | 4055 | #endif |
| @@ -4056,6 +4058,8 @@ void br_multicast_ctx_init(struct net_bridge *br, · 2 unmodified lines | ||
| 4056 | 4058 | br_ip4_multicast_local_router_expired, 0); |
| 4057 | 4059 | timer_setup(&brmctx->ip4_other_query.timer, |
| 4058 | 4060 | br_ip4_multicast_querier_expired, 0); |
| 4061 | + timer_setup(&brmctx->ip4_other_query.delay_timer, | |
| 4062 | + br_multicast_query_delay_expired, 0); | |
| 4059 | 4063 | timer_setup(&brmctx->ip4_own_query.timer, |
| 4060 | 4064 | br_ip4_multicast_query_expired, 0); |
| 4061 | 4065 | #if IS_ENABLED(CONFIG_IPV6) |
| @@ -4063,6 +4067,8 @@ void br_multicast_ctx_init(struct net_bridge *br, · 1 unmodified line | ||
| 4063 | 4067 | br_ip6_multicast_local_router_expired, 0); |
| 4064 | 4068 | timer_setup(&brmctx->ip6_other_query.timer, |
| 4065 | 4069 | br_ip6_multicast_querier_expired, 0); |
| 4070 | + timer_setup(&brmctx->ip6_other_query.delay_timer, | |
| 4071 | + br_multicast_query_delay_expired, 0); | |
| 4066 | 4072 | timer_setup(&brmctx->ip6_own_query.timer, |
| 4067 | 4073 | br_ip6_multicast_query_expired, 0); |
| 4068 | 4074 | #endif |
| @@ -4197,10 +4203,12 @@ static void __br_multicast_stop(struct net_bridge_mcast *brmctx) · 128 unmodified lines | ||
| 4197 | 4203 | { |
| 4198 | 4204 | del_timer_sync(&brmctx->ip4_mc_router_timer); |
| 4199 | 4205 | del_timer_sync(&brmctx->ip4_other_query.timer); |
| 4206 | + del_timer_sync(&brmctx->ip4_other_query.delay_timer); | |
| 4200 | 4207 | del_timer_sync(&brmctx->ip4_own_query.timer); |
| 4201 | 4208 | #if IS_ENABLED(CONFIG_IPV6) |
| 4202 | 4209 | del_timer_sync(&brmctx->ip6_mc_router_timer); |
| 4203 | 4210 | del_timer_sync(&brmctx->ip6_other_query.timer); |
| 4211 | + del_timer_sync(&brmctx->ip6_other_query.delay_timer); | |
| 4204 | 4212 | del_timer_sync(&brmctx->ip6_own_query.timer); |
| 4205 | 4213 | #endif |
| 4206 | 4214 | } |
| @@ -4643,13 +4651,15 @@ int br_multicast_set_querier(struct net_bridge_mcast *brmctx, unsigned long val) · 436 unmodified lines | ||
| 4643 | 4651 | max_delay = brmctx->multicast_query_response_interval; |
| 4644 | 4652 | |
| 4645 | 4653 | if (!timer_pending(&brmctx->ip4_other_query.timer)) |
| 4646 | − brmctx->ip4_other_query.delay_time = jiffies + max_delay; | |
| 4654 | + mod_timer(&brmctx->ip4_other_query.delay_timer, | |
| 4655 | + jiffies + max_delay); | |
| 4647 | 4656 | |
| 4648 | 4657 | br_multicast_start_querier(brmctx, &brmctx->ip4_own_query); |
| 4649 | 4658 | |
| 4650 | 4659 | #if IS_ENABLED(CONFIG_IPV6) |
| 4651 | 4660 | if (!timer_pending(&brmctx->ip6_other_query.timer)) |
| 4652 | − brmctx->ip6_other_query.delay_time = jiffies + max_delay; | |
| 4661 | + mod_timer(&brmctx->ip6_other_query.delay_timer, | |
| 4662 | + jiffies + max_delay); | |
| 4653 | 4663 | |
| 4654 | 4664 | br_multicast_start_querier(brmctx, &brmctx->ip6_own_query); |
| 4655 | 4665 | #endif |
| @@ -78,7 +78,7 @@ struct bridge_mcast_own_query { · 77 unmodified lines | ||
| 78 | 78 | /* other querier */ |
| 79 | 79 | struct bridge_mcast_other_query { |
| 80 | 80 | struct timer_list timer; |
| 81 | − unsigned long delay_time; | |
| 81 | + struct timer_list delay_timer; | |
| 82 | 82 | }; |
| 83 | 83 | |
| 84 | 84 | /* selected querier */ |
| @@ -1159,7 +1159,7 @@ __br_multicast_querier_exists(struct net_bridge_mcast *brmctx, · 1074 unmodified lines | ||
| 1159 | 1159 | own_querier_enabled = false; |
| 1160 | 1160 | } |
| 1161 | 1161 | |
| 1162 | − return time_is_before_jiffies(querier->delay_time) && | |
| 1162 | + return !timer_pending(&querier->delay_timer) && | |
| 1163 | 1163 | (own_querier_enabled || timer_pending(&querier->timer)); |
| 1164 | 1164 | } |
| 1165 | 1165 | |
| @@ -674,7 +674,7 @@ static int devlink_port_function_validate(struct devlink_port *devlink_port, · 673 unmodified lines | ||
| 674 | 674 | return -EOPNOTSUPP; |
| 675 | 675 | } |
| 676 | 676 | if (tb[DEVLINK_PORT_FN_ATTR_STATE] && !ops->port_fn_state_set) { |
| 677 | − NL_SET_ERR_MSG_ATTR(extack, tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR], | |
| 677 | + NL_SET_ERR_MSG_ATTR(extack, tb[DEVLINK_PORT_FN_ATTR_STATE], | |
| 678 | 678 | "Function does not support state setting"); |
| 679 | 679 | return -EOPNOTSUPP; |
| 680 | 680 | } |
| @@ -308,7 +308,7 @@ static void send_hsr_supervision_frame(struct hsr_port *master, · 307 unmodified lines | ||
| 308 | 308 | |
| 309 | 309 | skb = hsr_init_skb(master); |
| 310 | 310 | if (!skb) { |
| 311 | − WARN_ONCE(1, "HSR: Could not send supervision frame\n"); | |
| 311 | + netdev_warn_once(master->dev, "HSR: Could not send supervision frame\n"); | |
| 312 | 312 | return; |
| 313 | 313 | } |
| 314 | 314 | |
| @@ -355,7 +355,7 @@ static void send_prp_supervision_frame(struct hsr_port *master, · 40 unmodified lines | ||
| 355 | 355 | |
| 356 | 356 | skb = hsr_init_skb(master); |
| 357 | 357 | if (!skb) { |
| 358 | − WARN_ONCE(1, "PRP: Could not send supervision frame\n"); | |
| 358 | + netdev_warn_once(master->dev, "PRP: Could not send supervision frame\n"); | |
| 359 | 359 | return; |
| 360 | 360 | } |
| 361 | 361 | |
| @@ -1287,6 +1287,12 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork, · 1286 unmodified lines | ||
| 1287 | 1287 | if (unlikely(!rt)) |
| 1288 | 1288 | return -EFAULT; |
| 1289 | 1289 | |
| 1290 | + cork->fragsize = ip_sk_use_pmtu(sk) ? | |
| 1291 | + dst_mtu(&rt->dst) : READ_ONCE(rt->dst.dev->mtu); | |
| 1292 | + | |
| 1293 | + if (!inetdev_valid_mtu(cork->fragsize)) | |
| 1294 | + return -ENETUNREACH; | |
| 1295 | + | |
| 1290 | 1296 | /* |
| 1291 | 1297 | * setup for corking. |
| 1292 | 1298 | */ |
| @@ -1303,12 +1309,6 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork, · 10 unmodified lines | ||
| 1303 | 1309 | cork->addr = ipc->addr; |
| 1304 | 1310 | } |
| 1305 | 1311 | |
| 1306 | − cork->fragsize = ip_sk_use_pmtu(sk) ? | |
| 1307 | − dst_mtu(&rt->dst) : READ_ONCE(rt->dst.dev->mtu); | |
| 1308 | − | |
| 1309 | − if (!inetdev_valid_mtu(cork->fragsize)) | |
| 1310 | − return -ENETUNREACH; | |
| 1311 | − | |
| 1312 | 1312 | cork->gso_size = ipc->gso_size; |
| 1313 | 1313 | |
| 1314 | 1314 | cork->dst = &rt->dst; |
| @@ -1363,12 +1363,13 @@ e_inval: · 1362 unmodified lines | ||
| 1363 | 1363 | * ipv4_pktinfo_prepare - transfer some info from rtable to skb |
| 1364 | 1364 | * @sk: socket |
| 1365 | 1365 | * @skb: buffer |
| 1366 | + * @drop_dst: if true, drops skb dst | |
| 1366 | 1367 | * |
| 1367 | 1368 | * To support IP_CMSG_PKTINFO option, we store rt_iif and specific |
| 1368 | 1369 | * destination in skb->cb[] before dst drop. |
| 1369 | 1370 | * This way, receiver doesn't make cache line misses to read rtable. |
| 1370 | 1371 | */ |
| 1371 | −void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb) | |
| 1372 | +void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb, bool drop_dst) | |
| 1372 | 1373 | { |
| 1373 | 1374 | struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb); |
| 1374 | 1375 | bool prepare = inet_test_bit(PKTINFO, sk) || |
| @@ -1397,7 +1398,8 @@ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb) · 22 unmodified lines | ||
| 1397 | 1398 | pktinfo->ipi_ifindex = 0; |
| 1398 | 1399 | pktinfo->ipi_spec_dst.s_addr = 0; |
| 1399 | 1400 | } |
| 1400 | − skb_dst_drop(skb); | |
| 1401 | + if (drop_dst) | |
| 1402 | + skb_dst_drop(skb); | |
| 1401 | 1403 | } |
| 1402 | 1404 | |
| 1403 | 1405 | int ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval, |
| @@ -1073,7 +1073,7 @@ static int ipmr_cache_report(const struct mr_table *mrt, · 1072 unmodified lines | ||
| 1073 | 1073 | msg = (struct igmpmsg *)skb_network_header(skb); |
| 1074 | 1074 | msg->im_vif = vifi; |
| 1075 | 1075 | msg->im_vif_hi = vifi >> 8; |
| 1076 | − ipv4_pktinfo_prepare(mroute_sk, pkt); | |
| 1076 | + ipv4_pktinfo_prepare(mroute_sk, pkt, false); | |
| 1077 | 1077 | memcpy(skb->cb, pkt->cb, sizeof(skb->cb)); |
| 1078 | 1078 | /* Add our header */ |
| 1079 | 1079 | igmp = skb_put(skb, sizeof(struct igmphdr)); |
| @@ -292,7 +292,7 @@ static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb) · 291 unmodified lines | ||
| 292 | 292 | |
| 293 | 293 | /* Charge it to the socket. */ |
| 294 | 294 | |
| 295 | − ipv4_pktinfo_prepare(sk, skb); | |
| 295 | + ipv4_pktinfo_prepare(sk, skb, true); | |
| 296 | 296 | if (sock_queue_rcv_skb_reason(sk, skb, &reason) < 0) { |
| 297 | 297 | kfree_skb_reason(skb, reason); |
| 298 | 298 | return NET_RX_DROP; |
| @@ -1786,7 +1786,17 @@ static skb_frag_t *skb_advance_to_frag(struct sk_buff *skb, u32 offset_skb, · 1785 unmodified lines | ||
| 1786 | 1786 | |
| 1787 | 1787 | static bool can_map_frag(const skb_frag_t *frag) |
| 1788 | 1788 | { |
| 1789 | − return skb_frag_size(frag) == PAGE_SIZE && !skb_frag_off(frag); | |
| 1789 | + struct page *page; | |
| 1790 | + | |
| 1791 | + if (skb_frag_size(frag) != PAGE_SIZE || skb_frag_off(frag)) | |
| 1792 | + return false; | |
| 1793 | + | |
| 1794 | + page = skb_frag_page(frag); | |
| 1795 | + | |
| 1796 | + if (PageCompound(page) || page->mapping) | |
| 1797 | + return false; | |
| 1798 | + | |
| 1799 | + return true; | |
| 1790 | 1800 | } |
| 1791 | 1801 | |
| 1792 | 1802 | static int find_next_mappable_frag(const skb_frag_t *frag, |
| @@ -2169,7 +2169,7 @@ static int udp_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb) · 2168 unmodified lines | ||
| 2169 | 2169 | |
| 2170 | 2170 | udp_csum_pull_header(skb); |
| 2171 | 2171 | |
| 2172 | − ipv4_pktinfo_prepare(sk, skb); | |
| 2172 | + ipv4_pktinfo_prepare(sk, skb, true); | |
| 2173 | 2173 | return __udp_queue_rcv_skb(sk, skb); |
| 2174 | 2174 | |
| 2175 | 2175 | csum_error: |
| @@ -220,19 +220,26 @@ const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) { · 219 unmodified lines | ||
| 220 | 220 | EXPORT_SYMBOL_GPL(ipv6_stub); |
| 221 | 221 | |
| 222 | 222 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ |
| 223 | −const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; | |
| 223 | +const struct in6_addr in6addr_loopback __aligned(BITS_PER_LONG/8) | |
| 224 | + = IN6ADDR_LOOPBACK_INIT; | |
| 224 | 225 | EXPORT_SYMBOL(in6addr_loopback); |
| 225 | −const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; | |
| 226 | +const struct in6_addr in6addr_any __aligned(BITS_PER_LONG/8) | |
| 227 | + = IN6ADDR_ANY_INIT; | |
| 226 | 228 | EXPORT_SYMBOL(in6addr_any); |
| 227 | −const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT; | |
| 229 | +const struct in6_addr in6addr_linklocal_allnodes __aligned(BITS_PER_LONG/8) | |
| 230 | + = IN6ADDR_LINKLOCAL_ALLNODES_INIT; | |
| 228 | 231 | EXPORT_SYMBOL(in6addr_linklocal_allnodes); |
| 229 | −const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; | |
| 232 | +const struct in6_addr in6addr_linklocal_allrouters __aligned(BITS_PER_LONG/8) | |
| 233 | + = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; | |
| 230 | 234 | EXPORT_SYMBOL(in6addr_linklocal_allrouters); |
| 231 | −const struct in6_addr in6addr_interfacelocal_allnodes = IN6ADDR_INTERFACELOCAL_ALLNODES_INIT; | |
| 235 | +const struct in6_addr in6addr_interfacelocal_allnodes __aligned(BITS_PER_LONG/8) | |
| 236 | + = IN6ADDR_INTERFACELOCAL_ALLNODES_INIT; | |
| 232 | 237 | EXPORT_SYMBOL(in6addr_interfacelocal_allnodes); |
| 233 | −const struct in6_addr in6addr_interfacelocal_allrouters = IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT; | |
| 238 | +const struct in6_addr in6addr_interfacelocal_allrouters __aligned(BITS_PER_LONG/8) | |
| 239 | + = IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT; | |
| 234 | 240 | EXPORT_SYMBOL(in6addr_interfacelocal_allrouters); |
| 235 | −const struct in6_addr in6addr_sitelocal_allrouters = IN6ADDR_SITELOCAL_ALLROUTERS_INIT; | |
| 241 | +const struct in6_addr in6addr_sitelocal_allrouters __aligned(BITS_PER_LONG/8) | |
| 242 | + = IN6ADDR_SITELOCAL_ALLROUTERS_INIT; | |
| 236 | 243 | EXPORT_SYMBOL(in6addr_sitelocal_allrouters); |
| 237 | 244 | |
| 238 | 245 | static void snmp6_free_dev(struct inet6_dev *idev) |
| @@ -796,8 +796,8 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, · 795 unmodified lines | ||
| 796 | 796 | struct sk_buff *skb), |
| 797 | 797 | bool log_ecn_err) |
| 798 | 798 | { |
| 799 | − const struct ipv6hdr *ipv6h = ipv6_hdr(skb); | |
| 800 | − int err; | |
| 799 | + const struct ipv6hdr *ipv6h; | |
| 800 | + int nh, err; | |
| 801 | 801 | |
| 802 | 802 | if ((!(tpi->flags & TUNNEL_CSUM) && |
| 803 | 803 | (tunnel->parms.i_flags & TUNNEL_CSUM)) || |
| @@ -829,7 +829,6 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, · 25 unmodified lines | ||
| 829 | 829 | goto drop; |
| 830 | 830 | } |
| 831 | 831 | |
| 832 | − ipv6h = ipv6_hdr(skb); | |
| 833 | 832 | skb->protocol = eth_type_trans(skb, tunnel->dev); |
| 834 | 833 | skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); |
| 835 | 834 | } else { |
| @@ -837,7 +836,23 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, · 1 unmodified line | ||
| 837 | 836 | skb_reset_mac_header(skb); |
| 838 | 837 | } |
| 839 | 838 | |
| 839 | + /* Save offset of outer header relative to skb->head, | |
| 840 | + * because we are going to reset the network header to the inner header | |
| 841 | + * and might change skb->head. | |
| 842 | + */ | |
| 843 | + nh = skb_network_header(skb) - skb->head; | |
| 844 | + | |
| 840 | 845 | skb_reset_network_header(skb); |
| 846 | + | |
| 847 | + if (!pskb_inet_may_pull(skb)) { | |
| 848 | + DEV_STATS_INC(tunnel->dev, rx_length_errors); | |
| 849 | + DEV_STATS_INC(tunnel->dev, rx_errors); | |
| 850 | + goto drop; | |
| 851 | + } | |
| 852 | + | |
| 853 | + /* Get the outer header. */ | |
| 854 | + ipv6h = (struct ipv6hdr *)(skb->head + nh); | |
| 855 | + | |
| 841 | 856 | memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); |
| 842 | 857 | |
| 843 | 858 | __skb_tunnel_rx(skb, tunnel->dev, tunnel->net); |
| @@ -226,6 +226,8 @@ static int llc_ui_release(struct socket *sock) · 225 unmodified lines | ||
| 226 | 226 | } |
| 227 | 227 | netdev_put(llc->dev, &llc->dev_tracker); |
| 228 | 228 | sock_put(sk); |
| 229 | + sock_orphan(sk); | |
| 230 | + sock->sk = NULL; | |
| 229 | 231 | llc_sk_free(sk); |
| 230 | 232 | out: |
| 231 | 233 | return 0; |
| @@ -2314,9 +2314,6 @@ bool __mptcp_retransmit_pending_data(struct sock *sk) · 2313 unmodified lines | ||
| 2314 | 2314 | if (__mptcp_check_fallback(msk)) |
| 2315 | 2315 | return false; |
| 2316 | 2316 | |
| 2317 | − if (tcp_rtx_and_write_queues_empty(sk)) | |
| 2318 | − return false; | |
| 2319 | − | |
| 2320 | 2317 | /* the closing socket has some data untransmitted and/or unacked: |
| 2321 | 2318 | * some data in the mptcp rtx queue has not really xmitted yet. |
| 2322 | 2319 | * keep it simple and re-inject the whole mptcp level rtx queue |
| @@ -30,6 +30,7 @@ · 29 unmodified lines | ||
| 30 | 30 | #define mtype_del IPSET_TOKEN(MTYPE, _del) |
| 31 | 31 | #define mtype_list IPSET_TOKEN(MTYPE, _list) |
| 32 | 32 | #define mtype_gc IPSET_TOKEN(MTYPE, _gc) |
| 33 | +#define mtype_cancel_gc IPSET_TOKEN(MTYPE, _cancel_gc) | |
| 33 | 34 | #define mtype MTYPE |
| 34 | 35 | |
| 35 | 36 | #define get_ext(set, map, id) ((map)->extensions + ((set)->dsize * (id))) |
| @@ -59,9 +60,6 @@ mtype_destroy(struct ip_set *set) · 23 unmodified lines | ||
| 59 | 60 | { |
| 60 | 61 | struct mtype *map = set->data; |
| 61 | 62 | |
| 62 | − if (SET_WITH_TIMEOUT(set)) | |
| 63 | − del_timer_sync(&map->gc); | |
| 64 | − | |
| 65 | 63 | if (set->dsize && set->extensions & IPSET_EXT_DESTROY) |
| 66 | 64 | mtype_ext_cleanup(set); |
| 67 | 65 | ip_set_free(map->members); |
| @@ -290,6 +288,15 @@ mtype_gc(struct timer_list *t) · 222 unmodified lines | ||
| 290 | 288 | add_timer(&map->gc); |
| 291 | 289 | } |
| 292 | 290 | |
| 291 | +static void | |
| 292 | +mtype_cancel_gc(struct ip_set *set) | |
| 293 | +{ | |
| 294 | + struct mtype *map = set->data; | |
| 295 | + | |
| 296 | + if (SET_WITH_TIMEOUT(set)) | |
| 297 | + del_timer_sync(&map->gc); | |
| 298 | +} | |
| 299 | + | |
| 293 | 300 | static const struct ip_set_type_variant mtype = { |
| 294 | 301 | .kadt = mtype_kadt, |
| 295 | 302 | .uadt = mtype_uadt, |
| @@ -303,6 +310,7 @@ static const struct ip_set_type_variant mtype = { · 7 unmodified lines | ||
| 303 | 310 | .head = mtype_head, |
| 304 | 311 | .list = mtype_list, |
| 305 | 312 | .same_set = mtype_same_set, |
| 313 | + .cancel_gc = mtype_cancel_gc, | |
| 306 | 314 | }; |
| 307 | 315 | |
| 308 | 316 | #endif /* __IP_SET_BITMAP_IP_GEN_H */ |
| @@ -1182,6 +1182,14 @@ ip_set_destroy_set(struct ip_set *set) · 1181 unmodified lines | ||
| 1182 | 1182 | kfree(set); |
| 1183 | 1183 | } |
| 1184 | 1184 | |
| 1185 | +static void | |
| 1186 | +ip_set_destroy_set_rcu(struct rcu_head *head) | |
| 1187 | +{ | |
| 1188 | + struct ip_set *set = container_of(head, struct ip_set, rcu); | |
| 1189 | + | |
| 1190 | + ip_set_destroy_set(set); | |
| 1191 | +} | |
| 1192 | + | |
| 1185 | 1193 | static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info, |
| 1186 | 1194 | const struct nlattr * const attr[]) |
| 1187 | 1195 | { |
| @@ -1193,8 +1201,6 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info, · 5 unmodified lines | ||
| 1193 | 1201 | if (unlikely(protocol_min_failed(attr))) |
| 1194 | 1202 | return -IPSET_ERR_PROTOCOL; |
| 1195 | 1203 | |
| 1196 | − /* Must wait for flush to be really finished in list:set */ | |
| 1197 | − rcu_barrier(); | |
| 1198 | 1204 | |
| 1199 | 1205 | /* Commands are serialized and references are |
| 1200 | 1206 | * protected by the ip_set_ref_lock. |
| @@ -1206,8 +1212,10 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info, · 5 unmodified lines | ||
| 1206 | 1212 | * counter, so if it's already zero, we can proceed |
| 1207 | 1213 | * without holding the lock. |
| 1208 | 1214 | */ |
| 1209 | − read_lock_bh(&ip_set_ref_lock); | |
| 1210 | 1215 | if (!attr[IPSET_ATTR_SETNAME]) { |
| 1216 | + /* Must wait for flush to be really finished in list:set */ | |
| 1217 | + rcu_barrier(); | |
| 1218 | + read_lock_bh(&ip_set_ref_lock); | |
| 1211 | 1219 | for (i = 0; i < inst->ip_set_max; i++) { |
| 1212 | 1220 | s = ip_set(inst, i); |
| 1213 | 1221 | if (s && (s->ref || s->ref_netlink)) { |
| @@ -1221,6 +1229,8 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info, · 7 unmodified lines | ||
| 1221 | 1229 | s = ip_set(inst, i); |
| 1222 | 1230 | if (s) { |
| 1223 | 1231 | ip_set(inst, i) = NULL; |
| 1232 | + /* Must cancel garbage collectors */ | |
| 1233 | + s->variant->cancel_gc(s); | |
| 1224 | 1234 | ip_set_destroy_set(s); |
| 1225 | 1235 | } |
| 1226 | 1236 | } |
| @@ -1228,6 +1238,9 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info, · 1 unmodified line | ||
| 1228 | 1238 | inst->is_destroyed = false; |
| 1229 | 1239 | } else { |
| 1230 | 1240 | u32 flags = flag_exist(info->nlh); |
| 1241 | + u16 features = 0; | |
| 1242 | + | |
| 1243 | + read_lock_bh(&ip_set_ref_lock); | |
| 1231 | 1244 | s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]), |
| 1232 | 1245 | &i); |
| 1233 | 1246 | if (!s) { |
| @@ -1238,10 +1251,16 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info, · 4 unmodified lines | ||
| 1238 | 1251 | ret = -IPSET_ERR_BUSY; |
| 1239 | 1252 | goto out; |
| 1240 | 1253 | } |
| 1254 | + features = s->type->features; | |
| 1241 | 1255 | ip_set(inst, i) = NULL; |
| 1242 | 1256 | read_unlock_bh(&ip_set_ref_lock); |
| 1243 | − | |
| 1244 | − ip_set_destroy_set(s); | |
| 1257 | + if (features & IPSET_TYPE_NAME) { | |
| 1258 | + /* Must wait for flush to be really finished */ | |
| 1259 | + rcu_barrier(); | |
| 1260 | + } | |
| 1261 | + /* Must cancel garbage collectors */ | |
| 1262 | + s->variant->cancel_gc(s); | |
| 1263 | + call_rcu(&s->rcu, ip_set_destroy_set_rcu); | |
| 1245 | 1264 | } |
| 1246 | 1265 | return 0; |
| 1247 | 1266 | out: |
| @@ -1394,9 +1413,6 @@ static int ip_set_swap(struct sk_buff *skb, const struct nfnl_info *info, · 146 unmodified lines | ||
| 1394 | 1413 | ip_set(inst, to_id) = from; |
| 1395 | 1414 | write_unlock_bh(&ip_set_ref_lock); |
| 1396 | 1415 | |
| 1397 | − /* Make sure all readers of the old set pointers are completed. */ | |
| 1398 | − synchronize_rcu(); | |
| 1399 | − | |
| 1400 | 1416 | return 0; |
| 1401 | 1417 | } |
| 1402 | 1418 | |
| @@ -2409,8 +2425,11 @@ ip_set_fini(void) · 1006 unmodified lines | ||
| 2409 | 2425 | { |
| 2410 | 2426 | nf_unregister_sockopt(&so_set); |
| 2411 | 2427 | nfnetlink_subsys_unregister(&ip_set_netlink_subsys); |
| 2412 | − | |
| 2413 | 2428 | unregister_pernet_subsys(&ip_set_net_ops); |
| 2429 | + | |
| 2430 | + /* Wait for call_rcu() in destroy */ | |
| 2431 | + rcu_barrier(); | |
| 2432 | + | |
| 2414 | 2433 | pr_debug("these are the famous last words\n"); |
| 2415 | 2434 | } |
| 2416 | 2435 | |
| @@ -222,6 +222,7 @@ static const union nf_inet_addr zeromask = {}; · 221 unmodified lines | ||
| 222 | 222 | #undef mtype_gc_do |
| 223 | 223 | #undef mtype_gc |
| 224 | 224 | #undef mtype_gc_init |
| 225 | +#undef mtype_cancel_gc | |
| 225 | 226 | #undef mtype_variant |
| 226 | 227 | #undef mtype_data_match |
| 227 | 228 | |
| @@ -266,6 +267,7 @@ static const union nf_inet_addr zeromask = {}; · 38 unmodified lines | ||
| 266 | 267 | #define mtype_gc_do IPSET_TOKEN(MTYPE, _gc_do) |
| 267 | 268 | #define mtype_gc IPSET_TOKEN(MTYPE, _gc) |
| 268 | 269 | #define mtype_gc_init IPSET_TOKEN(MTYPE, _gc_init) |
| 270 | +#define mtype_cancel_gc IPSET_TOKEN(MTYPE, _cancel_gc) | |
| 269 | 271 | #define mtype_variant IPSET_TOKEN(MTYPE, _variant) |
| 270 | 272 | #define mtype_data_match IPSET_TOKEN(MTYPE, _data_match) |
| 271 | 273 | |
| @@ -450,9 +452,6 @@ mtype_destroy(struct ip_set *set) · 178 unmodified lines | ||
| 450 | 452 | struct htype *h = set->data; |
| 451 | 453 | struct list_head *l, *lt; |
| 452 | 454 | |
| 453 | − if (SET_WITH_TIMEOUT(set)) | |
| 454 | − cancel_delayed_work_sync(&h->gc.dwork); | |
| 455 | − | |
| 456 | 455 | mtype_ahash_destroy(set, ipset_dereference_nfnl(h->table), true); |
| 457 | 456 | list_for_each_safe(l, lt, &h->ad) { |
| 458 | 457 | list_del(l); |
| @@ -599,6 +598,15 @@ mtype_gc_init(struct htable_gc *gc) · 140 unmodified lines | ||
| 599 | 598 | queue_delayed_work(system_power_efficient_wq, &gc->dwork, HZ); |
| 600 | 599 | } |
| 601 | 600 | |
| 601 | +static void | |
| 602 | +mtype_cancel_gc(struct ip_set *set) | |
| 603 | +{ | |
| 604 | + struct htype *h = set->data; | |
| 605 | + | |
| 606 | + if (SET_WITH_TIMEOUT(set)) | |
| 607 | + cancel_delayed_work_sync(&h->gc.dwork); | |
| 608 | +} | |
| 609 | + | |
| 602 | 610 | static int |
| 603 | 611 | mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, |
| 604 | 612 | struct ip_set_ext *mext, u32 flags); |
| @@ -1441,6 +1449,7 @@ static const struct ip_set_type_variant mtype_variant = { · 836 unmodified lines | ||
| 1441 | 1449 | .uref = mtype_uref, |
| 1442 | 1450 | .resize = mtype_resize, |
| 1443 | 1451 | .same_set = mtype_same_set, |
| 1452 | + .cancel_gc = mtype_cancel_gc, | |
| 1444 | 1453 | .region_lock = true, |
| 1445 | 1454 | }; |
| 1446 | 1455 | |
| @@ -426,9 +426,6 @@ list_set_destroy(struct ip_set *set) · 425 unmodified lines | ||
| 426 | 426 | struct list_set *map = set->data; |
| 427 | 427 | struct set_elem *e, *n; |
| 428 | 428 | |
| 429 | − if (SET_WITH_TIMEOUT(set)) | |
| 430 | − timer_shutdown_sync(&map->gc); | |
| 431 | − | |
| 432 | 429 | list_for_each_entry_safe(e, n, &map->members, list) { |
| 433 | 430 | list_del(&e->list); |
| 434 | 431 | ip_set_put_byindex(map->net, e->id); |
| @@ -545,6 +542,15 @@ list_set_same_set(const struct ip_set *a, const struct ip_set *b) · 110 unmodified lines | ||
| 545 | 542 | a->extensions == b->extensions; |
| 546 | 543 | } |
| 547 | 544 | |
| 545 | +static void | |
| 546 | +list_set_cancel_gc(struct ip_set *set) | |
| 547 | +{ | |
| 548 | + struct list_set *map = set->data; | |
| 549 | + | |
| 550 | + if (SET_WITH_TIMEOUT(set)) | |
| 551 | + timer_shutdown_sync(&map->gc); | |
| 552 | +} | |
| 553 | + | |
| 548 | 554 | static const struct ip_set_type_variant set_variant = { |
| 549 | 555 | .kadt = list_set_kadt, |
| 550 | 556 | .uadt = list_set_uadt, |
| @@ -558,6 +564,7 @@ static const struct ip_set_type_variant set_variant = { · 7 unmodified lines | ||
| 558 | 564 | .head = list_set_head, |
| 559 | 565 | .list = list_set_list, |
| 560 | 566 | .same_set = list_set_same_set, |
| 567 | + .cancel_gc = list_set_cancel_gc, | |
| 561 | 568 | }; |
| 562 | 569 | |
| 563 | 570 | static void |
| @@ -283,7 +283,7 @@ sctp_new(struct nf_conn *ct, const struct sk_buff *skb, · 282 unmodified lines | ||
| 283 | 283 | pr_debug("Setting vtag %x for secondary conntrack\n", |
| 284 | 284 | sh->vtag); |
| 285 | 285 | ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = sh->vtag; |
| 286 | − } else { | |
| 286 | + } else if (sch->type == SCTP_CID_SHUTDOWN_ACK) { | |
| 287 | 287 | /* If it is a shutdown ack OOTB packet, we expect a return |
| 288 | 288 | shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */ |
| 289 | 289 | pr_debug("Setting vtag %x for new conn OOTB\n", |
| @@ -457,7 +457,8 @@ static void tcp_init_sender(struct ip_ct_tcp_state *sender, · 456 unmodified lines | ||
| 457 | 457 | const struct sk_buff *skb, |
| 458 | 458 | unsigned int dataoff, |
| 459 | 459 | const struct tcphdr *tcph, |
| 460 | − u32 end, u32 win) | |
| 460 | + u32 end, u32 win, | |
| 461 | + enum ip_conntrack_dir dir) | |
| 461 | 462 | { |
| 462 | 463 | /* SYN-ACK in reply to a SYN |
| 463 | 464 | * or SYN from reply direction in simultaneous open. |
| @@ -471,7 +472,8 @@ static void tcp_init_sender(struct ip_ct_tcp_state *sender, · 7 unmodified lines | ||
| 471 | 472 | * Both sides must send the Window Scale option |
| 472 | 473 | * to enable window scaling in either direction. |
| 473 | 474 | */ |
| 474 | − if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE && | |
| 475 | + if (dir == IP_CT_DIR_REPLY && | |
| 476 | + !(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE && | |
| 475 | 477 | receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE)) { |
| 476 | 478 | sender->td_scale = 0; |
| 477 | 479 | receiver->td_scale = 0; |
| @@ -542,7 +544,7 @@ tcp_in_window(struct nf_conn *ct, enum ip_conntrack_dir dir, · 64 unmodified lines | ||
| 542 | 544 | if (tcph->syn) { |
| 543 | 545 | tcp_init_sender(sender, receiver, |
| 544 | 546 | skb, dataoff, tcph, |
| 545 | − end, win); | |
| 547 | + end, win, dir); | |
| 546 | 548 | if (!tcph->ack) |
| 547 | 549 | /* Simultaneous open */ |
| 548 | 550 | return NFCT_TCP_ACCEPT; |
| @@ -585,7 +587,7 @@ tcp_in_window(struct nf_conn *ct, enum ip_conntrack_dir dir, · 36 unmodified lines | ||
| 585 | 587 | */ |
| 586 | 588 | tcp_init_sender(sender, receiver, |
| 587 | 589 | skb, dataoff, tcph, |
| 588 | − end, win); | |
| 590 | + end, win, dir); | |
| 589 | 591 | |
| 590 | 592 | if (dir == IP_CT_DIR_REPLY && !tcph->ack) |
| 591 | 593 | return NFCT_TCP_ACCEPT; |
| @@ -193,11 +193,12 @@ void nf_logger_put(int pf, enum nf_log_type type) · 192 unmodified lines | ||
| 193 | 193 | return; |
| 194 | 194 | } |
| 195 | 195 | |
| 196 | − BUG_ON(loggers[pf][type] == NULL); | |
| 197 | − | |
| 198 | 196 | rcu_read_lock(); |
| 199 | 197 | logger = rcu_dereference(loggers[pf][type]); |
| 200 | − module_put(logger->me); | |
| 198 | + if (!logger) | |
| 199 | + WARN_ON_ONCE(1); | |
| 200 | + else | |
| 201 | + module_put(logger->me); | |
| 201 | 202 | rcu_read_unlock(); |
| 202 | 203 | } |
| 203 | 204 | EXPORT_SYMBOL_GPL(nf_logger_put); |
| @@ -7558,11 +7558,15 @@ nla_put_failure: · 7557 unmodified lines | ||
| 7558 | 7558 | return -1; |
| 7559 | 7559 | } |
| 7560 | 7560 | |
| 7561 | −static const struct nft_object_type *__nft_obj_type_get(u32 objtype) | |
| 7561 | +static const struct nft_object_type *__nft_obj_type_get(u32 objtype, u8 family) | |
| 7562 | 7562 | { |
| 7563 | 7563 | const struct nft_object_type *type; |
| 7564 | 7564 | |
| 7565 | 7565 | list_for_each_entry(type, &nf_tables_objects, list) { |
| 7566 | + if (type->family != NFPROTO_UNSPEC && | |
| 7567 | + type->family != family) | |
| 7568 | + continue; | |
| 7569 | + | |
| 7566 | 7570 | if (objtype == type->type) |
| 7567 | 7571 | return type; |
| 7568 | 7572 | } |
| @@ -7570,11 +7574,11 @@ static const struct nft_object_type *__nft_obj_type_get(u32 objtype) · 1 unmodified line | ||
| 7570 | 7574 | } |
| 7571 | 7575 | |
| 7572 | 7576 | static const struct nft_object_type * |
| 7573 | −nft_obj_type_get(struct net *net, u32 objtype) | |
| 7577 | +nft_obj_type_get(struct net *net, u32 objtype, u8 family) | |
| 7574 | 7578 | { |
| 7575 | 7579 | const struct nft_object_type *type; |
| 7576 | 7580 | |
| 7577 | − type = __nft_obj_type_get(objtype); | |
| 7581 | + type = __nft_obj_type_get(objtype, family); | |
| 7578 | 7582 | if (type != NULL && try_module_get(type->owner)) |
| 7579 | 7583 | return type; |
| 7580 | 7584 | |
| @@ -7667,7 +7671,7 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info, · 86 unmodified lines | ||
| 7667 | 7671 | if (info->nlh->nlmsg_flags & NLM_F_REPLACE) |
| 7668 | 7672 | return -EOPNOTSUPP; |
| 7669 | 7673 | |
| 7670 | − type = __nft_obj_type_get(objtype); | |
| 7674 | + type = __nft_obj_type_get(objtype, family); | |
| 7671 | 7675 | if (WARN_ON_ONCE(!type)) |
| 7672 | 7676 | return -ENOENT; |
| 7673 | 7677 | |
| @@ -7681,7 +7685,7 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info, · 7 unmodified lines | ||
| 7681 | 7685 | if (!nft_use_inc(&table->use)) |
| 7682 | 7686 | return -EMFILE; |
| 7683 | 7687 | |
| 7684 | − type = nft_obj_type_get(net, objtype); | |
| 7688 | + type = nft_obj_type_get(net, objtype, family); | |
| 7685 | 7689 | if (IS_ERR(type)) { |
| 7686 | 7690 | err = PTR_ERR(type); |
| 7687 | 7691 | goto err_type; |
| @@ -1250,7 +1250,31 @@ static int nft_ct_expect_obj_init(const struct nft_ctx *ctx, · 1249 unmodified lines | ||
| 1250 | 1250 | if (tb[NFTA_CT_EXPECT_L3PROTO]) |
| 1251 | 1251 | priv->l3num = ntohs(nla_get_be16(tb[NFTA_CT_EXPECT_L3PROTO])); |
| 1252 | 1252 | |
| 1253 | + switch (priv->l3num) { | |
| 1254 | + case NFPROTO_IPV4: | |
| 1255 | + case NFPROTO_IPV6: | |
| 1256 | + if (priv->l3num != ctx->family) | |
| 1257 | + return -EINVAL; | |
| 1258 | + | |
| 1259 | + fallthrough; | |
| 1260 | + case NFPROTO_INET: | |
| 1261 | + break; | |
| 1262 | + default: | |
| 1263 | + return -EOPNOTSUPP; | |
| 1264 | + } | |
| 1265 | + | |
| 1253 | 1266 | priv->l4proto = nla_get_u8(tb[NFTA_CT_EXPECT_L4PROTO]); |
| 1267 | + switch (priv->l4proto) { | |
| 1268 | + case IPPROTO_TCP: | |
| 1269 | + case IPPROTO_UDP: | |
| 1270 | + case IPPROTO_UDPLITE: | |
| 1271 | + case IPPROTO_DCCP: | |
| 1272 | + case IPPROTO_SCTP: | |
| 1273 | + break; | |
| 1274 | + default: | |
| 1275 | + return -EOPNOTSUPP; | |
| 1276 | + } | |
| 1277 | + | |
| 1254 | 1278 | priv->dport = nla_get_be16(tb[NFTA_CT_EXPECT_DPORT]); |
| 1255 | 1279 | priv->timeout = nla_get_u32(tb[NFTA_CT_EXPECT_TIMEOUT]); |
| 1256 | 1280 | priv->size = nla_get_u8(tb[NFTA_CT_EXPECT_SIZE]); |
| @@ -713,6 +713,7 @@ static const struct nft_object_ops nft_tunnel_obj_ops = { · 712 unmodified lines | ||
| 713 | 713 | |
| 714 | 714 | static struct nft_object_type nft_tunnel_obj_type __read_mostly = { |
| 715 | 715 | .type = NFT_OBJECT_TUNNEL, |
| 716 | + .family = NFPROTO_NETDEV, | |
| 716 | 717 | .ops = &nft_tunnel_obj_ops, |
| 717 | 718 | .maxattr = NFTA_TUNNEL_KEY_MAX, |
| 718 | 719 | .policy = nft_tunnel_key_policy, |
| @@ -1208,6 +1208,10 @@ void nci_free_device(struct nci_dev *ndev) · 1207 unmodified lines | ||
| 1208 | 1208 | { |
| 1209 | 1209 | nfc_free_device(ndev->nfc_dev); |
| 1210 | 1210 | nci_hci_deallocate(ndev); |
| 1211 | + | |
| 1212 | + /* drop partial rx data packet if present */ | |
| 1213 | + if (ndev->rx_data_reassembly) | |
| 1214 | + kfree_skb(ndev->rx_data_reassembly); | |
| 1211 | 1215 | kfree(ndev); |
| 1212 | 1216 | } |
| 1213 | 1217 | EXPORT_SYMBOL(nci_free_device); |
| @@ -1877,9 +1877,15 @@ static bool smcd_lgr_match(struct smc_link_group *lgr, · 1876 unmodified lines | ||
| 1877 | 1877 | struct smcd_dev *smcismdev, |
| 1878 | 1878 | struct smcd_gid *peer_gid) |
| 1879 | 1879 | { |
| 1880 | − return lgr->peer_gid.gid == peer_gid->gid && lgr->smcd == smcismdev && | |
| 1881 | − smc_ism_is_virtual(smcismdev) ? | |
| 1882 | − (lgr->peer_gid.gid_ext == peer_gid->gid_ext) : 1; | |
| 1880 | + if (lgr->peer_gid.gid != peer_gid->gid || | |
| 1881 | + lgr->smcd != smcismdev) | |
| 1882 | + return false; | |
| 1883 | + | |
| 1884 | + if (smc_ism_is_virtual(smcismdev) && | |
| 1885 | + lgr->peer_gid.gid_ext != peer_gid->gid_ext) | |
| 1886 | + return false; | |
| 1887 | + | |
| 1888 | + return true; | |
| 1883 | 1889 | } |
| 1884 | 1890 | |
| 1885 | 1891 | /* create a new SMC connection (and a new link group if necessary) */ |
| @@ -1598,10 +1598,10 @@ void svc_process_bc(struct rpc_rqst *req, struct svc_rqst *rqstp) · 1597 unmodified lines | ||
| 1598 | 1598 | /* Finally, send the reply synchronously */ |
| 1599 | 1599 | if (rqstp->bc_to_initval > 0) { |
| 1600 | 1600 | timeout.to_initval = rqstp->bc_to_initval; |
| 1601 | − timeout.to_retries = rqstp->bc_to_initval; | |
| 1601 | + timeout.to_retries = rqstp->bc_to_retries; | |
| 1602 | 1602 | } else { |
| 1603 | 1603 | timeout.to_initval = req->rq_xprt->timeout->to_initval; |
| 1604 | − timeout.to_initval = req->rq_xprt->timeout->to_retries; | |
| 1604 | + timeout.to_retries = req->rq_xprt->timeout->to_retries; | |
| 1605 | 1605 | } |
| 1606 | 1606 | memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf)); |
| 1607 | 1607 | task = rpc_run_bc_task(req, &timeout); |
| @@ -1342,13 +1342,11 @@ static void unix_state_double_lock(struct sock *sk1, struct sock *sk2) · 1341 unmodified lines | ||
| 1342 | 1342 | unix_state_lock(sk1); |
| 1343 | 1343 | return; |
| 1344 | 1344 | } |
| 1345 | − if (sk1 < sk2) { | |
| 1346 | − unix_state_lock(sk1); | |
| 1347 | − unix_state_lock_nested(sk2); | |
| 1348 | − } else { | |
| 1349 | − unix_state_lock(sk2); | |
| 1350 | − unix_state_lock_nested(sk1); | |
| 1351 | − } | |
| 1345 | + if (sk1 > sk2) | |
| 1346 | + swap(sk1, sk2); | |
| 1347 | + | |
| 1348 | + unix_state_lock(sk1); | |
| 1349 | + unix_state_lock_nested(sk2, U_LOCK_SECOND); | |
| 1352 | 1350 | } |
| 1353 | 1351 | |
| 1354 | 1352 | static void unix_state_double_unlock(struct sock *sk1, struct sock *sk2) |
| @@ -1589,7 +1587,7 @@ restart: · 234 unmodified lines | ||
| 1589 | 1587 | goto out_unlock; |
| 1590 | 1588 | } |
| 1591 | 1589 | |
| 1592 | − unix_state_lock_nested(sk); | |
| 1590 | + unix_state_lock_nested(sk, U_LOCK_SECOND); | |
| 1593 | 1591 | |
| 1594 | 1592 | if (sk->sk_state != st) { |
| 1595 | 1593 | unix_state_unlock(sk); |
| @@ -84,7 +84,7 @@ static int sk_diag_dump_icons(struct sock *sk, struct sk_buff *nlskb) · 83 unmodified lines | ||
| 84 | 84 | * queue lock. With the other's queue locked it's |
| 85 | 85 | * OK to lock the state. |
| 86 | 86 | */ |
| 87 | − unix_state_lock_nested(req); | |
| 87 | + unix_state_lock_nested(req, U_LOCK_DIAG); | |
| 88 | 88 | peer = unix_sk(req)->peer; |
| 89 | 89 | buf[i++] = (peer ? sock_i_ino(peer) : 0); |
| 90 | 90 | unix_state_unlock(req); |
| @@ -9,8 +9,8 @@ · 8 unmodified lines | ||
| 9 | 9 | # Input config fragments without '.config' suffix |
| 10 | 10 | define merge_into_defconfig |
| 11 | 11 | $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh \ |
| 12 | − -m -O $(objtree) $(srctree)/arch/$(ARCH)/configs/$(1) \ | |
| 13 | − $(foreach config,$(2),$(srctree)/arch/$(ARCH)/configs/$(config).config) | |
| 12 | + -m -O $(objtree) $(srctree)/arch/$(SRCARCH)/configs/$(1) \ | |
| 13 | + $(foreach config,$(2),$(srctree)/arch/$(SRCARCH)/configs/$(config).config) | |
| 14 | 14 | +$(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig |
| 15 | 15 | endef |
| 16 | 16 | |
| @@ -23,7 +23,7 @@ endef · 6 unmodified lines | ||
| 23 | 23 | # Input config fragments without '.config' suffix |
| 24 | 24 | define merge_into_defconfig_override |
| 25 | 25 | $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh \ |
| 26 | − -Q -m -O $(objtree) $(srctree)/arch/$(ARCH)/configs/$(1) \ | |
| 27 | − $(foreach config,$(2),$(srctree)/arch/$(ARCH)/configs/$(config).config) | |
| 26 | + -Q -m -O $(objtree) $(srctree)/arch/$(SRCARCH)/configs/$(1) \ | |
| 27 | + $(foreach config,$(2),$(srctree)/arch/$(SRCARCH)/configs/$(config).config) | |
| 28 | 28 | +$(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig |
| 29 | 29 | endef |
| @@ -345,6 +345,8 @@ void sym_calc_value(struct symbol *sym) · 344 unmodified lines | ||
| 345 | 345 | |
| 346 | 346 | oldval = sym->curr; |
| 347 | 347 | |
| 348 | + newval.tri = no; | |
| 349 | + | |
| 348 | 350 | switch (sym->type) { |
| 349 | 351 | case S_INT: |
| 350 | 352 | newval.val = "0"; |
| @@ -357,7 +359,7 @@ void sym_calc_value(struct symbol *sym) · 6 unmodified lines | ||
| 357 | 359 | break; |
| 358 | 360 | case S_BOOLEAN: |
| 359 | 361 | case S_TRISTATE: |
| 360 | − newval = symbol_no.curr; | |
| 362 | + newval.val = "n"; | |
| 361 | 363 | break; |
| 362 | 364 | default: |
| 363 | 365 | sym->curr.val = sym->name; |
| @@ -70,9 +70,7 @@ void modpost_log(enum loglevel loglevel, const char *fmt, ...) · 69 unmodified lines | ||
| 70 | 70 | break; |
| 71 | 71 | case LOG_ERROR: |
| 72 | 72 | fprintf(stderr, "ERROR: "); |
| 73 | − break; | |
| 74 | − case LOG_FATAL: | |
| 75 | − fprintf(stderr, "FATAL: "); | |
| 73 | + error_occurred = true; | |
| 76 | 74 | break; |
| 77 | 75 | default: /* invalid loglevel, ignore */ |
| 78 | 76 | break; |
| @@ -83,16 +81,8 @@ void modpost_log(enum loglevel loglevel, const char *fmt, ...) · 4 unmodified lines | ||
| 83 | 81 | va_start(arglist, fmt); |
| 84 | 82 | vfprintf(stderr, fmt, arglist); |
| 85 | 83 | va_end(arglist); |
| 86 | − | |
| 87 | − if (loglevel == LOG_FATAL) | |
| 88 | − exit(1); | |
| 89 | − if (loglevel == LOG_ERROR) | |
| 90 | − error_occurred = true; | |
| 91 | 84 | } |
| 92 | 85 | |
| 93 | −void __attribute__((alias("modpost_log"))) | |
| 94 | −modpost_log_noret(enum loglevel loglevel, const char *fmt, ...); | |
| 95 | − | |
| 96 | 86 | static inline bool strends(const char *str, const char *postfix) |
| 97 | 87 | { |
| 98 | 88 | if (strlen(str) < strlen(postfix)) |
| @@ -806,7 +796,8 @@ static void check_section(const char *modname, struct elf_info *elf, · 707 unmodified lines | ||
| 806 | 796 | |
| 807 | 797 | #define DATA_SECTIONS ".data", ".data.rel" |
| 808 | 798 | #define TEXT_SECTIONS ".text", ".text.*", ".sched.text", \ |
| 809 | − ".kprobes.text", ".cpuidle.text", ".noinstr.text" | |
| 799 | + ".kprobes.text", ".cpuidle.text", ".noinstr.text", \ | |
| 800 | + ".ltext", ".ltext.*" | |
| 810 | 801 | #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ |
| 811 | 802 | ".fixup", ".entry.text", ".exception.text", \ |
| 812 | 803 | ".coldtext", ".softirqentry.text" |
| @@ -194,15 +194,11 @@ void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym); · 193 unmodified lines | ||
| 194 | 194 | enum loglevel { |
| 195 | 195 | LOG_WARN, |
| 196 | 196 | LOG_ERROR, |
| 197 | − LOG_FATAL | |
| 198 | 197 | }; |
| 199 | 198 | |
| 200 | 199 | void __attribute__((format(printf, 2, 3))) |
| 201 | 200 | modpost_log(enum loglevel loglevel, const char *fmt, ...); |
| 202 | 201 | |
| 203 | −void __attribute__((format(printf, 2, 3), noreturn)) | |
| 204 | −modpost_log_noret(enum loglevel loglevel, const char *fmt, ...); | |
| 205 | − | |
| 206 | 202 | /* |
| 207 | 203 | * warn - show the given message, then let modpost continue running, still |
| 208 | 204 | * allowing modpost to exit successfully. This should be used when |
| @@ -218,4 +214,4 @@ modpost_log_noret(enum loglevel loglevel, const char *fmt, ...); · 9 unmodified lines | ||
| 218 | 214 | */ |
| 219 | 215 | #define warn(fmt, args...) modpost_log(LOG_WARN, fmt, ##args) |
| 220 | 216 | #define error(fmt, args...) modpost_log(LOG_ERROR, fmt, ##args) |
| 221 | −#define fatal(fmt, args...) modpost_log_noret(LOG_FATAL, fmt, ##args) | |
| 217 | +#define fatal(fmt, args...) do { error(fmt, ##args); exit(1); } while (1) | |
| @@ -55,12 +55,12 @@ patch -p1 < %{SOURCE2} · 54 unmodified lines | ||
| 55 | 55 | %{make} %{makeflags} KERNELRELEASE=%{KERNELRELEASE} KBUILD_BUILD_VERSION=%{release} |
| 56 | 56 | |
| 57 | 57 | %install |
| 58 | −mkdir -p %{buildroot}/boot | |
| 59 | −cp $(%{make} %{makeflags} -s image_name) %{buildroot}/boot/vmlinuz-%{KERNELRELEASE} | |
| 58 | +mkdir -p %{buildroot}/lib/modules/%{KERNELRELEASE} | |
| 59 | +cp $(%{make} %{makeflags} -s image_name) %{buildroot}/lib/modules/%{KERNELRELEASE}/vmlinuz | |
| 60 | 60 | %{make} %{makeflags} INSTALL_MOD_PATH=%{buildroot} modules_install |
| 61 | 61 | %{make} %{makeflags} INSTALL_HDR_PATH=%{buildroot}/usr headers_install |
| 62 | −cp System.map %{buildroot}/boot/System.map-%{KERNELRELEASE} | |
| 63 | −cp .config %{buildroot}/boot/config-%{KERNELRELEASE} | |
| 62 | +cp System.map %{buildroot}/lib/modules/%{KERNELRELEASE} | |
| 63 | +cp .config %{buildroot}/lib/modules/%{KERNELRELEASE}/config | |
| 64 | 64 | ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEASE}/build |
| 65 | 65 | %if %{with_devel} |
| 66 | 66 | %{make} %{makeflags} run-command KBUILD_RUN_COMMAND='${srctree}/scripts/package/install-extmod-build %{buildroot}/usr/src/kernels/%{KERNELRELEASE}' |
| @@ -70,13 +70,14 @@ ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEA · 3 unmodified lines | ||
| 70 | 70 | rm -rf %{buildroot} |
| 71 | 71 | |
| 72 | 72 | %post |
| 73 | −if [ -x /sbin/installkernel -a -r /boot/vmlinuz-%{KERNELRELEASE} -a -r /boot/System.map-%{KERNELRELEASE} ]; then | |
| 74 | −cp /boot/vmlinuz-%{KERNELRELEASE} /boot/.vmlinuz-%{KERNELRELEASE}-rpm | |
| 75 | −cp /boot/System.map-%{KERNELRELEASE} /boot/.System.map-%{KERNELRELEASE}-rpm | |
| 76 | −rm -f /boot/vmlinuz-%{KERNELRELEASE} /boot/System.map-%{KERNELRELEASE} | |
| 77 | −/sbin/installkernel %{KERNELRELEASE} /boot/.vmlinuz-%{KERNELRELEASE}-rpm /boot/.System.map-%{KERNELRELEASE}-rpm | |
| 78 | −rm -f /boot/.vmlinuz-%{KERNELRELEASE}-rpm /boot/.System.map-%{KERNELRELEASE}-rpm | |
| 73 | +if [ -x /usr/bin/kernel-install ]; then | |
| 74 | + /usr/bin/kernel-install add %{KERNELRELEASE} /lib/modules/%{KERNELRELEASE}/vmlinuz | |
| 79 | 75 | fi |
| 76 | +for file in vmlinuz System.map config; do | |
| 77 | + if ! cmp --silent "/lib/modules/%{KERNELRELEASE}/${file}" "/boot/${file}-%{KERNELRELEASE}"; then | |
| 78 | + cp "/lib/modules/%{KERNELRELEASE}/${file}" "/boot/${file}-%{KERNELRELEASE}" | |
| 79 | + fi | |
| 80 | +done | |
| 80 | 81 | |
| 81 | 82 | %preun |
| 82 | 83 | if [ -x /sbin/new-kernel-pkg ]; then |
| @@ -94,7 +95,6 @@ fi · 11 unmodified lines | ||
| 94 | 95 | %defattr (-, root, root) |
| 95 | 96 | /lib/modules/%{KERNELRELEASE} |
| 96 | 97 | %exclude /lib/modules/%{KERNELRELEASE}/build |
| 97 | −/boot/* | |
| 98 | 98 | |
| 99 | 99 | %files headers |
| 100 | 100 | %defattr (-, root, root) |
| @@ -4255,7 +4255,19 @@ EXPORT_SYMBOL(security_inode_setsecctx); · 4254 unmodified lines | ||
| 4255 | 4255 | */ |
| 4256 | 4256 | int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) |
| 4257 | 4257 | { |
| 4258 | − return call_int_hook(inode_getsecctx, -EOPNOTSUPP, inode, ctx, ctxlen); | |
| 4258 | + struct security_hook_list *hp; | |
| 4259 | + int rc; | |
| 4260 | + | |
| 4261 | + /* | |
| 4262 | + * Only one module will provide a security context. | |
| 4263 | + */ | |
| 4264 | + hlist_for_each_entry(hp, &security_hook_heads.inode_getsecctx, list) { | |
| 4265 | + rc = hp->hook.inode_getsecctx(inode, ctx, ctxlen); | |
| 4266 | + if (rc != LSM_RET_DEFAULT(inode_getsecctx)) | |
| 4267 | + return rc; | |
| 4268 | + } | |
| 4269 | + | |
| 4270 | + return LSM_RET_DEFAULT(inode_getsecctx); | |
| 4259 | 4271 | } |
| 4260 | 4272 | EXPORT_SYMBOL(security_inode_getsecctx); |
| 4261 | 4273 | |
| @@ -4612,8 +4624,20 @@ EXPORT_SYMBOL(security_sock_rcv_skb); · 350 unmodified lines | ||
| 4612 | 4624 | int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval, |
| 4613 | 4625 | sockptr_t optlen, unsigned int len) |
| 4614 | 4626 | { |
| 4615 | − return call_int_hook(socket_getpeersec_stream, -ENOPROTOOPT, sock, | |
| 4616 | − optval, optlen, len); | |
| 4627 | + struct security_hook_list *hp; | |
| 4628 | + int rc; | |
| 4629 | + | |
| 4630 | + /* | |
| 4631 | + * Only one module will provide a security context. | |
| 4632 | + */ | |
| 4633 | + hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_stream, | |
| 4634 | + list) { | |
| 4635 | + rc = hp->hook.socket_getpeersec_stream(sock, optval, optlen, | |
| 4636 | + len); | |
| 4637 | + if (rc != LSM_RET_DEFAULT(socket_getpeersec_stream)) | |
| 4638 | + return rc; | |
| 4639 | + } | |
| 4640 | + return LSM_RET_DEFAULT(socket_getpeersec_stream); | |
| 4617 | 4641 | } |
| 4618 | 4642 | |
| 4619 | 4643 | /** |
| @@ -4633,8 +4657,19 @@ int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval, · 13 unmodified lines | ||
| 4633 | 4657 | int security_socket_getpeersec_dgram(struct socket *sock, |
| 4634 | 4658 | struct sk_buff *skb, u32 *secid) |
| 4635 | 4659 | { |
| 4636 | − return call_int_hook(socket_getpeersec_dgram, -ENOPROTOOPT, sock, | |
| 4637 | − skb, secid); | |
| 4660 | + struct security_hook_list *hp; | |
| 4661 | + int rc; | |
| 4662 | + | |
| 4663 | + /* | |
| 4664 | + * Only one module will provide a security context. | |
| 4665 | + */ | |
| 4666 | + hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_dgram, | |
| 4667 | + list) { | |
| 4668 | + rc = hp->hook.socket_getpeersec_dgram(sock, skb, secid); | |
| 4669 | + if (rc != LSM_RET_DEFAULT(socket_getpeersec_dgram)) | |
| 4670 | + return rc; | |
| 4671 | + } | |
| 4672 | + return LSM_RET_DEFAULT(socket_getpeersec_dgram); | |
| 4638 | 4673 | } |
| 4639 | 4674 | EXPORT_SYMBOL(security_socket_getpeersec_dgram); |
| 4640 | 4675 | |
| @@ -15,7 +15,7 @@ LIBS = -L../ -L$(OUTPUT) -lm -lcpupower · 14 unmodified lines | ||
| 15 | 15 | OBJS = $(OUTPUT)main.o $(OUTPUT)parse.o $(OUTPUT)system.o $(OUTPUT)benchmark.o |
| 16 | 16 | endif |
| 17 | 17 | |
| 18 | −CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\" | |
| 18 | +override CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\" | |
| 19 | 19 | |
| 20 | 20 | $(OUTPUT)%.o : %.c |
| 21 | 21 | $(ECHO) " CC " $@ |
| @@ -65,4 +65,6 @@ cxl_core-y += config_check.o · 64 unmodified lines | ||
| 65 | 65 | cxl_core-y += cxl_core_test.o |
| 66 | 66 | cxl_core-y += cxl_core_exports.o |
| 67 | 67 | |
| 68 | +KBUILD_CFLAGS := $(filter-out -Wmissing-prototypes -Wmissing-declarations, $(KBUILD_CFLAGS)) | |
| 69 | + | |
| 68 | 70 | obj-m += test/ |
| @@ -8,3 +8,5 @@ obj-m += cxl_mock_mem.o · 7 unmodified lines | ||
| 8 | 8 | cxl_test-y := cxl.o |
| 9 | 9 | cxl_mock-y := mock.o |
| 10 | 10 | cxl_mock_mem-y := mem.o |
| 11 | + | |
| 12 | +KBUILD_CFLAGS := $(filter-out -Wmissing-prototypes -Wmissing-declarations, $(KBUILD_CFLAGS)) | |
| @@ -82,4 +82,6 @@ libnvdimm-$(CONFIG_NVDIMM_KEYS) += $(NVDIMM_SRC)/security.o · 81 unmodified lines | ||
| 82 | 82 | libnvdimm-y += libnvdimm_test.o |
| 83 | 83 | libnvdimm-y += config_check.o |
| 84 | 84 | |
| 85 | +KBUILD_CFLAGS := $(filter-out -Wmissing-prototypes -Wmissing-declarations, $(KBUILD_CFLAGS)) | |
| 86 | + | |
| 85 | 87 | obj-m += test/ |
| @@ -48,6 +48,17 @@ test_LAG_cleanup() · 47 unmodified lines | ||
| 48 | 48 | ip link add mv0 link "$name" up address "$ucaddr" type macvlan |
| 49 | 49 | # Used to test dev->mc handling |
| 50 | 50 | ip address add "$addr6" dev "$name" |
| 51 | + | |
| 52 | + # Check that addresses were added as expected | |
| 53 | + (grep_bridge_fdb "$ucaddr" bridge fdb show dev dummy1 || | |
| 54 | + grep_bridge_fdb "$ucaddr" bridge fdb show dev dummy2) >/dev/null | |
| 55 | + check_err $? "macvlan unicast address not found on a slave" | |
| 56 | + | |
| 57 | + # mcaddr is added asynchronously by addrconf_dad_work(), use busywait | |
| 58 | + (busywait 10000 grep_bridge_fdb "$mcaddr" bridge fdb show dev dummy1 || | |
| 59 | + grep_bridge_fdb "$mcaddr" bridge fdb show dev dummy2) >/dev/null | |
| 60 | + check_err $? "IPv6 solicited-node multicast mac address not found on a slave" | |
| 61 | + | |
| 51 | 62 | ip link set dev "$name" down |
| 52 | 63 | ip link del "$name" |
| 53 | 64 | |
| @@ -1,3 +1,5 @@ | ||
| 1 | +CONFIG_DUMMY=y | |
| 2 | +CONFIG_IPV6=y | |
| 3 | +CONFIG_MACVLAN=y | |
| 1 | 4 | CONFIG_NET_TEAM=y |
| 2 | 5 | CONFIG_NET_TEAM_MODE_LOADBALANCE=y |
| 3 | −CONFIG_MACVLAN=y | |
| @@ -880,8 +880,8 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest · 879 unmodified lines | ||
| 880 | 880 | does not overlap with other contacts. The value of `t` may be |
| 881 | 881 | incremented over time to move the point along a linear path. |
| 882 | 882 | """ |
| 883 | − x = 50 + 10 * contact_id + t | |
| 884 | − y = 100 + 100 * contact_id + t | |
| 883 | + x = 50 + 10 * contact_id + t * 11 | |
| 884 | + y = 100 + 100 * contact_id + t * 11 | |
| 885 | 885 | return test_multitouch.Touch(contact_id, x, y) |
| 886 | 886 | |
| 887 | 887 | def make_contacts(self, n, t=0): |
| @@ -902,8 +902,8 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest · 14 unmodified lines | ||
| 902 | 902 | tracking_id = contact_ids.tracking_id |
| 903 | 903 | slot_num = contact_ids.slot_num |
| 904 | 904 | |
| 905 | − x = 50 + 10 * contact_id + t | |
| 906 | − y = 100 + 100 * contact_id + t | |
| 905 | + x = 50 + 10 * contact_id + t * 11 | |
| 906 | + y = 100 + 100 * contact_id + t * 11 | |
| 907 | 907 | |
| 908 | 908 | # If the data isn't supposed to be stored in any slots, there is |
| 909 | 909 | # nothing we can check for in the evdev stream. |
| @@ -42,17 +42,6 @@ function die() { · 41 unmodified lines | ||
| 42 | 42 | exit 1 |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | −# save existing dmesg so we can detect new content | |
| 46 | −function save_dmesg() { | |
| 47 | − SAVED_DMESG=$(mktemp --tmpdir -t klp-dmesg-XXXXXX) | |
| 48 | − dmesg > "$SAVED_DMESG" | |
| 49 | −} | |
| 50 | − | |
| 51 | −# cleanup temporary dmesg file from save_dmesg() | |
| 52 | −function cleanup_dmesg_file() { | |
| 53 | − rm -f "$SAVED_DMESG" | |
| 54 | −} | |
| 55 | − | |
| 56 | 45 | function push_config() { |
| 57 | 46 | DYNAMIC_DEBUG=$(grep '^kernel/livepatch' /sys/kernel/debug/dynamic_debug/control | \ |
| 58 | 47 | awk -F'[: ]' '{print "file " $1 " line " $2 " " $4}') |
| @@ -99,7 +88,6 @@ function set_ftrace_enabled() { · 40 unmodified lines | ||
| 99 | 88 | |
| 100 | 89 | function cleanup() { |
| 101 | 90 | pop_config |
| 102 | − cleanup_dmesg_file | |
| 103 | 91 | } |
| 104 | 92 | |
| 105 | 93 | # setup_config - save the current config and set a script exit trap that |
| @@ -280,7 +268,15 @@ function set_pre_patch_ret { · 174 unmodified lines | ||
| 280 | 268 | function start_test { |
| 281 | 269 | local test="$1" |
| 282 | 270 | |
| 283 | − save_dmesg | |
| 271 | + # Dump something unique into the dmesg log, then stash the entry | |
| 272 | + # in LAST_DMESG. The check_result() function will use it to | |
| 273 | + # find new kernel messages since the test started. | |
| 274 | + local last_dmesg_msg="livepatch kselftest timestamp: $(date --rfc-3339=ns)" | |
| 275 | + log "$last_dmesg_msg" | |
| 276 | + loop_until 'dmesg | grep -q "$last_dmesg_msg"' || | |
| 277 | + die "buffer busy? can't find canary dmesg message: $last_dmesg_msg" | |
| 278 | + LAST_DMESG=$(dmesg | grep "$last_dmesg_msg") | |
| 279 | + | |
| 284 | 280 | echo -n "TEST: $test ... " |
| 285 | 281 | log "===== TEST: $test =====" |
| 286 | 282 | } |
| @@ -291,23 +287,24 @@ function check_result { · 4 unmodified lines | ||
| 291 | 287 | local expect="$*" |
| 292 | 288 | local result |
| 293 | 289 | |
| 294 | − # Note: when comparing dmesg output, the kernel log timestamps | |
| 295 | − # help differentiate repeated testing runs. Remove them with a | |
| 296 | − # post-comparison sed filter. | |
| 297 | − | |
| 298 | − result=$(dmesg | comm --nocheck-order -13 "$SAVED_DMESG" - | \ | |
| 290 | + # Test results include any new dmesg entry since LAST_DMESG, then: | |
| 291 | + # - include lines matching keywords | |
| 292 | + # - exclude lines matching keywords | |
| 293 | + # - filter out dmesg timestamp prefixes | |
| 294 | + result=$(dmesg | awk -v last_dmesg="$LAST_DMESG" 'p; $0 == last_dmesg { p=1 }' | \ | |
| 299 | 295 | grep -e 'livepatch:' -e 'test_klp' | \ |
| 300 | 296 | grep -v '\(tainting\|taints\) kernel' | \ |
| 301 | 297 | sed 's/^\[[ 0-9.]*\] //') |
| 302 | 298 | |
| 303 | 299 | if [[ "$expect" == "$result" ]] ; then |
| 304 | 300 | echo "ok" |
| 301 | + elif [[ "$result" == "" ]] ; then | |
| 302 | + echo -e "not ok\n\nbuffer overrun? can't find canary dmesg entry: $LAST_DMESG\n" | |
| 303 | + die "livepatch kselftest(s) failed" | |
| 305 | 304 | else |
| 306 | 305 | echo -e "not ok\n\n$(diff -upr --label expected --label result <(echo "$expect") <(echo "$result"))\n" |
| 307 | 306 | die "livepatch kselftest(s) failed" |
| 308 | 307 | fi |
| 309 | − | |
| 310 | − cleanup_dmesg_file | |
| 311 | 308 | } |
| 312 | 309 | |
| 313 | 310 | # check_sysfs_rights(modname, rel_path, expected_rights) - check sysfs |
| @@ -1,4 +1,4 @@ | ||
| 1 | −#!/bin/sh | |
| 1 | +#!/bin/bash | |
| 2 | 2 | # SPDX-License-Identifier: GPL-2.0 |
| 3 | 3 | |
| 4 | 4 | # Kselftest framework requirement - SKIP code is 4. |
| @@ -566,7 +566,7 @@ static int ksm_merge_hugepages_time(int merge_type, int mapping, int prot, · 565 unmodified lines | ||
| 566 | 566 | if (map_ptr_orig == MAP_FAILED) |
| 567 | 567 | err(2, "initial mmap"); |
| 568 | 568 | |
| 569 | − if (madvise(map_ptr, len + HPAGE_SIZE, MADV_HUGEPAGE)) | |
| 569 | + if (madvise(map_ptr, len, MADV_HUGEPAGE)) | |
| 570 | 570 | err(2, "MADV_HUGEPAGE"); |
| 571 | 571 | |
| 572 | 572 | pagemap_fd = open("/proc/self/pagemap", O_RDONLY); |
| @@ -15,6 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | #include <unistd.h> |
| 16 | 16 | #include <sys/mman.h> |
| 17 | 17 | #include <fcntl.h> |
| 18 | +#include "vm_util.h" | |
| 18 | 19 | |
| 19 | 20 | #define LENGTH (256UL*1024*1024) |
| 20 | 21 | #define PROTECTION (PROT_READ | PROT_WRITE) |
| @@ -58,10 +59,16 @@ int main(int argc, char **argv) · 37 unmodified lines | ||
| 58 | 59 | { |
| 59 | 60 | void *addr; |
| 60 | 61 | int ret; |
| 62 | + size_t hugepage_size; | |
| 61 | 63 | size_t length = LENGTH; |
| 62 | 64 | int flags = FLAGS; |
| 63 | 65 | int shift = 0; |
| 64 | 66 | |
| 67 | + hugepage_size = default_huge_page_size(); | |
| 68 | + /* munmap with fail if the length is not page aligned */ | |
| 69 | + if (hugepage_size > length) | |
| 70 | + length = hugepage_size; | |
| 71 | + | |
| 65 | 72 | if (argc > 1) |
| 66 | 73 | length = atol(argv[1]) << 20; |
| 67 | 74 | if (argc > 2) { |
| @@ -360,7 +360,8 @@ static long long remap_region(struct config c, unsigned int threshold_mb, · 359 unmodified lines | ||
| 360 | 360 | char pattern_seed) |
| 361 | 361 | { |
| 362 | 362 | void *addr, *src_addr, *dest_addr, *dest_preamble_addr; |
| 363 | − unsigned long long i; | |
| 363 | + int d; | |
| 364 | + unsigned long long t; | |
| 364 | 365 | struct timespec t_start = {0, 0}, t_end = {0, 0}; |
| 365 | 366 | long long start_ns, end_ns, align_mask, ret, offset; |
| 366 | 367 | unsigned long long threshold; |
| @@ -378,8 +379,8 @@ static long long remap_region(struct config c, unsigned int threshold_mb, · 11 unmodified lines | ||
| 378 | 379 | |
| 379 | 380 | /* Set byte pattern for source block. */ |
| 380 | 381 | srand(pattern_seed); |
| 381 | − for (i = 0; i < threshold; i++) | |
| 382 | − memset((char *) src_addr + i, (char) rand(), 1); | |
| 382 | + for (t = 0; t < threshold; t++) | |
| 383 | + memset((char *) src_addr + t, (char) rand(), 1); | |
| 383 | 384 | |
| 384 | 385 | /* Mask to zero out lower bits of address for alignment */ |
| 385 | 386 | align_mask = ~(c.dest_alignment - 1); |
| @@ -420,8 +421,8 @@ static long long remap_region(struct config c, unsigned int threshold_mb, · 34 unmodified lines | ||
| 420 | 421 | |
| 421 | 422 | /* Set byte pattern for the dest preamble block. */ |
| 422 | 423 | srand(pattern_seed); |
| 423 | − for (i = 0; i < c.dest_preamble_size; i++) | |
| 424 | − memset((char *) dest_preamble_addr + i, (char) rand(), 1); | |
| 424 | + for (d = 0; d < c.dest_preamble_size; d++) | |
| 425 | + memset((char *) dest_preamble_addr + d, (char) rand(), 1); | |
| 425 | 426 | } |
| 426 | 427 | |
| 427 | 428 | clock_gettime(CLOCK_MONOTONIC, &t_start); |
| @@ -437,14 +438,14 @@ static long long remap_region(struct config c, unsigned int threshold_mb, · 9 unmodified lines | ||
| 437 | 438 | |
| 438 | 439 | /* Verify byte pattern after remapping */ |
| 439 | 440 | srand(pattern_seed); |
| 440 | − for (i = 0; i < threshold; i++) { | |
| 441 | + for (t = 0; t < threshold; t++) { | |
| 441 | 442 | char c = (char) rand(); |
| 442 | 443 | |
| 443 | − if (((char *) dest_addr)[i] != c) { | |
| 444 | + if (((char *) dest_addr)[t] != c) { | |
| 444 | 445 | ksft_print_msg("Data after remap doesn't match at offset %llu\n", |
| 445 | − i); | |
| 446 | + t); | |
| 446 | 447 | ksft_print_msg("Expected: %#x\t Got: %#x\n", c & 0xff, |
| 447 | − ((char *) dest_addr)[i] & 0xff); | |
| 448 | + ((char *) dest_addr)[t] & 0xff); | |
| 448 | 449 | ret = -1; |
| 449 | 450 | goto clean_up_dest; |
| 450 | 451 | } |
| @@ -453,14 +454,14 @@ static long long remap_region(struct config c, unsigned int threshold_mb, · 2 unmodified lines | ||
| 453 | 454 | /* Verify the dest preamble byte pattern after remapping */ |
| 454 | 455 | if (c.dest_preamble_size) { |
| 455 | 456 | srand(pattern_seed); |
| 456 | − for (i = 0; i < c.dest_preamble_size; i++) { | |
| 457 | + for (d = 0; d < c.dest_preamble_size; d++) { | |
| 457 | 458 | char c = (char) rand(); |
| 458 | 459 | |
| 459 | − if (((char *) dest_preamble_addr)[i] != c) { | |
| 460 | + if (((char *) dest_preamble_addr)[d] != c) { | |
| 460 | 461 | ksft_print_msg("Preamble data after remap doesn't match at offset %d\n", |
| 461 | − i); | |
| 462 | + d); | |
| 462 | 463 | ksft_print_msg("Expected: %#x\t Got: %#x\n", c & 0xff, |
| 463 | − ((char *) dest_preamble_addr)[i] & 0xff); | |
| 464 | + ((char *) dest_preamble_addr)[d] & 0xff); | |
| 464 | 465 | ret = -1; |
| 465 | 466 | goto clean_up_dest; |
| 466 | 467 | } |
| @@ -29,9 +29,15 @@ check_supported_x86_64() · 28 unmodified lines | ||
| 29 | 29 | # See man 1 gzip under '-f'. |
| 30 | 30 | local pg_table_levels=$(gzip -dcfq "${config}" | grep PGTABLE_LEVELS | cut -d'=' -f 2) |
| 31 | 31 | |
| 32 | + local cpu_supports_pl5=$(awk '/^flags/ {if (/la57/) {print 0;} | |
| 33 | + else {print 1}; exit}' /proc/cpuinfo 2>/dev/null) | |
| 34 | + | |
| 32 | 35 | if [[ "${pg_table_levels}" -lt 5 ]]; then |
| 33 | 36 | echo "$0: PGTABLE_LEVELS=${pg_table_levels}, must be >= 5 to run this test" |
| 34 | 37 | exit $ksft_skip |
| 38 | + elif [[ "${cpu_supports_pl5}" -ne 0 ]]; then | |
| 39 | + echo "$0: CPU does not have the necessary la57 flag to support page table level 5" | |
| 40 | + exit $ksft_skip | |
| 35 | 41 | fi |
| 36 | 42 | } |
| 37 | 43 | |
| @@ -1,4 +1,4 @@ | ||
| 1 | −#!/bin/sh | |
| 1 | +#!/bin/bash | |
| 2 | 2 | # SPDX-License-Identifier: GPL-2.0 |
| 3 | 3 | |
| 4 | 4 | set -e |
| @@ -53,8 +53,7 @@ TEST_PROGS += bind_bhash.sh · 52 unmodified lines | ||
| 53 | 53 | TEST_PROGS += ip_local_port_range.sh |
| 54 | 54 | TEST_PROGS += rps_default_mask.sh |
| 55 | 55 | TEST_PROGS += big_tcp.sh |
| 56 | −TEST_PROGS_EXTENDED := in_netns.sh setup_loopback.sh setup_veth.sh | |
| 57 | −TEST_PROGS_EXTENDED += toeplitz_client.sh toeplitz.sh lib.sh | |
| 56 | +TEST_PROGS_EXTENDED := toeplitz_client.sh toeplitz.sh | |
| 58 | 57 | TEST_GEN_FILES = socket nettest |
| 59 | 58 | TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy reuseport_addr_any |
| 60 | 59 | TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd txring_overwrite |
| @@ -84,6 +83,7 @@ TEST_PROGS += sctp_vrf.sh · 23 unmodified lines | ||
| 84 | 83 | TEST_GEN_FILES += sctp_hello |
| 85 | 84 | TEST_GEN_FILES += csum |
| 86 | 85 | TEST_GEN_FILES += nat6to4.o |
| 86 | +TEST_GEN_FILES += xdp_dummy.o | |
| 87 | 87 | TEST_GEN_FILES += ip_local_port_range |
| 88 | 88 | TEST_GEN_FILES += bind_wildcard |
| 89 | 89 | TEST_PROGS += test_vxlan_mdb.sh |
| @@ -95,6 +95,7 @@ TEST_PROGS += fq_band_pktlimit.sh · 5 unmodified lines | ||
| 95 | 95 | TEST_PROGS += vlan_hw_filter.sh |
| 96 | 96 | |
| 97 | 97 | TEST_FILES := settings |
| 98 | +TEST_FILES += in_netns.sh lib.sh net_helper.sh setup_loopback.sh setup_veth.sh | |
| 98 | 99 | |
| 99 | 100 | include ../lib.mk |
| 100 | 101 | |
| @@ -104,7 +105,7 @@ $(OUTPUT)/tcp_inq: LDLIBS += -lpthread · 3 unmodified lines | ||
| 104 | 105 | $(OUTPUT)/bind_bhash: LDLIBS += -lpthread |
| 105 | 106 | $(OUTPUT)/io_uring_zerocopy_tx: CFLAGS += -I../../../include/ |
| 106 | 107 | |
| 107 | −# Rules to generate bpf obj nat6to4.o | |
| 108 | +# Rules to generate bpf objs | |
| 108 | 109 | CLANG ?= clang |
| 109 | 110 | SCRATCH_DIR := $(OUTPUT)/tools |
| 110 | 111 | BUILD_DIR := $(SCRATCH_DIR)/build |
| @@ -139,7 +140,7 @@ endif · 28 unmodified lines | ||
| 139 | 140 | |
| 140 | 141 | CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG),$(CLANG_TARGET_ARCH)) |
| 141 | 142 | |
| 142 | −$(OUTPUT)/nat6to4.o: nat6to4.c $(BPFOBJ) | $(MAKE_DIRS) | |
| 143 | +$(OUTPUT)/nat6to4.o $(OUTPUT)/xdp_dummy.o: $(OUTPUT)/%.o : %.c $(BPFOBJ) | $(MAKE_DIRS) | |
| 143 | 144 | $(CLANG) -O2 --target=bpf -c $< $(CCINCLUDE) $(CLANG_SYS_INCLUDES) -o $@ |
| 144 | 145 | |
| 145 | 146 | $(BPFOBJ): $(wildcard $(BPFDIR)/*.[ch] $(BPFDIR)/Makefile) \ |
| @@ -19,8 +19,11 @@ CONFIG_BRIDGE_VLAN_FILTERING=y · 18 unmodified lines | ||
| 19 | 19 | CONFIG_BRIDGE=y |
| 20 | 20 | CONFIG_CRYPTO_CHACHA20POLY1305=m |
| 21 | 21 | CONFIG_VLAN_8021Q=y |
| 22 | +CONFIG_GENEVE=m | |
| 22 | 23 | CONFIG_IFB=y |
| 23 | 24 | CONFIG_INET_DIAG=y |
| 25 | +CONFIG_INET_ESP=y | |
| 26 | +CONFIG_INET_ESP_OFFLOAD=y | |
| 24 | 27 | CONFIG_IP_GRE=m |
| 25 | 28 | CONFIG_NETFILTER=y |
| 26 | 29 | CONFIG_NETFILTER_ADVANCED=y |
| @@ -29,7 +32,10 @@ CONFIG_NF_NAT=m · 2 unmodified lines | ||
| 29 | 32 | CONFIG_IP6_NF_IPTABLES=m |
| 30 | 33 | CONFIG_IP_NF_IPTABLES=m |
| 31 | 34 | CONFIG_IP6_NF_NAT=m |
| 35 | +CONFIG_IP6_NF_RAW=m | |
| 32 | 36 | CONFIG_IP_NF_NAT=m |
| 37 | +CONFIG_IP_NF_RAW=m | |
| 38 | +CONFIG_IP_NF_TARGET_TTL=m | |
| 33 | 39 | CONFIG_IPV6_GRE=m |
| 34 | 40 | CONFIG_IPV6_SEG6_LWTUNNEL=y |
| 35 | 41 | CONFIG_L2TP_ETH=m |
| @@ -45,8 +51,14 @@ CONFIG_NF_TABLES=m · 9 unmodified lines | ||
| 45 | 51 | CONFIG_NF_TABLES_IPV6=y |
| 46 | 52 | CONFIG_NF_TABLES_IPV4=y |
| 47 | 53 | CONFIG_NFT_NAT=m |
| 54 | +CONFIG_NETFILTER_XT_MATCH_LENGTH=m | |
| 55 | +CONFIG_NET_ACT_CSUM=m | |
| 56 | +CONFIG_NET_ACT_CT=m | |
| 48 | 57 | CONFIG_NET_ACT_GACT=m |
| 58 | +CONFIG_NET_ACT_PEDIT=m | |
| 49 | 59 | CONFIG_NET_CLS_BASIC=m |
| 60 | +CONFIG_NET_CLS_BPF=m | |
| 61 | +CONFIG_NET_CLS_MATCHALL=m | |
| 50 | 62 | CONFIG_NET_CLS_U32=m |
| 51 | 63 | CONFIG_NET_IPGRE_DEMUX=m |
| 52 | 64 | CONFIG_NET_IPGRE=m |
| @@ -55,6 +67,9 @@ CONFIG_NET_SCH_HTB=m · 2 unmodified lines | ||
| 55 | 67 | CONFIG_NET_SCH_FQ=m |
| 56 | 68 | CONFIG_NET_SCH_ETF=m |
| 57 | 69 | CONFIG_NET_SCH_NETEM=y |
| 70 | +CONFIG_NET_SCH_PRIO=m | |
| 71 | +CONFIG_NFT_COMPAT=m | |
| 72 | +CONFIG_NF_FLOW_TABLE=m | |
| 58 | 73 | CONFIG_PSAMPLE=m |
| 59 | 74 | CONFIG_TCP_MD5SIG=y |
| 60 | 75 | CONFIG_TEST_BLACKHOLE_DEV=m |
| @@ -80,3 +95,4 @@ CONFIG_IP_SCTP=m · 19 unmodified lines | ||
| 80 | 95 | CONFIG_NETFILTER_XT_MATCH_POLICY=m |
| 81 | 96 | CONFIG_CRYPTO_ARIA=y |
| 82 | 97 | CONFIG_XFRM_INTERFACE=m |
| 98 | +CONFIG_XFRM_USER=m | |
| @@ -112,7 +112,7 @@ TEST_PROGS = bridge_fdb_learning_limit.sh \ · 111 unmodified lines | ||
| 112 | 112 | vxlan_symmetric_ipv6.sh \ |
| 113 | 113 | vxlan_symmetric.sh |
| 114 | 114 | |
| 115 | −TEST_PROGS_EXTENDED := devlink_lib.sh \ | |
| 115 | +TEST_FILES := devlink_lib.sh \ | |
| 116 | 116 | ethtool_lib.sh \ |
| 117 | 117 | fib_offload_lib.sh \ |
| 118 | 118 | forwarding.config.sample \ |
| @@ -4,6 +4,9 @@ · 3 unmodified lines | ||
| 4 | 4 | ############################################################################## |
| 5 | 5 | # Defines |
| 6 | 6 | |
| 7 | +WAIT_TIMEOUT=${WAIT_TIMEOUT:=20} | |
| 8 | +BUSYWAIT_TIMEOUT=$((WAIT_TIMEOUT * 1000)) # ms | |
| 9 | + | |
| 7 | 10 | # Kselftest framework requirement - SKIP code is 4. |
| 8 | 11 | ksft_skip=4 |
| 9 | 12 | # namespace list created by setup_ns |
| @@ -48,7 +51,7 @@ cleanup_ns() · 38 unmodified lines | ||
| 48 | 51 | |
| 49 | 52 | for ns in "$@"; do |
| 50 | 53 | ip netns delete "${ns}" &> /dev/null |
| 51 | − if ! busywait 2 ip netns list \| grep -vq "^$ns$" &> /dev/null; then | |
| 54 | + if ! busywait $BUSYWAIT_TIMEOUT ip netns list \| grep -vq "^$ns$" &> /dev/null; then | |
| 52 | 55 | echo "Warn: Failed to remove namespace $ns" |
| 53 | 56 | ret=1 |
| 54 | 57 | fi |
| @@ -22,8 +22,11 @@ CONFIG_NFT_TPROXY=m · 21 unmodified lines | ||
| 22 | 22 | CONFIG_NFT_SOCKET=m |
| 23 | 23 | CONFIG_IP_ADVANCED_ROUTER=y |
| 24 | 24 | CONFIG_IP_MULTIPLE_TABLES=y |
| 25 | +CONFIG_IP_NF_FILTER=m | |
| 26 | +CONFIG_IP_NF_MANGLE=m | |
| 25 | 27 | CONFIG_IP_NF_TARGET_REJECT=m |
| 26 | 28 | CONFIG_IPV6_MULTIPLE_TABLES=y |
| 29 | +CONFIG_IP6_NF_FILTER=m | |
| 27 | 30 | CONFIG_NET_ACT_CSUM=m |
| 28 | 31 | CONFIG_NET_ACT_PEDIT=m |
| 29 | 32 | CONFIG_NET_CLS_ACT=y |
| @@ -643,13 +643,6 @@ kill_events_pids() · 642 unmodified lines | ||
| 643 | 643 | mptcp_lib_kill_wait $evts_ns2_pid |
| 644 | 644 | } |
| 645 | 645 | |
| 646 | −kill_tests_wait() | |
| 647 | −{ | |
| 648 | − #shellcheck disable=SC2046 | |
| 649 | − kill -SIGUSR1 $(ip netns pids $ns2) $(ip netns pids $ns1) | |
| 650 | − wait | |
| 651 | −} | |
| 652 | − | |
| 653 | 646 | pm_nl_set_limits() |
| 654 | 647 | { |
| 655 | 648 | local ns=$1 |
| @@ -3453,7 +3446,7 @@ userspace_tests() · 2797 unmodified lines | ||
| 3453 | 3446 | chk_mptcp_info subflows 0 subflows 0 |
| 3454 | 3447 | chk_subflows_total 1 1 |
| 3455 | 3448 | kill_events_pids |
| 3456 | − wait $tests_pid | |
| 3449 | + mptcp_lib_kill_wait $tests_pid | |
| 3457 | 3450 | fi |
| 3458 | 3451 | |
| 3459 | 3452 | # userspace pm create destroy subflow |
| @@ -3475,7 +3468,7 @@ userspace_tests() · 15 unmodified lines | ||
| 3475 | 3468 | chk_mptcp_info subflows 0 subflows 0 |
| 3476 | 3469 | chk_subflows_total 1 1 |
| 3477 | 3470 | kill_events_pids |
| 3478 | − wait $tests_pid | |
| 3471 | + mptcp_lib_kill_wait $tests_pid | |
| 3479 | 3472 | fi |
| 3480 | 3473 | |
| 3481 | 3474 | # userspace pm create id 0 subflow |
| @@ -3494,7 +3487,7 @@ userspace_tests() · 12 unmodified lines | ||
| 3494 | 3487 | chk_mptcp_info subflows 1 subflows 1 |
| 3495 | 3488 | chk_subflows_total 2 2 |
| 3496 | 3489 | kill_events_pids |
| 3497 | − wait $tests_pid | |
| 3490 | + mptcp_lib_kill_wait $tests_pid | |
| 3498 | 3491 | fi |
| 3499 | 3492 | |
| 3500 | 3493 | # userspace pm remove initial subflow |
| @@ -3518,7 +3511,7 @@ userspace_tests() · 17 unmodified lines | ||
| 3518 | 3511 | chk_mptcp_info subflows 1 subflows 1 |
| 3519 | 3512 | chk_subflows_total 1 1 |
| 3520 | 3513 | kill_events_pids |
| 3521 | − wait $tests_pid | |
| 3514 | + mptcp_lib_kill_wait $tests_pid | |
| 3522 | 3515 | fi |
| 3523 | 3516 | |
| 3524 | 3517 | # userspace pm send RM_ADDR for ID 0 |
| @@ -3544,7 +3537,7 @@ userspace_tests() · 19 unmodified lines | ||
| 3544 | 3537 | chk_mptcp_info subflows 1 subflows 1 |
| 3545 | 3538 | chk_subflows_total 1 1 |
| 3546 | 3539 | kill_events_pids |
| 3547 | − wait $tests_pid | |
| 3540 | + mptcp_lib_kill_wait $tests_pid | |
| 3548 | 3541 | fi |
| 3549 | 3542 | } |
| 3550 | 3543 | |
| @@ -3558,7 +3551,8 @@ endpoint_tests() · 7 unmodified lines | ||
| 3558 | 3551 | pm_nl_set_limits $ns2 2 2 |
| 3559 | 3552 | pm_nl_add_endpoint $ns1 10.0.2.1 flags signal |
| 3560 | 3553 | speed=slow \ |
| 3561 | − run_tests $ns1 $ns2 10.0.1.1 2>/dev/null & | |
| 3554 | + run_tests $ns1 $ns2 10.0.1.1 & | |
| 3555 | + local tests_pid=$! | |
| 3562 | 3556 | |
| 3563 | 3557 | wait_mpj $ns1 |
| 3564 | 3558 | pm_nl_check_endpoint "creation" \ |
| @@ -3573,7 +3567,7 @@ endpoint_tests() · 8 unmodified lines | ||
| 3573 | 3567 | pm_nl_add_endpoint $ns2 10.0.2.2 flags signal |
| 3574 | 3568 | pm_nl_check_endpoint "modif is allowed" \ |
| 3575 | 3569 | $ns2 10.0.2.2 id 1 flags signal |
| 3576 | − kill_tests_wait | |
| 3570 | + mptcp_lib_kill_wait $tests_pid | |
| 3577 | 3571 | fi |
| 3578 | 3572 | |
| 3579 | 3573 | if reset "delete and re-add" && |
| @@ -3582,7 +3576,8 @@ endpoint_tests() · 2 unmodified lines | ||
| 3582 | 3576 | pm_nl_set_limits $ns2 1 1 |
| 3583 | 3577 | pm_nl_add_endpoint $ns2 10.0.2.2 id 2 dev ns2eth2 flags subflow |
| 3584 | 3578 | test_linkfail=4 speed=20 \ |
| 3585 | − run_tests $ns1 $ns2 10.0.1.1 2>/dev/null & | |
| 3579 | + run_tests $ns1 $ns2 10.0.1.1 & | |
| 3580 | + local tests_pid=$! | |
| 3586 | 3581 | |
| 3587 | 3582 | wait_mpj $ns2 |
| 3588 | 3583 | chk_subflow_nr "before delete" 2 |
| @@ -3597,7 +3592,7 @@ endpoint_tests() · 8 unmodified lines | ||
| 3597 | 3592 | wait_mpj $ns2 |
| 3598 | 3593 | chk_subflow_nr "after re-add" 2 |
| 3599 | 3594 | chk_mptcp_info subflows 1 subflows 1 |
| 3600 | − kill_tests_wait | |
| 3595 | + mptcp_lib_kill_wait $tests_pid | |
| 3601 | 3596 | fi |
| 3602 | 3597 | } |
| 3603 | 3598 | |
| @@ -6,7 +6,7 @@ readonly KSFT_FAIL=1 · 5 unmodified lines | ||
| 6 | 6 | readonly KSFT_SKIP=4 |
| 7 | 7 | |
| 8 | 8 | # shellcheck disable=SC2155 # declare and assign separately |
| 9 | −readonly KSFT_TEST=$(basename "${0}" | sed 's/\.sh$//g') | |
| 9 | +readonly KSFT_TEST="${MPTCP_LIB_KSFT_TEST:-$(basename "${0}" .sh)}" | |
| 10 | 10 | |
| 11 | 11 | MPTCP_LIB_SUBTESTS=() |
| 12 | 12 | |
| @@ -1 +1 @@ | ||
| 1 | −timeout=1200 | |
| 1 | +timeout=1800 | |
| @@ -284,12 +284,12 @@ done · 283 unmodified lines | ||
| 284 | 284 | |
| 285 | 285 | setup |
| 286 | 286 | run_test 10 10 0 0 "balanced bwidth" |
| 287 | −run_test 10 10 1 50 "balanced bwidth with unbalanced delay" | |
| 287 | +run_test 10 10 1 25 "balanced bwidth with unbalanced delay" | |
| 288 | 288 | |
| 289 | 289 | # we still need some additional infrastructure to pass the following test-cases |
| 290 | −run_test 30 10 0 0 "unbalanced bwidth" | |
| 291 | −run_test 30 10 1 50 "unbalanced bwidth with unbalanced delay" | |
| 292 | −run_test 30 10 50 1 "unbalanced bwidth with opposed, unbalanced delay" | |
| 290 | +run_test 10 3 0 0 "unbalanced bwidth" | |
| 291 | +run_test 10 3 1 25 "unbalanced bwidth with unbalanced delay" | |
| 292 | +run_test 10 3 25 1 "unbalanced bwidth with opposed, unbalanced delay" | |
| 293 | 293 | |
| 294 | 294 | mptcp_lib_result_print_all_tap |
| 295 | 295 | exit $ret |
File mode changed from 100755 to 100644.
| @@ -707,23 +707,23 @@ setup_xfrm6() { · 706 unmodified lines | ||
| 707 | 707 | } |
| 708 | 708 | |
| 709 | 709 | setup_xfrm4udp() { |
| 710 | − setup_xfrm 4 ${veth4_a_addr} ${veth4_b_addr} "encap espinudp 4500 4500 0.0.0.0" | |
| 711 | − setup_nettest_xfrm 4 4500 | |
| 710 | + setup_xfrm 4 ${veth4_a_addr} ${veth4_b_addr} "encap espinudp 4500 4500 0.0.0.0" && \ | |
| 711 | + setup_nettest_xfrm 4 4500 | |
| 712 | 712 | } |
| 713 | 713 | |
| 714 | 714 | setup_xfrm6udp() { |
| 715 | − setup_xfrm 6 ${veth6_a_addr} ${veth6_b_addr} "encap espinudp 4500 4500 0.0.0.0" | |
| 716 | − setup_nettest_xfrm 6 4500 | |
| 715 | + setup_xfrm 6 ${veth6_a_addr} ${veth6_b_addr} "encap espinudp 4500 4500 0.0.0.0" && \ | |
| 716 | + setup_nettest_xfrm 6 4500 | |
| 717 | 717 | } |
| 718 | 718 | |
| 719 | 719 | setup_xfrm4udprouted() { |
| 720 | − setup_xfrm 4 ${prefix4}.${a_r1}.1 ${prefix4}.${b_r1}.1 "encap espinudp 4500 4500 0.0.0.0" | |
| 721 | − setup_nettest_xfrm 4 4500 | |
| 720 | + setup_xfrm 4 ${prefix4}.${a_r1}.1 ${prefix4}.${b_r1}.1 "encap espinudp 4500 4500 0.0.0.0" && \ | |
| 721 | + setup_nettest_xfrm 4 4500 | |
| 722 | 722 | } |
| 723 | 723 | |
| 724 | 724 | setup_xfrm6udprouted() { |
| 725 | − setup_xfrm 6 ${prefix6}:${a_r1}::1 ${prefix6}:${b_r1}::1 "encap espinudp 4500 4500 0.0.0.0" | |
| 726 | − setup_nettest_xfrm 6 4500 | |
| 725 | + setup_xfrm 6 ${prefix6}:${a_r1}::1 ${prefix6}:${b_r1}::1 "encap espinudp 4500 4500 0.0.0.0" && \ | |
| 726 | + setup_nettest_xfrm 6 4500 | |
| 727 | 727 | } |
| 728 | 728 | |
| 729 | 729 | setup_routing_old() { |
| @@ -1339,7 +1339,7 @@ test_pmtu_ipvX_over_bridged_vxlanY_or_geneveY_exception() { · 609 unmodified lines | ||
| 1339 | 1339 | |
| 1340 | 1340 | sleep 1 |
| 1341 | 1341 | |
| 1342 | − dd if=/dev/zero of=/dev/stdout status=none bs=1M count=1 | ${target} socat -T 3 -u STDIN $TCPDST,connect-timeout=3 | |
| 1342 | + dd if=/dev/zero status=none bs=1M count=1 | ${target} socat -T 3 -u STDIN $TCPDST,connect-timeout=3 | |
| 1343 | 1343 | |
| 1344 | 1344 | size=$(du -sb $tmpoutfile) |
| 1345 | 1345 | size=${size%%/tmp/*} |
File mode changed from 100755 to 100644.
| @@ -11,7 +11,7 @@ setup_veth_ns() { · 10 unmodified lines | ||
| 11 | 11 | local -r ns_mac="$4" |
| 12 | 12 | |
| 13 | 13 | [[ -e /var/run/netns/"${ns_name}" ]] || ip netns add "${ns_name}" |
| 14 | − echo 100000 > "/sys/class/net/${ns_dev}/gro_flush_timeout" | |
| 14 | + echo 1000000 > "/sys/class/net/${ns_dev}/gro_flush_timeout" | |
| 15 | 15 | ip link set dev "${ns_dev}" netns "${ns_name}" mtu 65535 |
| 16 | 16 | ip -netns "${ns_name}" link set dev "${ns_dev}" up |
| 17 | 17 | |
| @@ -0,0 +1,10 @@ | ||
| 1 | +CONFIG_CRYPTO_HMAC=y | |
| 2 | +CONFIG_CRYPTO_RMD160=y | |
| 3 | +CONFIG_CRYPTO_SHA1=y | |
| 4 | +CONFIG_IPV6_MULTIPLE_TABLES=y | |
| 5 | +CONFIG_IPV6=y | |
| 6 | +CONFIG_NET_L3_MASTER_DEV=y | |
| 7 | +CONFIG_NET_VRF=y | |
| 8 | +CONFIG_TCP_AO=y | |
| 9 | +CONFIG_TCP_MD5SIG=y | |
| 10 | +CONFIG_VETH=m | |
| @@ -417,9 +417,9 @@ struct test_key { · 416 unmodified lines | ||
| 417 | 417 | matches_vrf : 1, |
| 418 | 418 | is_current : 1, |
| 419 | 419 | is_rnext : 1, |
| 420 | − used_on_handshake : 1, | |
| 421 | − used_after_accept : 1, | |
| 422 | − used_on_client : 1; | |
| 420 | + used_on_server_tx : 1, | |
| 421 | + used_on_client_tx : 1, | |
| 422 | + skip_counters_checks : 1; | |
| 423 | 423 | }; |
| 424 | 424 | |
| 425 | 425 | struct key_collection { |
| @@ -609,16 +609,14 @@ static int key_collection_socket(bool server, unsigned int port) · 183 unmodified lines | ||
| 609 | 609 | addr = &this_ip_dest; |
| 610 | 610 | sndid = key->client_keyid; |
| 611 | 611 | rcvid = key->server_keyid; |
| 612 | − set_current = key->is_current; | |
| 613 | − set_rnext = key->is_rnext; | |
| 612 | + key->used_on_client_tx = set_current = key->is_current; | |
| 613 | + key->used_on_server_tx = set_rnext = key->is_rnext; | |
| 614 | 614 | } |
| 615 | 615 | |
| 616 | 616 | if (test_add_key_cr(sk, key->password, key->len, |
| 617 | 617 | *addr, vrf, sndid, rcvid, key->maclen, |
| 618 | 618 | key->alg, set_current, set_rnext)) |
| 619 | 619 | test_key_error("setsockopt(TCP_AO_ADD_KEY)", key); |
| 620 | − if (set_current || set_rnext) | |
| 621 | − key->used_on_handshake = 1; | |
| 622 | 620 | #ifdef DEBUG |
| 623 | 621 | test_print("%s [%u/%u] key: { %s, %u:%u, %u, %u:%u:%u:%u (%u)}", |
| 624 | 622 | server ? "server" : "client", i, collection.nr_keys, |
| @@ -640,22 +638,22 @@ static void verify_counters(const char *tst_name, bool is_listen_sk, bool server · 15 unmodified lines | ||
| 640 | 638 | for (i = 0; i < collection.nr_keys; i++) { |
| 641 | 639 | struct test_key *key = &collection.keys[i]; |
| 642 | 640 | uint8_t sndid, rcvid; |
| 643 | − bool was_used; | |
| 641 | + bool rx_cnt_expected; | |
| 644 | 642 | |
| 643 | + if (key->skip_counters_checks) | |
| 644 | + continue; | |
| 645 | 645 | if (server) { |
| 646 | 646 | sndid = key->server_keyid; |
| 647 | 647 | rcvid = key->client_keyid; |
| 648 | − if (is_listen_sk) | |
| 649 | − was_used = key->used_on_handshake; | |
| 650 | − else | |
| 651 | − was_used = key->used_after_accept; | |
| 648 | + rx_cnt_expected = key->used_on_client_tx; | |
| 652 | 649 | } else { |
| 653 | 650 | sndid = key->client_keyid; |
| 654 | 651 | rcvid = key->server_keyid; |
| 655 | − was_used = key->used_on_client; | |
| 652 | + rx_cnt_expected = key->used_on_server_tx; | |
| 656 | 653 | } |
| 657 | 654 | |
| 658 | − test_tcp_ao_key_counters_cmp(tst_name, a, b, was_used, | |
| 655 | + test_tcp_ao_key_counters_cmp(tst_name, a, b, | |
| 656 | + rx_cnt_expected ? TEST_CNT_KEY_GOOD : 0, | |
| 659 | 657 | sndid, rcvid); |
| 660 | 658 | } |
| 661 | 659 | test_tcp_ao_counters_free(a); |
| @@ -843,7 +841,7 @@ static void end_server(const char *tst_name, int sk, · 181 unmodified lines | ||
| 843 | 841 | synchronize_threads(); /* 4: verified => closed */ |
| 844 | 842 | close(sk); |
| 845 | 843 | |
| 846 | − verify_counters(tst_name, true, false, begin, &end); | |
| 844 | + verify_counters(tst_name, false, true, begin, &end); | |
| 847 | 845 | synchronize_threads(); /* 5: counters */ |
| 848 | 846 | } |
| 849 | 847 | |
| @@ -916,9 +914,8 @@ static int run_client(const char *tst_name, unsigned int port, · 66 unmodified lines | ||
| 916 | 914 | current_index = nr_keys - 1; |
| 917 | 915 | if (rnext_index < 0) |
| 918 | 916 | rnext_index = nr_keys - 1; |
| 919 | − collection.keys[current_index].used_on_handshake = 1; | |
| 920 | − collection.keys[rnext_index].used_after_accept = 1; | |
| 921 | − collection.keys[rnext_index].used_on_client = 1; | |
| 917 | + collection.keys[current_index].used_on_client_tx = 1; | |
| 918 | + collection.keys[rnext_index].used_on_server_tx = 1; | |
| 922 | 919 | |
| 923 | 920 | synchronize_threads(); /* 3: accepted => send data */ |
| 924 | 921 | if (test_client_verify(sk, msg_sz, msg_nr, TEST_TIMEOUT_SEC)) { |
| @@ -1059,7 +1056,16 @@ static void check_current_back(const char *tst_name, unsigned int port, · 134 unmodified lines | ||
| 1059 | 1056 | test_error("Can't change the current key"); |
| 1060 | 1057 | if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC)) |
| 1061 | 1058 | test_fail("verify failed"); |
| 1062 | − collection.keys[rotate_to_index].used_after_accept = 1; | |
| 1059 | + /* There is a race here: between setting the current_key with | |
| 1060 | + * setsockopt(TCP_AO_INFO) and starting to send some data - there | |
| 1061 | + * might have been a segment received with the desired | |
| 1062 | + * RNext_key set. In turn that would mean that the first outgoing | |
| 1063 | + * segment will have the desired current_key (flipped back). | |
| 1064 | + * Which is what the user/test wants. As it's racy, skip checking | |
| 1065 | + * the counters, yet check what are the resulting current/rnext | |
| 1066 | + * keys on both sides. | |
| 1067 | + */ | |
| 1068 | + collection.keys[rotate_to_index].skip_counters_checks = 1; | |
| 1063 | 1069 | |
| 1064 | 1070 | end_client(tst_name, sk, nr_keys, current_index, rnext_index, &tmp); |
| 1065 | 1071 | } |
| @@ -1089,7 +1095,7 @@ static void roll_over_keys(const char *tst_name, unsigned int port, · 23 unmodified lines | ||
| 1089 | 1095 | } |
| 1090 | 1096 | verify_current_rnext(tst_name, sk, -1, |
| 1091 | 1097 | collection.keys[i].server_keyid); |
| 1092 | − collection.keys[i].used_on_client = 1; | |
| 1098 | + collection.keys[i].used_on_server_tx = 1; | |
| 1093 | 1099 | synchronize_threads(); /* verify current/rnext */ |
| 1094 | 1100 | } |
| 1095 | 1101 | end_client(tst_name, sk, nr_keys, current_index, rnext_index, &tmp); |
| @@ -62,7 +62,9 @@ int test_wait_fd(int sk, time_t sec, bool write) · 61 unmodified lines | ||
| 62 | 62 | return -ETIMEDOUT; |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | − if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &slen) || ret) | |
| 65 | + if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &slen)) | |
| 66 | + return -errno; | |
| 67 | + if (ret) | |
| 66 | 68 | return -ret; |
| 67 | 69 | return 0; |
| 68 | 70 | } |
| @@ -584,9 +586,11 @@ int test_client_verify(int sk, const size_t msg_len, const size_t nr, · 515 unmodified lines | ||
| 584 | 586 | { |
| 585 | 587 | size_t buf_sz = msg_len * nr; |
| 586 | 588 | char *buf = alloca(buf_sz); |
| 589 | + ssize_t ret; | |
| 587 | 590 | |
| 588 | 591 | randomize_buffer(buf, buf_sz); |
| 589 | − if (test_client_loop(sk, buf, buf_sz, msg_len, timeout_sec) != buf_sz) | |
| 590 | − return -1; | |
| 591 | − return 0; | |
| 592 | + ret = test_client_loop(sk, buf, buf_sz, msg_len, timeout_sec); | |
| 593 | + if (ret < 0) | |
| 594 | + return (int)ret; | |
| 595 | + return ret != buf_sz ? -1 : 0; | |
| 592 | 596 | } |
| @@ -1,10 +1,33 @@ | ||
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | −/* Author: Dmitry Safonov <dima@arista.com> */ | |
| 2 | +/* | |
| 3 | + * The test checks that both active and passive reset have correct TCP-AO | |
| 4 | + * signature. An "active" reset (abort) here is procured from closing | |
| 5 | + * listen() socket with non-accepted connections in the queue: | |
| 6 | + * inet_csk_listen_stop() => inet_child_forget() => | |
| 7 | + * => tcp_disconnect() => tcp_send_active_reset() | |
| 8 | + * | |
| 9 | + * The passive reset is quite hard to get on established TCP connections. | |
| 10 | + * It could be procured from non-established states, but the synchronization | |
| 11 | + * part from userspace in order to reliably get RST seems uneasy. | |
| 12 | + * So, instead it's procured by corrupting SEQ number on TIMED-WAIT state. | |
| 13 | + * | |
| 14 | + * It's important to test both passive and active RST as they go through | |
| 15 | + * different code-paths: | |
| 16 | + * - tcp_send_active_reset() makes no-data skb, sends it with tcp_transmit_skb() | |
| 17 | + * - tcp_v*_send_reset() create their reply skbs and send them with | |
| 18 | + * ip_send_unicast_reply() | |
| 19 | + * | |
| 20 | + * In both cases TCP-AO signatures have to be correct, which is verified by | |
| 21 | + * (1) checking that the TCP-AO connection was reset and (2) TCP-AO counters. | |
| 22 | + * | |
| 23 | + * Author: Dmitry Safonov <dima@arista.com> | |
| 24 | + */ | |
| 3 | 25 | #include <inttypes.h> |
| 4 | 26 | #include "../../../../include/linux/kernel.h" |
| 5 | 27 | #include "aolib.h" |
| 6 | 28 | |
| 7 | 29 | const size_t quota = 1000; |
| 30 | +const size_t packet_sz = 100; | |
| 8 | 31 | /* |
| 9 | 32 | * Backlog == 0 means 1 connection in queue, see: |
| 10 | 33 | * commit 64a146513f8f ("[NET]: Revert incorrect accept queue...") |
| @@ -59,26 +82,6 @@ static void close_forced(int sk) · 48 unmodified lines | ||
| 59 | 82 | close(sk); |
| 60 | 83 | } |
| 61 | 84 | |
| 62 | −static int test_wait_for_exception(int sk, time_t sec) | |
| 63 | −{ | |
| 64 | − struct timeval tv = { .tv_sec = sec }; | |
| 65 | − struct timeval *ptv = NULL; | |
| 66 | − fd_set efds; | |
| 67 | − int ret; | |
| 68 | − | |
| 69 | − FD_ZERO(&efds); | |
| 70 | − FD_SET(sk, &efds); | |
| 71 | − | |
| 72 | − if (sec) | |
| 73 | − ptv = &tv; | |
| 74 | − | |
| 75 | − errno = 0; | |
| 76 | − ret = select(sk + 1, NULL, NULL, &efds, ptv); | |
| 77 | − if (ret < 0) | |
| 78 | − return -errno; | |
| 79 | − return ret ? sk : 0; | |
| 80 | −} | |
| 81 | − | |
| 82 | 85 | static void test_server_active_rst(unsigned int port) |
| 83 | 86 | { |
| 84 | 87 | struct tcp_ao_counters cnt1, cnt2; |
| @@ -155,17 +158,16 @@ static void test_server_passive_rst(unsigned int port) · 70 unmodified lines | ||
| 155 | 158 | test_fail("server returned %zd", bytes); |
| 156 | 159 | } |
| 157 | 160 | |
| 158 | − synchronize_threads(); /* 3: chekpoint/restore the connection */ | |
| 161 | + synchronize_threads(); /* 3: checkpoint the client */ | |
| 162 | + synchronize_threads(); /* 4: close the server, creating twsk */ | |
| 159 | 163 | if (test_get_tcp_ao_counters(sk, &ao2)) |
| 160 | 164 | test_error("test_get_tcp_ao_counters()"); |
| 161 | − | |
| 162 | − synchronize_threads(); /* 4: terminate server + send more on client */ | |
| 163 | − bytes = test_server_run(sk, quota, TEST_RETRANSMIT_SEC); | |
| 164 | 165 | close(sk); |
| 166 | + | |
| 167 | + synchronize_threads(); /* 5: restore the socket, send more data */ | |
| 165 | 168 | test_tcp_ao_counters_cmp("passive RST server", &ao1, &ao2, TEST_CNT_GOOD); |
| 166 | 169 | |
| 167 | − synchronize_threads(); /* 5: verified => closed */ | |
| 168 | − close(sk); | |
| 170 | + synchronize_threads(); /* 6: server exits */ | |
| 169 | 171 | } |
| 170 | 172 | |
| 171 | 173 | static void *server_fn(void *arg) |
| @@ -284,7 +286,7 @@ static void test_client_active_rst(unsigned int port) · 112 unmodified lines | ||
| 284 | 286 | test_error("test_wait_fds(): %d", err); |
| 285 | 287 | |
| 286 | 288 | synchronize_threads(); /* 3: close listen socket */ |
| 287 | − if (test_client_verify(sk[0], 100, quota / 100, TEST_TIMEOUT_SEC)) | |
| 289 | + if (test_client_verify(sk[0], packet_sz, quota / packet_sz, TEST_TIMEOUT_SEC)) | |
| 288 | 290 | test_fail("Failed to send data on connected socket"); |
| 289 | 291 | else |
| 290 | 292 | test_ok("Verified established tcp connection"); |
| @@ -323,7 +325,6 @@ static void test_client_passive_rst(unsigned int port) · 32 unmodified lines | ||
| 323 | 325 | struct tcp_sock_state img; |
| 324 | 326 | sockaddr_af saddr; |
| 325 | 327 | int sk, err; |
| 326 | − socklen_t slen = sizeof(err); | |
| 327 | 328 | |
| 328 | 329 | sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP); |
| 329 | 330 | if (sk < 0) |
| @@ -337,18 +338,51 @@ static void test_client_passive_rst(unsigned int port) · 7 unmodified lines | ||
| 337 | 338 | test_error("failed to connect()"); |
| 338 | 339 | |
| 339 | 340 | synchronize_threads(); /* 2: accepted => send data */ |
| 340 | − if (test_client_verify(sk, 100, quota / 100, TEST_TIMEOUT_SEC)) | |
| 341 | + if (test_client_verify(sk, packet_sz, quota / packet_sz, TEST_TIMEOUT_SEC)) | |
| 341 | 342 | test_fail("Failed to send data on connected socket"); |
| 342 | 343 | else |
| 343 | 344 | test_ok("Verified established tcp connection"); |
| 344 | 345 | |
| 345 | − synchronize_threads(); /* 3: chekpoint/restore the connection */ | |
| 346 | + synchronize_threads(); /* 3: checkpoint the client */ | |
| 346 | 347 | test_enable_repair(sk); |
| 347 | 348 | test_sock_checkpoint(sk, &img, &saddr); |
| 348 | 349 | test_ao_checkpoint(sk, &ao_img); |
| 349 | − test_kill_sk(sk); | |
| 350 | + test_disable_repair(sk); | |
| 350 | 351 | |
| 351 | − img.out.seq += quota; | |
| 352 | + synchronize_threads(); /* 4: close the server, creating twsk */ | |
| 353 | + | |
| 354 | + /* | |
| 355 | + * The "corruption" in SEQ has to be small enough to fit into TCP | |
| 356 | + * window, see tcp_timewait_state_process() for out-of-window | |
| 357 | + * segments. | |
| 358 | + */ | |
| 359 | + img.out.seq += 5; /* 5 is more noticeable in tcpdump than 1 */ | |
| 360 | + | |
| 361 | + /* | |
| 362 | + * FIXME: This is kind-of ugly and dirty, but it works. | |
| 363 | + * | |
| 364 | + * At this moment, the server has close'ed(sk). | |
| 365 | + * The passive RST that is being targeted here is new data after | |
| 366 | + * half-duplex close, see tcp_timewait_state_process() => TCP_TW_RST | |
| 367 | + * | |
| 368 | + * What is needed here is: | |
| 369 | + * (1) wait for FIN from the server | |
| 370 | + * (2) make sure that the ACK from the client went out | |
| 371 | + * (3) make sure that the ACK was received and processed by the server | |
| 372 | + * | |
| 373 | + * Otherwise, the data that will be sent from "repaired" socket | |
| 374 | + * post SEQ corruption may get to the server before it's in | |
| 375 | + * TCP_FIN_WAIT2. | |
| 376 | + * | |
| 377 | + * (1) is easy with select()/poll() | |
| 378 | + * (2) is possible by polling tcpi_state from TCP_INFO | |
| 379 | + * (3) is quite complex: as server's socket was already closed, | |
| 380 | + * probably the way to do it would be tcp-diag. | |
| 381 | + */ | |
| 382 | + sleep(TEST_RETRANSMIT_SEC); | |
| 383 | + | |
| 384 | + synchronize_threads(); /* 5: restore the socket, send more data */ | |
| 385 | + test_kill_sk(sk); | |
| 352 | 386 | |
| 353 | 387 | sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP); |
| 354 | 388 | if (sk < 0) |
| @@ -366,25 +400,33 @@ static void test_client_passive_rst(unsigned int port) · 11 unmodified lines | ||
| 366 | 400 | test_disable_repair(sk); |
| 367 | 401 | test_sock_state_free(&img); |
| 368 | 402 | |
| 369 | − synchronize_threads(); /* 4: terminate server + send more on client */ | |
| 370 | − if (test_client_verify(sk, 100, quota / 100, 2 * TEST_TIMEOUT_SEC)) | |
| 371 | − test_ok("client connection broken post-seq-adjust"); | |
| 372 | − else | |
| 373 | − test_fail("client connection still works post-seq-adjust"); | |
| 374 | − | |
| 375 | − test_wait_for_exception(sk, TEST_TIMEOUT_SEC); | |
| 376 | − | |
| 377 | − if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &slen)) | |
| 378 | − test_error("getsockopt()"); | |
| 379 | − if (err != ECONNRESET && err != EPIPE) | |
| 380 | − test_fail("client connection was not reset: %d", err); | |
| 403 | + /* | |
| 404 | + * This is how "passive reset" is acquired in this test from TCP_TW_RST: | |
| 405 | + * | |
| 406 | + * IP 10.0.254.1.7011 > 10.0.1.1.59772: Flags [P.], seq 901:1001, ack 1001, win 249, | |
| 407 | + * options [tcp-ao keyid 100 rnextkeyid 100 mac 0x10217d6c36a22379086ef3b1], length 100 | |
| 408 | + * IP 10.0.254.1.7011 > 10.0.1.1.59772: Flags [F.], seq 1001, ack 1001, win 249, | |
| 409 | + * options [tcp-ao keyid 100 rnextkeyid 100 mac 0x104ffc99b98c10a5298cc268], length 0 | |
| 410 | + * IP 10.0.1.1.59772 > 10.0.254.1.7011: Flags [.], ack 1002, win 251, | |
| 411 | + * options [tcp-ao keyid 100 rnextkeyid 100 mac 0xe496dd4f7f5a8a66873c6f93,nop,nop,sack 1 {1001:1002}], length 0 | |
| 412 | + * IP 10.0.1.1.59772 > 10.0.254.1.7011: Flags [P.], seq 1006:1106, ack 1001, win 251, | |
| 413 | + * options [tcp-ao keyid 100 rnextkeyid 100 mac 0x1b5f3330fb23fbcd0c77d0ca], length 100 | |
| 414 | + * IP 10.0.254.1.7011 > 10.0.1.1.59772: Flags [R], seq 3215596252, win 0, | |
| 415 | + * options [tcp-ao keyid 100 rnextkeyid 100 mac 0x0bcfbbf497bce844312304b2], length 0 | |
| 416 | + */ | |
| 417 | + err = test_client_verify(sk, packet_sz, quota / packet_sz, 2 * TEST_TIMEOUT_SEC); | |
| 418 | + /* Make sure that the connection was reset, not timeouted */ | |
| 419 | + if (err && err == -ECONNRESET) | |
| 420 | + test_ok("client sock was passively reset post-seq-adjust"); | |
| 421 | + else if (err) | |
| 422 | + test_fail("client sock was not reset post-seq-adjust: %d", err); | |
| 381 | 423 | else |
| 382 | − test_ok("client connection was reset"); | |
| 424 | + test_fail("client sock is yet connected post-seq-adjust"); | |
| 383 | 425 | |
| 384 | 426 | if (test_get_tcp_ao_counters(sk, &ao2)) |
| 385 | 427 | test_error("test_get_tcp_ao_counters()"); |
| 386 | 428 | |
| 387 | − synchronize_threads(); /* 5: verified => closed */ | |
| 429 | + synchronize_threads(); /* 6: server exits */ | |
| 388 | 430 | close(sk); |
| 389 | 431 | test_tcp_ao_counters_cmp("client passive RST", &ao1, &ao2, TEST_CNT_GOOD); |
| 390 | 432 | } |
| @@ -410,6 +452,6 @@ static void *client_fn(void *arg) · 19 unmodified lines | ||
| 410 | 452 | |
| 411 | 453 | int main(int argc, char *argv[]) |
| 412 | 454 | { |
| 413 | − test_init(15, server_fn, client_fn); | |
| 455 | + test_init(14, server_fn, client_fn); | |
| 414 | 456 | return 0; |
| 415 | 457 | } |
| @@ -0,0 +1 @@ | ||
| 1 | +timeout=120 | |
| @@ -7,7 +7,7 @@ source net_helper.sh · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)" |
| 9 | 9 | |
| 10 | −BPF_FILE="../bpf/xdp_dummy.bpf.o" | |
| 10 | +BPF_FILE="xdp_dummy.o" | |
| 11 | 11 | |
| 12 | 12 | # set global exit status, but never reset nonzero one. |
| 13 | 13 | check_err() |
| @@ -197,7 +197,7 @@ run_all() { · 183 unmodified lines | ||
| 197 | 197 | } |
| 198 | 198 | |
| 199 | 199 | if [ ! -f ${BPF_FILE} ]; then |
| 200 | − echo "Missing ${BPF_FILE}. Build bpf selftest first" | |
| 200 | + echo "Missing ${BPF_FILE}. Run 'make' first" | |
| 201 | 201 | exit -1 |
| 202 | 202 | fi |
| 203 | 203 | |
| @@ -7,7 +7,7 @@ source net_helper.sh · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)" |
| 9 | 9 | |
| 10 | −BPF_FILE="../bpf/xdp_dummy.bpf.o" | |
| 10 | +BPF_FILE="xdp_dummy.o" | |
| 11 | 11 | |
| 12 | 12 | cleanup() { |
| 13 | 13 | local -r jobs="$(jobs -p)" |
| @@ -84,7 +84,7 @@ run_all() { · 70 unmodified lines | ||
| 84 | 84 | } |
| 85 | 85 | |
| 86 | 86 | if [ ! -f ${BPF_FILE} ]; then |
| 87 | − echo "Missing ${BPF_FILE}. Build bpf selftest first" | |
| 87 | + echo "Missing ${BPF_FILE}. Run 'make' first" | |
| 88 | 88 | exit -1 |
| 89 | 89 | fi |
| 90 | 90 | |
| @@ -7,7 +7,7 @@ source net_helper.sh · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)" |
| 9 | 9 | |
| 10 | −BPF_FILE="../bpf/xdp_dummy.bpf.o" | |
| 10 | +BPF_FILE="xdp_dummy.o" | |
| 11 | 11 | |
| 12 | 12 | cleanup() { |
| 13 | 13 | local -r jobs="$(jobs -p)" |
| @@ -85,12 +85,12 @@ run_all() { · 71 unmodified lines | ||
| 85 | 85 | } |
| 86 | 86 | |
| 87 | 87 | if [ ! -f ${BPF_FILE} ]; then |
| 88 | − echo "Missing ${BPF_FILE}. Build bpf selftest first" | |
| 88 | + echo "Missing ${BPF_FILE}. Run 'make' first" | |
| 89 | 89 | exit -1 |
| 90 | 90 | fi |
| 91 | 91 | |
| 92 | 92 | if [ ! -f nat6to4.o ]; then |
| 93 | − echo "Missing nat6to4 helper. Build bpf nat6to4.o selftest first" | |
| 93 | + echo "Missing nat6to4 helper. Run 'make' first" | |
| 94 | 94 | exit -1 |
| 95 | 95 | fi |
| 96 | 96 | |
| @@ -1,7 +1,9 @@ | ||
| 1 | 1 | #!/bin/bash |
| 2 | 2 | # SPDX-License-Identifier: GPL-2.0 |
| 3 | 3 | |
| 4 | −BPF_FILE="../bpf/xdp_dummy.bpf.o" | |
| 4 | +source net_helper.sh | |
| 5 | + | |
| 6 | +BPF_FILE="xdp_dummy.o" | |
| 5 | 7 | readonly BASE="ns-$(mktemp -u XXXXXX)" |
| 6 | 8 | readonly SRC=2 |
| 7 | 9 | readonly DST=1 |
| @@ -119,7 +121,7 @@ run_test() { · 111 unmodified lines | ||
| 119 | 121 | ip netns exec $NS_DST $ipt -A INPUT -p udp --dport 8000 |
| 120 | 122 | ip netns exec $NS_DST ./udpgso_bench_rx -C 1000 -R 10 -n 10 -l 1300 $rx_args & |
| 121 | 123 | local spid=$! |
| 122 | − sleep 0.1 | |
| 124 | + wait_local_port_listen "$NS_DST" 8000 udp | |
| 123 | 125 | ip netns exec $NS_SRC ./udpgso_bench_tx $family -M 1 -s 13000 -S 1300 -D $dst |
| 124 | 126 | local retc=$? |
| 125 | 127 | wait $spid |
| @@ -168,7 +170,7 @@ run_bench() { · 42 unmodified lines | ||
| 168 | 170 | ip netns exec $NS_DST bash -c "echo 2 > /sys/class/net/veth$DST/queues/rx-0/rps_cpus" |
| 169 | 171 | ip netns exec $NS_DST taskset 0x2 ./udpgso_bench_rx -C 1000 -R 10 & |
| 170 | 172 | local spid=$! |
| 171 | − sleep 0.1 | |
| 173 | + wait_local_port_listen "$NS_DST" 8000 udp | |
| 172 | 174 | ip netns exec $NS_SRC taskset 0x1 ./udpgso_bench_tx $family -l 3 -S 1300 -D $dst |
| 173 | 175 | local retc=$? |
| 174 | 176 | wait $spid |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | #!/bin/sh |
| 2 | 2 | # SPDX-License-Identifier: GPL-2.0 |
| 3 | 3 | |
| 4 | −BPF_FILE="../bpf/xdp_dummy.bpf.o" | |
| 4 | +BPF_FILE="xdp_dummy.o" | |
| 5 | 5 | readonly STATS="$(mktemp -p /tmp ns-XXXXXX)" |
| 6 | 6 | readonly BASE=`basename $STATS` |
| 7 | 7 | readonly SRC=2 |
| @@ -218,7 +218,7 @@ while getopts "hs:" option; do · 210 unmodified lines | ||
| 218 | 218 | done |
| 219 | 219 | |
| 220 | 220 | if [ ! -f ${BPF_FILE} ]; then |
| 221 | − echo "Missing ${BPF_FILE}. Build bpf selftest first" | |
| 221 | + echo "Missing ${BPF_FILE}. Run 'make' first" | |
| 222 | 222 | exit 1 |
| 223 | 223 | fi |
| 224 | 224 | |
| @@ -0,0 +1,13 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +#define KBUILD_MODNAME "xdp_dummy" | |
| 4 | +#include <linux/bpf.h> | |
| 5 | +#include <bpf/bpf_helpers.h> | |
| 6 | + | |
| 7 | +SEC("xdp") | |
| 8 | +int xdp_dummy_prog(struct xdp_md *ctx) | |
| 9 | +{ | |
| 10 | + return XDP_PASS; | |
| 11 | +} | |
| 12 | + | |
| 13 | +char _license[] SEC("license") = "GPL"; | |
| @@ -24,6 +24,11 @@ bool rseq_validate_cpu_id(void) · 23 unmodified lines | ||
| 24 | 24 | { |
| 25 | 25 | return rseq_mm_cid_available(); |
| 26 | 26 | } |
| 27 | +static | |
| 28 | +bool rseq_use_cpu_index(void) | |
| 29 | +{ | |
| 30 | + return false; /* Use mm_cid */ | |
| 31 | +} | |
| 27 | 32 | #else |
| 28 | 33 | # define RSEQ_PERCPU RSEQ_PERCPU_CPU_ID |
| 29 | 34 | static |
| @@ -36,6 +41,11 @@ bool rseq_validate_cpu_id(void) · 6 unmodified lines | ||
| 36 | 41 | { |
| 37 | 42 | return rseq_current_cpu_raw() >= 0; |
| 38 | 43 | } |
| 44 | +static | |
| 45 | +bool rseq_use_cpu_index(void) | |
| 46 | +{ | |
| 47 | + return true; /* Use cpu_id as index. */ | |
| 48 | +} | |
| 39 | 49 | #endif |
| 40 | 50 | |
| 41 | 51 | struct percpu_lock_entry { |
| @@ -274,7 +284,7 @@ void test_percpu_list(void) · 232 unmodified lines | ||
| 274 | 284 | /* Generate list entries for every usable cpu. */ |
| 275 | 285 | sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus); |
| 276 | 286 | for (i = 0; i < CPU_SETSIZE; i++) { |
| 277 | − if (!CPU_ISSET(i, &allowed_cpus)) | |
| 287 | + if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus)) | |
| 278 | 288 | continue; |
| 279 | 289 | for (j = 1; j <= 100; j++) { |
| 280 | 290 | struct percpu_list_node *node; |
| @@ -299,7 +309,7 @@ void test_percpu_list(void) · 18 unmodified lines | ||
| 299 | 309 | for (i = 0; i < CPU_SETSIZE; i++) { |
| 300 | 310 | struct percpu_list_node *node; |
| 301 | 311 | |
| 302 | − if (!CPU_ISSET(i, &allowed_cpus)) | |
| 312 | + if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus)) | |
| 303 | 313 | continue; |
| 304 | 314 | |
| 305 | 315 | while ((node = __percpu_list_pop(&list, i))) { |
| @@ -288,6 +288,11 @@ bool rseq_validate_cpu_id(void) · 287 unmodified lines | ||
| 288 | 288 | { |
| 289 | 289 | return rseq_mm_cid_available(); |
| 290 | 290 | } |
| 291 | +static | |
| 292 | +bool rseq_use_cpu_index(void) | |
| 293 | +{ | |
| 294 | + return false; /* Use mm_cid */ | |
| 295 | +} | |
| 291 | 296 | # ifdef TEST_MEMBARRIER |
| 292 | 297 | /* |
| 293 | 298 | * Membarrier does not currently support targeting a mm_cid, so |
| @@ -312,6 +317,11 @@ bool rseq_validate_cpu_id(void) · 18 unmodified lines | ||
| 312 | 317 | { |
| 313 | 318 | return rseq_current_cpu_raw() >= 0; |
| 314 | 319 | } |
| 320 | +static | |
| 321 | +bool rseq_use_cpu_index(void) | |
| 322 | +{ | |
| 323 | + return true; /* Use cpu_id as index. */ | |
| 324 | +} | |
| 315 | 325 | # ifdef TEST_MEMBARRIER |
| 316 | 326 | static |
| 317 | 327 | int rseq_membarrier_expedited(int cpu) |
| @@ -715,7 +725,7 @@ void test_percpu_list(void) · 397 unmodified lines | ||
| 715 | 725 | /* Generate list entries for every usable cpu. */ |
| 716 | 726 | sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus); |
| 717 | 727 | for (i = 0; i < CPU_SETSIZE; i++) { |
| 718 | − if (!CPU_ISSET(i, &allowed_cpus)) | |
| 728 | + if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus)) | |
| 719 | 729 | continue; |
| 720 | 730 | for (j = 1; j <= 100; j++) { |
| 721 | 731 | struct percpu_list_node *node; |
| @@ -752,7 +762,7 @@ void test_percpu_list(void) · 30 unmodified lines | ||
| 752 | 762 | for (i = 0; i < CPU_SETSIZE; i++) { |
| 753 | 763 | struct percpu_list_node *node; |
| 754 | 764 | |
| 755 | − if (!CPU_ISSET(i, &allowed_cpus)) | |
| 765 | + if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus)) | |
| 756 | 766 | continue; |
| 757 | 767 | |
| 758 | 768 | while ((node = __percpu_list_pop(&list, i))) { |
| @@ -902,7 +912,7 @@ void test_percpu_buffer(void) · 143 unmodified lines | ||
| 902 | 912 | /* Generate list entries for every usable cpu. */ |
| 903 | 913 | sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus); |
| 904 | 914 | for (i = 0; i < CPU_SETSIZE; i++) { |
| 905 | − if (!CPU_ISSET(i, &allowed_cpus)) | |
| 915 | + if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus)) | |
| 906 | 916 | continue; |
| 907 | 917 | /* Worse-case is every item in same CPU. */ |
| 908 | 918 | buffer.c[i].array = |
| @@ -952,7 +962,7 @@ void test_percpu_buffer(void) · 43 unmodified lines | ||
| 952 | 962 | for (i = 0; i < CPU_SETSIZE; i++) { |
| 953 | 963 | struct percpu_buffer_node *node; |
| 954 | 964 | |
| 955 | − if (!CPU_ISSET(i, &allowed_cpus)) | |
| 965 | + if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus)) | |
| 956 | 966 | continue; |
| 957 | 967 | |
| 958 | 968 | while ((node = __percpu_buffer_pop(&buffer, i))) { |
| @@ -1113,7 +1123,7 @@ void test_percpu_memcpy_buffer(void) · 154 unmodified lines | ||
| 1113 | 1123 | /* Generate list entries for every usable cpu. */ |
| 1114 | 1124 | sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus); |
| 1115 | 1125 | for (i = 0; i < CPU_SETSIZE; i++) { |
| 1116 | − if (!CPU_ISSET(i, &allowed_cpus)) | |
| 1126 | + if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus)) | |
| 1117 | 1127 | continue; |
| 1118 | 1128 | /* Worse-case is every item in same CPU. */ |
| 1119 | 1129 | buffer.c[i].array = |
| @@ -1160,7 +1170,7 @@ void test_percpu_memcpy_buffer(void) · 40 unmodified lines | ||
| 1160 | 1170 | for (i = 0; i < CPU_SETSIZE; i++) { |
| 1161 | 1171 | struct percpu_memcpy_buffer_node item; |
| 1162 | 1172 | |
| 1163 | − if (!CPU_ISSET(i, &allowed_cpus)) | |
| 1173 | + if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus)) | |
| 1164 | 1174 | continue; |
| 1165 | 1175 | |
| 1166 | 1176 | while (__percpu_memcpy_buffer_pop(&buffer, &item, i)) { |
| @@ -38,10 +38,10 @@ unsigned long long timing(clockid_t clk_id, unsigned long long samples) · 37 unmodified lines | ||
| 38 | 38 | i *= 1000000000ULL; |
| 39 | 39 | i += finish.tv_nsec - start.tv_nsec; |
| 40 | 40 | |
| 41 | − printf("%lu.%09lu - %lu.%09lu = %llu (%.1fs)\n", | |
| 42 | − finish.tv_sec, finish.tv_nsec, | |
| 43 | − start.tv_sec, start.tv_nsec, | |
| 44 | − i, (double)i / 1000000000.0); | |
| 41 | + ksft_print_msg("%lu.%09lu - %lu.%09lu = %llu (%.1fs)\n", | |
| 42 | + finish.tv_sec, finish.tv_nsec, | |
| 43 | + start.tv_sec, start.tv_nsec, | |
| 44 | + i, (double)i / 1000000000.0); | |
| 45 | 45 | |
| 46 | 46 | return i; |
| 47 | 47 | } |
| @@ -53,7 +53,7 @@ unsigned long long calibrate(void) · 5 unmodified lines | ||
| 53 | 53 | pid_t pid, ret; |
| 54 | 54 | int seconds = 15; |
| 55 | 55 | |
| 56 | − printf("Calibrating sample size for %d seconds worth of syscalls ...\n", seconds); | |
| 56 | + ksft_print_msg("Calibrating sample size for %d seconds worth of syscalls ...\n", seconds); | |
| 57 | 57 | |
| 58 | 58 | samples = 0; |
| 59 | 59 | pid = getpid(); |
| @@ -98,24 +98,36 @@ bool le(int i_one, int i_two) · 38 unmodified lines | ||
| 98 | 98 | } |
| 99 | 99 | |
| 100 | 100 | long compare(const char *name_one, const char *name_eval, const char *name_two, |
| 101 | − unsigned long long one, bool (*eval)(int, int), unsigned long long two) | |
| 101 | + unsigned long long one, bool (*eval)(int, int), unsigned long long two, | |
| 102 | + bool skip) | |
| 102 | 103 | { |
| 103 | 104 | bool good; |
| 104 | 105 | |
| 105 | − printf("\t%s %s %s (%lld %s %lld): ", name_one, name_eval, name_two, | |
| 106 | − (long long)one, name_eval, (long long)two); | |
| 106 | + if (skip) { | |
| 107 | + ksft_test_result_skip("%s %s %s\n", name_one, name_eval, | |
| 108 | + name_two); | |
| 109 | + return 0; | |
| 110 | + } | |
| 111 | + | |
| 112 | + ksft_print_msg("\t%s %s %s (%lld %s %lld): ", name_one, name_eval, name_two, | |
| 113 | + (long long)one, name_eval, (long long)two); | |
| 107 | 114 | if (one > INT_MAX) { |
| 108 | − printf("Miscalculation! Measurement went negative: %lld\n", (long long)one); | |
| 109 | − return 1; | |
| 115 | + ksft_print_msg("Miscalculation! Measurement went negative: %lld\n", (long long)one); | |
| 116 | + good = false; | |
| 117 | + goto out; | |
| 110 | 118 | } |
| 111 | 119 | if (two > INT_MAX) { |
| 112 | − printf("Miscalculation! Measurement went negative: %lld\n", (long long)two); | |
| 113 | − return 1; | |
| 120 | + ksft_print_msg("Miscalculation! Measurement went negative: %lld\n", (long long)two); | |
| 121 | + good = false; | |
| 122 | + goto out; | |
| 114 | 123 | } |
| 115 | 124 | |
| 116 | 125 | good = eval(one, two); |
| 117 | 126 | printf("%s\n", good ? "✔️" : "❌"); |
| 118 | 127 | |
| 128 | +out: | |
| 129 | + ksft_test_result(good, "%s %s %s\n", name_one, name_eval, name_two); | |
| 130 | + | |
| 119 | 131 | return good ? 0 : 1; |
| 120 | 132 | } |
| 121 | 133 | |
| @@ -142,15 +154,22 @@ int main(int argc, char *argv[]) · 20 unmodified lines | ||
| 142 | 154 | unsigned long long samples, calc; |
| 143 | 155 | unsigned long long native, filter1, filter2, bitmap1, bitmap2; |
| 144 | 156 | unsigned long long entry, per_filter1, per_filter2; |
| 157 | + bool skip = false; | |
| 145 | 158 | |
| 146 | 159 | setbuf(stdout, NULL); |
| 147 | 160 | |
| 148 | − printf("Running on:\n"); | |
| 161 | + ksft_print_header(); | |
| 162 | + ksft_set_plan(7); | |
| 163 | + | |
| 164 | + ksft_print_msg("Running on:\n"); | |
| 165 | + ksft_print_msg(""); | |
| 149 | 166 | system("uname -a"); |
| 150 | 167 | |
| 151 | − printf("Current BPF sysctl settings:\n"); | |
| 168 | + ksft_print_msg("Current BPF sysctl settings:\n"); | |
| 152 | 169 | /* Avoid using "sysctl" which may not be installed. */ |
| 170 | + ksft_print_msg(""); | |
| 153 | 171 | system("grep -H . /proc/sys/net/core/bpf_jit_enable"); |
| 172 | + ksft_print_msg(""); | |
| 154 | 173 | system("grep -H . /proc/sys/net/core/bpf_jit_harden"); |
| 155 | 174 | |
| 156 | 175 | if (argc > 1) |
| @@ -158,11 +177,11 @@ int main(int argc, char *argv[]) · 1 unmodified line | ||
| 158 | 177 | else |
| 159 | 178 | samples = calibrate(); |
| 160 | 179 | |
| 161 | − printf("Benchmarking %llu syscalls...\n", samples); | |
| 180 | + ksft_print_msg("Benchmarking %llu syscalls...\n", samples); | |
| 162 | 181 | |
| 163 | 182 | /* Native call */ |
| 164 | 183 | native = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; |
| 165 | − printf("getpid native: %llu ns\n", native); | |
| 184 | + ksft_print_msg("getpid native: %llu ns\n", native); | |
| 166 | 185 | |
| 167 | 186 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); |
| 168 | 187 | assert(ret == 0); |
| @@ -172,35 +191,37 @@ int main(int argc, char *argv[]) · 3 unmodified lines | ||
| 172 | 191 | assert(ret == 0); |
| 173 | 192 | |
| 174 | 193 | bitmap1 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; |
| 175 | − printf("getpid RET_ALLOW 1 filter (bitmap): %llu ns\n", bitmap1); | |
| 194 | + ksft_print_msg("getpid RET_ALLOW 1 filter (bitmap): %llu ns\n", bitmap1); | |
| 176 | 195 | |
| 177 | 196 | /* Second filter resulting in a bitmap */ |
| 178 | 197 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &bitmap_prog); |
| 179 | 198 | assert(ret == 0); |
| 180 | 199 | |
| 181 | 200 | bitmap2 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; |
| 182 | − printf("getpid RET_ALLOW 2 filters (bitmap): %llu ns\n", bitmap2); | |
| 201 | + ksft_print_msg("getpid RET_ALLOW 2 filters (bitmap): %llu ns\n", bitmap2); | |
| 183 | 202 | |
| 184 | 203 | /* Third filter, can no longer be converted to bitmap */ |
| 185 | 204 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); |
| 186 | 205 | assert(ret == 0); |
| 187 | 206 | |
| 188 | 207 | filter1 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; |
| 189 | − printf("getpid RET_ALLOW 3 filters (full): %llu ns\n", filter1); | |
| 208 | + ksft_print_msg("getpid RET_ALLOW 3 filters (full): %llu ns\n", filter1); | |
| 190 | 209 | |
| 191 | 210 | /* Fourth filter, can not be converted to bitmap because of filter 3 */ |
| 192 | 211 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &bitmap_prog); |
| 193 | 212 | assert(ret == 0); |
| 194 | 213 | |
| 195 | 214 | filter2 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; |
| 196 | − printf("getpid RET_ALLOW 4 filters (full): %llu ns\n", filter2); | |
| 215 | + ksft_print_msg("getpid RET_ALLOW 4 filters (full): %llu ns\n", filter2); | |
| 197 | 216 | |
| 198 | 217 | /* Estimations */ |
| 199 | 218 | #define ESTIMATE(fmt, var, what) do { \ |
| 200 | 219 | var = (what); \ |
| 201 | − printf("Estimated " fmt ": %llu ns\n", var); \ | |
| 202 | − if (var > INT_MAX) \ | |
| 203 | − goto more_samples; \ | |
| 220 | + ksft_print_msg("Estimated " fmt ": %llu ns\n", var); \ | |
| 221 | + if (var > INT_MAX) { \ | |
| 222 | + skip = true; \ | |
| 223 | + ret |= 1; \ | |
| 224 | + } \ | |
| 204 | 225 | } while (0) |
| 205 | 226 | |
| 206 | 227 | ESTIMATE("total seccomp overhead for 1 bitmapped filter", calc, |
| @@ -218,31 +239,34 @@ int main(int argc, char *argv[]) · 11 unmodified lines | ||
| 218 | 239 | ESTIMATE("seccomp per-filter overhead (filters / 4)", per_filter2, |
| 219 | 240 | (filter2 - native - entry) / 4); |
| 220 | 241 | |
| 221 | − printf("Expectations:\n"); | |
| 222 | − ret |= compare("native", "≤", "1 bitmap", native, le, bitmap1); | |
| 223 | − bits = compare("native", "≤", "1 filter", native, le, filter1); | |
| 242 | + ksft_print_msg("Expectations:\n"); | |
| 243 | + ret |= compare("native", "≤", "1 bitmap", native, le, bitmap1, | |
| 244 | + skip); | |
| 245 | + bits = compare("native", "≤", "1 filter", native, le, filter1, | |
| 246 | + skip); | |
| 224 | 247 | if (bits) |
| 225 | − goto more_samples; | |
| 248 | + skip = true; | |
| 226 | 249 | |
| 227 | 250 | ret |= compare("per-filter (last 2 diff)", "≈", "per-filter (filters / 4)", |
| 228 | − per_filter1, approx, per_filter2); | |
| 251 | + per_filter1, approx, per_filter2, skip); | |
| 229 | 252 | |
| 230 | 253 | bits = compare("1 bitmapped", "≈", "2 bitmapped", |
| 231 | − bitmap1 - native, approx, bitmap2 - native); | |
| 254 | + bitmap1 - native, approx, bitmap2 - native, skip); | |
| 232 | 255 | if (bits) { |
| 233 | − printf("Skipping constant action bitmap expectations: they appear unsupported.\n"); | |
| 234 | − goto out; | |
| 256 | + ksft_print_msg("Skipping constant action bitmap expectations: they appear unsupported.\n"); | |
| 257 | + skip = true; | |
| 235 | 258 | } |
| 236 | 259 | |
| 237 | − ret |= compare("entry", "≈", "1 bitmapped", entry, approx, bitmap1 - native); | |
| 238 | − ret |= compare("entry", "≈", "2 bitmapped", entry, approx, bitmap2 - native); | |
| 260 | + ret |= compare("entry", "≈", "1 bitmapped", entry, approx, | |
| 261 | + bitmap1 - native, skip); | |
| 262 | + ret |= compare("entry", "≈", "2 bitmapped", entry, approx, | |
| 263 | + bitmap2 - native, skip); | |
| 239 | 264 | ret |= compare("native + entry + (per filter * 4)", "≈", "4 filters total", |
| 240 | − entry + (per_filter1 * 4) + native, approx, filter2); | |
| 241 | − if (ret == 0) | |
| 242 | − goto out; | |
| 265 | + entry + (per_filter1 * 4) + native, approx, filter2, | |
| 266 | + skip); | |
| 243 | 267 | |
| 244 | −more_samples: | |
| 245 | − printf("Saw unexpected benchmark result. Try running again with more samples?\n"); | |
| 246 | −out: | |
| 247 | − return 0; | |
| 268 | + if (ret) | |
| 269 | + ksft_print_msg("Saw unexpected benchmark result. Try running again with more samples?\n"); | |
| 270 | + | |
| 271 | + ksft_finished(); | |
| 248 | 272 | } |