Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
e1d9d7b913
|
@ -1,29 +1,29 @@
|
|||
What: sys/devices/pciXXXX:XX/0000:XX:XX.X/dma/dma<n>chan<n>/quickdata/cap
|
||||
What: /sys/devices/pciXXXX:XX/0000:XX:XX.X/dma/dma<n>chan<n>/quickdata/cap
|
||||
Date: December 3, 2009
|
||||
KernelVersion: 2.6.32
|
||||
Contact: dmaengine@vger.kernel.org
|
||||
Description: Capabilities the DMA supports.Currently there are DMA_PQ, DMA_PQ_VAL,
|
||||
DMA_XOR,DMA_XOR_VAL,DMA_INTERRUPT.
|
||||
|
||||
What: sys/devices/pciXXXX:XX/0000:XX:XX.X/dma/dma<n>chan<n>/quickdata/ring_active
|
||||
What: /sys/devices/pciXXXX:XX/0000:XX:XX.X/dma/dma<n>chan<n>/quickdata/ring_active
|
||||
Date: December 3, 2009
|
||||
KernelVersion: 2.6.32
|
||||
Contact: dmaengine@vger.kernel.org
|
||||
Description: The number of descriptors active in the ring.
|
||||
|
||||
What: sys/devices/pciXXXX:XX/0000:XX:XX.X/dma/dma<n>chan<n>/quickdata/ring_size
|
||||
What: /sys/devices/pciXXXX:XX/0000:XX:XX.X/dma/dma<n>chan<n>/quickdata/ring_size
|
||||
Date: December 3, 2009
|
||||
KernelVersion: 2.6.32
|
||||
Contact: dmaengine@vger.kernel.org
|
||||
Description: Descriptor ring size, total number of descriptors available.
|
||||
|
||||
What: sys/devices/pciXXXX:XX/0000:XX:XX.X/dma/dma<n>chan<n>/quickdata/version
|
||||
What: /sys/devices/pciXXXX:XX/0000:XX:XX.X/dma/dma<n>chan<n>/quickdata/version
|
||||
Date: December 3, 2009
|
||||
KernelVersion: 2.6.32
|
||||
Contact: dmaengine@vger.kernel.org
|
||||
Description: Version of ioatdma device.
|
||||
|
||||
What: sys/devices/pciXXXX:XX/0000:XX:XX.X/dma/dma<n>chan<n>/quickdata/intr_coalesce
|
||||
What: /sys/devices/pciXXXX:XX/0000:XX:XX.X/dma/dma<n>chan<n>/quickdata/intr_coalesce
|
||||
Date: August 8, 2017
|
||||
KernelVersion: 4.14
|
||||
Contact: dmaengine@vger.kernel.org
|
||||
|
|
|
@ -152,7 +152,7 @@ Description:
|
|||
When an interface is under test, it cannot be expected
|
||||
to pass packets as normal.
|
||||
|
||||
What: /sys/clas/net/<iface>/duplex
|
||||
What: /sys/class/net/<iface>/duplex
|
||||
Date: October 2009
|
||||
KernelVersion: 2.6.33
|
||||
Contact: netdev@vger.kernel.org
|
||||
|
|
|
@ -32,6 +32,11 @@ description: |
|
|||
| | vint | bit | | 0 |.....|63| vintx |
|
||||
| +--------------+ +------------+ |
|
||||
| |
|
||||
| Unmap |
|
||||
| +--------------+ |
|
||||
Unmapped events ---->| | umapidx |-------------------------> Globalevents
|
||||
| +--------------+ |
|
||||
| |
|
||||
+-----------------------------------------+
|
||||
|
||||
Configuration of these Intmap registers that maps global events to vint is
|
||||
|
@ -70,6 +75,11 @@ properties:
|
|||
- description: |
|
||||
"limit" specifies the limit for translation
|
||||
|
||||
ti,unmapped-event-sources:
|
||||
$ref: /schemas/types.yaml#definitions/phandle-array
|
||||
description:
|
||||
Array of phandles to DMA controllers where the unmapped events originate.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
@ -256,6 +256,10 @@ which is 1024 bytes long:
|
|||
- s\_padding2
|
||||
-
|
||||
* - 0x54
|
||||
- \_\_be32
|
||||
- s\_num\_fc\_blocks
|
||||
- Number of fast commit blocks in the journal.
|
||||
* - 0x58
|
||||
- \_\_u32
|
||||
- s\_padding[42]
|
||||
-
|
||||
|
@ -310,6 +314,8 @@ The journal incompat features are any combination of the following:
|
|||
- This journal uses v3 of the checksum on-disk format. This is the same as
|
||||
v2, but the journal block tag size is fixed regardless of the size of
|
||||
block numbers. (JBD2\_FEATURE\_INCOMPAT\_CSUM\_V3)
|
||||
* - 0x20
|
||||
- Journal has fast commit blocks. (JBD2\_FEATURE\_INCOMPAT\_FAST\_COMMIT)
|
||||
|
||||
.. _jbd2_checksum_type:
|
||||
|
||||
|
|
|
@ -596,6 +596,13 @@ following:
|
|||
- Sparse Super Block, v2. If this flag is set, the SB field s\_backup\_bgs
|
||||
points to the two block groups that contain backup superblocks
|
||||
(COMPAT\_SPARSE\_SUPER2).
|
||||
* - 0x400
|
||||
- Fast commits supported. Although fast commits blocks are
|
||||
backward incompatible, fast commit blocks are not always
|
||||
present in the journal. If fast commit blocks are present in
|
||||
the journal, JBD2 incompat feature
|
||||
(JBD2\_FEATURE\_INCOMPAT\_FAST\_COMMIT) gets
|
||||
set (COMPAT\_FAST\_COMMIT).
|
||||
|
||||
.. _super_incompat:
|
||||
|
||||
|
|
|
@ -136,10 +136,8 @@ Fast commits
|
|||
~~~~~~~~~~~~
|
||||
|
||||
JBD2 to also allows you to perform file-system specific delta commits known as
|
||||
fast commits. In order to use fast commits, you first need to call
|
||||
:c:func:`jbd2_fc_init` and tell how many blocks at the end of journal
|
||||
area should be reserved for fast commits. Along with that, you will also need
|
||||
to set following callbacks that perform correspodning work:
|
||||
fast commits. In order to use fast commits, you will need to set following
|
||||
callbacks that perform correspodning work:
|
||||
|
||||
`journal->j_fc_cleanup_cb`: Cleanup function called after every full commit and
|
||||
fast commit.
|
||||
|
|
|
@ -19,9 +19,9 @@ report the "current" state of the lid as either "opened" or "closed".
|
|||
|
||||
For most platforms, both the _LID method and the lid notifications are
|
||||
reliable. However, there are exceptions. In order to work with these
|
||||
exceptional buggy platforms, special restrictions and expections should be
|
||||
exceptional buggy platforms, special restrictions and exceptions should be
|
||||
taken into account. This document describes the restrictions and the
|
||||
expections of the Linux ACPI lid device driver.
|
||||
exceptions of the Linux ACPI lid device driver.
|
||||
|
||||
|
||||
Restrictions of the returning value of the _LID control method
|
||||
|
@ -46,7 +46,7 @@ state is changed to "closed". The "closed" notification is normally used to
|
|||
trigger some system power saving operations on Windows. Since it is fully
|
||||
tested, it is reliable from all AML tables.
|
||||
|
||||
Expections for the userspace users of the ACPI lid device driver
|
||||
Exceptions for the userspace users of the ACPI lid device driver
|
||||
================================================================
|
||||
|
||||
The ACPI button driver exports the lid state to the userspace via the
|
||||
|
@ -100,7 +100,7 @@ use the following kernel parameter:
|
|||
C. button.lid_init_state=ignore:
|
||||
When this option is specified, the ACPI button driver never reports the
|
||||
initial lid state and there is a compensation mechanism implemented to
|
||||
ensure that the reliable "closed" notifications can always be delievered
|
||||
ensure that the reliable "closed" notifications can always be delivered
|
||||
to the userspace by always pairing "closed" input events with complement
|
||||
"opened" input events. But there is still no guarantee that the "opened"
|
||||
notifications can be delivered to the userspace when the lid is actually
|
||||
|
|
|
@ -20,9 +20,9 @@ index, like the ASL example below shows::
|
|||
|
||||
Name (_CRS, ResourceTemplate ()
|
||||
{
|
||||
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
|
||||
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionOutputOnly,
|
||||
"\\_SB.GPO0", 0, ResourceConsumer) {15}
|
||||
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
|
||||
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionOutputOnly,
|
||||
"\\_SB.GPO0", 0, ResourceConsumer) {27, 31}
|
||||
})
|
||||
|
||||
|
@ -49,15 +49,41 @@ index
|
|||
pin
|
||||
Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
|
||||
active_low
|
||||
If 1 the GPIO is marked as active_low.
|
||||
If 1, the GPIO is marked as active_low.
|
||||
|
||||
Since ACPI GpioIo() resource does not have a field saying whether it is
|
||||
active low or high, the "active_low" argument can be used here. Setting
|
||||
it to 1 marks the GPIO as active low.
|
||||
|
||||
Note, active_low in _DSD does not make sense for GpioInt() resource and
|
||||
must be 0. GpioInt() resource has its own means of defining it.
|
||||
|
||||
In our Bluetooth example the "reset-gpios" refers to the second GpioIo()
|
||||
resource, second pin in that resource with the GPIO number of 31.
|
||||
|
||||
The GpioIo() resource unfortunately doesn't explicitly provide an initial
|
||||
state of the output pin which driver should use during its initialization.
|
||||
|
||||
Linux tries to use common sense here and derives the state from the bias
|
||||
and polarity settings. The table below shows the expectations:
|
||||
|
||||
========= ============= ==============
|
||||
Pull Bias Polarity Requested...
|
||||
========= ============= ==============
|
||||
Implicit x AS IS (assumed firmware configured for us)
|
||||
Explicit x (no _DSD) as Pull Bias (Up == High, Down == Low),
|
||||
assuming non-active (Polarity = !Pull Bias)
|
||||
Down Low as low, assuming active
|
||||
Down High as low, assuming non-active
|
||||
Up Low as high, assuming non-active
|
||||
Up High as high, assuming active
|
||||
========= ============= ==============
|
||||
|
||||
That said, for our above example the both GPIOs, since the bias setting
|
||||
is explicit and _DSD is present, will be treated as active with a high
|
||||
polarity and Linux will configure the pins in this state until a driver
|
||||
reprograms them differently.
|
||||
|
||||
It is possible to leave holes in the array of GPIOs. This is useful in
|
||||
cases like with SPI host controllers where some chip selects may be
|
||||
implemented as GPIOs and some as native signals. For example a SPI host
|
||||
|
@ -112,8 +138,8 @@ Example::
|
|||
Package () {
|
||||
"gpio-line-names",
|
||||
Package () {
|
||||
"SPI0_CS_N", "EXP2_INT", "MUX6_IO", "UART0_RXD", "MUX7_IO",
|
||||
"LVL_C_A1", "MUX0_IO", "SPI1_MISO"
|
||||
"SPI0_CS_N", "EXP2_INT", "MUX6_IO", "UART0_RXD",
|
||||
"MUX7_IO", "LVL_C_A1", "MUX0_IO", "SPI1_MISO",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,7 +163,7 @@ to the GPIO lines it is going to use and provide the GPIO subsystem with a
|
|||
mapping between those names and the ACPI GPIO resources corresponding to them.
|
||||
|
||||
To do that, the driver needs to define a mapping table as a NULL-terminated
|
||||
array of struct acpi_gpio_mapping objects that each contain a name, a pointer
|
||||
array of struct acpi_gpio_mapping objects that each contains a name, a pointer
|
||||
to an array of line data (struct acpi_gpio_params) objects and the size of that
|
||||
array. Each struct acpi_gpio_params object consists of three fields,
|
||||
crs_entry_index, line_index, active_low, representing the index of the target
|
||||
|
@ -154,13 +180,14 @@ question would look like this::
|
|||
static const struct acpi_gpio_mapping bluetooth_acpi_gpios[] = {
|
||||
{ "reset-gpios", &reset_gpio, 1 },
|
||||
{ "shutdown-gpios", &shutdown_gpio, 1 },
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
|
||||
Next, the mapping table needs to be passed as the second argument to
|
||||
acpi_dev_add_driver_gpios() that will register it with the ACPI device object
|
||||
pointed to by its first argument. That should be done in the driver's .probe()
|
||||
routine. On removal, the driver should unregister its GPIO mapping table by
|
||||
acpi_dev_add_driver_gpios() or its managed analogue that will
|
||||
register it with the ACPI device object pointed to by its first
|
||||
argument. That should be done in the driver's .probe() routine.
|
||||
On removal, the driver should unregister its GPIO mapping table by
|
||||
calling acpi_dev_remove_driver_gpios() on the ACPI device object where that
|
||||
table was previously registered.
|
||||
|
||||
|
@ -191,12 +218,12 @@ The driver might expect to get the right GPIO when it does::
|
|||
but since there is no way to know the mapping between "reset" and
|
||||
the GpioIo() in _CRS desc will hold ERR_PTR(-ENOENT).
|
||||
|
||||
The driver author can solve this by passing the mapping explictly
|
||||
(the recommended way and documented in the above chapter).
|
||||
The driver author can solve this by passing the mapping explicitly
|
||||
(this is the recommended way and it's documented in the above chapter).
|
||||
|
||||
The ACPI GPIO mapping tables should not contaminate drivers that are not
|
||||
knowing about which exact device they are servicing on. It implies that
|
||||
the ACPI GPIO mapping tables are hardly linked to ACPI ID and certain
|
||||
the ACPI GPIO mapping tables are hardly linked to an ACPI ID and certain
|
||||
objects, as listed in the above chapter, of the device in question.
|
||||
|
||||
Getting GPIO descriptor
|
||||
|
@ -229,5 +256,5 @@ Case 2 explicitly tells GPIO core to look for resources in _CRS.
|
|||
Be aware that gpiod_get_index() in cases 1 and 2, assuming that there
|
||||
are two versions of ACPI device description provided and no mapping is
|
||||
present in the driver, will return different resources. That's why a
|
||||
certain driver has to handle them carefully as explained in previous
|
||||
certain driver has to handle them carefully as explained in the previous
|
||||
chapter.
|
||||
|
|
|
@ -98,7 +98,7 @@ subject to change::
|
|||
[ 0.188903] exdebug-0398 ex_trace_point : Method End [0xf58394d8:\_SB.PCI0.LPCB.ECOK] execution.
|
||||
|
||||
Developers can utilize these special log entries to track the AML
|
||||
interpretion, thus can aid issue debugging and performance tuning. Note
|
||||
interpretation, thus can aid issue debugging and performance tuning. Note
|
||||
that, as the "AML tracer" logs are implemented via ACPI_DEBUG_PRINT()
|
||||
macro, CONFIG_ACPI_DEBUG is also required to be enabled for enabling
|
||||
"AML tracer" logs.
|
||||
|
|
|
@ -25,3 +25,4 @@ LEDs
|
|||
leds-lp5562
|
||||
leds-lp55xx
|
||||
leds-mlxcpld
|
||||
leds-sc27xx
|
||||
|
|
|
@ -24,7 +24,6 @@ fit into other categories.
|
|||
isl29003
|
||||
lis3lv02d
|
||||
max6875
|
||||
mic/index
|
||||
pci-endpoint-test
|
||||
spear-pcie-gadget
|
||||
uacce
|
||||
|
|
|
@ -110,7 +110,7 @@ Q: I sent a patch and I'm wondering what happened to it?
|
|||
Q: How can I tell whether it got merged?
|
||||
A: Start by looking at the main patchworks queue for netdev:
|
||||
|
||||
http://patchwork.ozlabs.org/project/netdev/list/
|
||||
https://patchwork.kernel.org/project/netdevbpf/list/
|
||||
|
||||
The "State" field will tell you exactly where things are at with your
|
||||
patch.
|
||||
|
@ -152,7 +152,7 @@ networking subsystem, and then hands them off to Greg.
|
|||
|
||||
There is a patchworks queue that you can see here:
|
||||
|
||||
http://patchwork.ozlabs.org/bundle/davem/stable/?state=*
|
||||
https://patchwork.kernel.org/bundle/netdev/stable/?state=*
|
||||
|
||||
It contains the patches which Dave has selected, but not yet handed off
|
||||
to Greg. If Greg already has the patch, then it will be here:
|
||||
|
|
|
@ -247,8 +247,8 @@ Some of the interface modes are described below:
|
|||
speeds (see below.)
|
||||
|
||||
``PHY_INTERFACE_MODE_2500BASEX``
|
||||
This defines a variant of 1000BASE-X which is clocked 2.5 times faster,
|
||||
than the 802.3 standard giving a fixed bit rate of 3.125Gbaud.
|
||||
This defines a variant of 1000BASE-X which is clocked 2.5 times as fast
|
||||
as the 802.3 standard, giving a fixed bit rate of 3.125Gbaud.
|
||||
|
||||
``PHY_INTERFACE_MODE_SGMII``
|
||||
This is used for Cisco SGMII, which is a modification of 1000BASE-X
|
||||
|
|
|
@ -39,7 +39,7 @@ Procedure for submitting patches to the -stable tree
|
|||
submission guidelines as described in
|
||||
:ref:`Documentation/networking/netdev-FAQ.rst <netdev-FAQ>`
|
||||
after first checking the stable networking queue at
|
||||
https://patchwork.ozlabs.org/bundle/davem/stable/?series=&submitter=&state=*&q=&archive=
|
||||
https://patchwork.kernel.org/bundle/netdev/stable/?state=*
|
||||
to ensure the requested patch is not already queued up.
|
||||
- Security patches should not be handled (solely) by the -stable review
|
||||
process but should follow the procedures in
|
||||
|
|
|
@ -46,7 +46,7 @@ Procedura per sottomettere patch per i sorgenti -stable
|
|||
:ref:`Documentation/translations/it_IT/networking/netdev-FAQ.rst <it_netdev-FAQ>`;
|
||||
ma solo dopo aver verificato al seguente indirizzo che la patch non sia
|
||||
già in coda:
|
||||
https://patchwork.ozlabs.org/bundle/davem/stable/?series=&submitter=&state=*&q=&archive=
|
||||
https://patchwork.kernel.org/bundle/netdev/stable/?state=*
|
||||
- Una patch di sicurezza non dovrebbero essere gestite (solamente) dal processo
|
||||
di revisione -stable, ma dovrebbe seguire le procedure descritte in
|
||||
:ref:`Documentation/translations/it_IT/admin-guide/security-bugs.rst <it_securitybugs>`.
|
||||
|
|
|
@ -6367,7 +6367,7 @@ accesses that would usually trigger a #GP by KVM into the guest will
|
|||
instead get bounced to user space through the KVM_EXIT_X86_RDMSR and
|
||||
KVM_EXIT_X86_WRMSR exit notifications.
|
||||
|
||||
8.25 KVM_X86_SET_MSR_FILTER
|
||||
8.27 KVM_X86_SET_MSR_FILTER
|
||||
---------------------------
|
||||
|
||||
:Architectures: x86
|
||||
|
@ -6381,8 +6381,7 @@ In combination with KVM_CAP_X86_USER_SPACE_MSR, this allows user space to
|
|||
trap and emulate MSRs that are outside of the scope of KVM as well as
|
||||
limit the attack surface on KVM's MSR emulation code.
|
||||
|
||||
|
||||
8.26 KVM_CAP_ENFORCE_PV_CPUID
|
||||
8.28 KVM_CAP_ENFORCE_PV_CPUID
|
||||
-----------------------------
|
||||
|
||||
Architectures: x86
|
||||
|
|
30
MAINTAINERS
30
MAINTAINERS
|
@ -1279,7 +1279,7 @@ M: Igor Russkikh <irusskikh@marvell.com>
|
|||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://www.marvell.com/
|
||||
Q: http://patchwork.ozlabs.org/project/netdev/list/
|
||||
Q: https://patchwork.kernel.org/project/netdevbpf/list/
|
||||
F: Documentation/networking/device_drivers/ethernet/aquantia/atlantic.rst
|
||||
F: drivers/net/ethernet/aquantia/atlantic/
|
||||
|
||||
|
@ -6614,6 +6614,7 @@ Q: http://patchwork.ozlabs.org/project/linux-ext4/list/
|
|||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git
|
||||
F: Documentation/filesystems/ext4/
|
||||
F: fs/ext4/
|
||||
F: include/trace/events/ext4.h
|
||||
|
||||
Extended Verification Module (EVM)
|
||||
M: Mimi Zohar <zohar@linux.ibm.com>
|
||||
|
@ -8838,8 +8839,8 @@ S: Supported
|
|||
W: http://www.intel.com/support/feedback.htm
|
||||
W: http://e1000.sourceforge.net/
|
||||
Q: http://patchwork.ozlabs.org/project/intel-wired-lan/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-queue.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue.git
|
||||
F: Documentation/networking/device_drivers/ethernet/intel/
|
||||
F: drivers/net/ethernet/intel/
|
||||
F: drivers/net/ethernet/intel/*/
|
||||
|
@ -11162,7 +11163,7 @@ F: Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt
|
|||
F: drivers/input/touchscreen/melfas_mip4.c
|
||||
|
||||
MELLANOX BLUEFIELD I2C DRIVER
|
||||
M: Khalil Blaiech <kblaiech@mellanox.com>
|
||||
M: Khalil Blaiech <kblaiech@nvidia.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/i2c/busses/i2c-mlxbf.c
|
||||
|
@ -11172,7 +11173,7 @@ M: Tariq Toukan <tariqt@nvidia.com>
|
|||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
W: http://www.mellanox.com
|
||||
Q: http://patchwork.ozlabs.org/project/netdev/list/
|
||||
Q: https://patchwork.kernel.org/project/netdevbpf/list/
|
||||
F: drivers/net/ethernet/mellanox/mlx4/en_*
|
||||
|
||||
MELLANOX ETHERNET DRIVER (mlx5e)
|
||||
|
@ -11180,7 +11181,7 @@ M: Saeed Mahameed <saeedm@nvidia.com>
|
|||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
W: http://www.mellanox.com
|
||||
Q: http://patchwork.ozlabs.org/project/netdev/list/
|
||||
Q: https://patchwork.kernel.org/project/netdevbpf/list/
|
||||
F: drivers/net/ethernet/mellanox/mlx5/core/en_*
|
||||
|
||||
MELLANOX ETHERNET INNOVA DRIVERS
|
||||
|
@ -11188,7 +11189,7 @@ R: Boris Pismenny <borisp@nvidia.com>
|
|||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
W: http://www.mellanox.com
|
||||
Q: http://patchwork.ozlabs.org/project/netdev/list/
|
||||
Q: https://patchwork.kernel.org/project/netdevbpf/list/
|
||||
F: drivers/net/ethernet/mellanox/mlx5/core/accel/*
|
||||
F: drivers/net/ethernet/mellanox/mlx5/core/en_accel/*
|
||||
F: drivers/net/ethernet/mellanox/mlx5/core/fpga/*
|
||||
|
@ -11200,7 +11201,7 @@ M: Ido Schimmel <idosch@nvidia.com>
|
|||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
W: http://www.mellanox.com
|
||||
Q: http://patchwork.ozlabs.org/project/netdev/list/
|
||||
Q: https://patchwork.kernel.org/project/netdevbpf/list/
|
||||
F: drivers/net/ethernet/mellanox/mlxsw/
|
||||
F: tools/testing/selftests/drivers/net/mlxsw/
|
||||
|
||||
|
@ -11209,7 +11210,7 @@ M: mlxsw@nvidia.com
|
|||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
W: http://www.mellanox.com
|
||||
Q: http://patchwork.ozlabs.org/project/netdev/list/
|
||||
Q: https://patchwork.kernel.org/project/netdevbpf/list/
|
||||
F: drivers/net/ethernet/mellanox/mlxfw/
|
||||
|
||||
MELLANOX HARDWARE PLATFORM SUPPORT
|
||||
|
@ -11228,7 +11229,7 @@ L: netdev@vger.kernel.org
|
|||
L: linux-rdma@vger.kernel.org
|
||||
S: Supported
|
||||
W: http://www.mellanox.com
|
||||
Q: http://patchwork.ozlabs.org/project/netdev/list/
|
||||
Q: https://patchwork.kernel.org/project/netdevbpf/list/
|
||||
F: drivers/net/ethernet/mellanox/mlx4/
|
||||
F: include/linux/mlx4/
|
||||
|
||||
|
@ -11249,7 +11250,7 @@ L: netdev@vger.kernel.org
|
|||
L: linux-rdma@vger.kernel.org
|
||||
S: Supported
|
||||
W: http://www.mellanox.com
|
||||
Q: http://patchwork.ozlabs.org/project/netdev/list/
|
||||
Q: https://patchwork.kernel.org/project/netdevbpf/list/
|
||||
F: Documentation/networking/device_drivers/ethernet/mellanox/
|
||||
F: drivers/net/ethernet/mellanox/mlx5/core/
|
||||
F: include/linux/mlx5/
|
||||
|
@ -12129,7 +12130,7 @@ M: Jakub Kicinski <kuba@kernel.org>
|
|||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
W: http://www.linuxfoundation.org/en/Net
|
||||
Q: http://patchwork.ozlabs.org/project/netdev/list/
|
||||
Q: https://patchwork.kernel.org/project/netdevbpf/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
|
||||
F: Documentation/devicetree/bindings/net/
|
||||
|
@ -12174,7 +12175,7 @@ M: Jakub Kicinski <kuba@kernel.org>
|
|||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
W: http://www.linuxfoundation.org/en/Net
|
||||
Q: http://patchwork.ozlabs.org/project/netdev/list/
|
||||
Q: https://patchwork.kernel.org/project/netdevbpf/list/
|
||||
B: mailto:netdev@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
|
||||
|
@ -15246,7 +15247,6 @@ F: drivers/iommu/s390-iommu.c
|
|||
S390 IUCV NETWORK LAYER
|
||||
M: Julian Wiedmann <jwi@linux.ibm.com>
|
||||
M: Karsten Graul <kgraul@linux.ibm.com>
|
||||
M: Ursula Braun <ubraun@linux.ibm.com>
|
||||
L: linux-s390@vger.kernel.org
|
||||
S: Supported
|
||||
W: http://www.ibm.com/developerworks/linux/linux390/
|
||||
|
@ -15257,7 +15257,6 @@ F: net/iucv/
|
|||
S390 NETWORK DRIVERS
|
||||
M: Julian Wiedmann <jwi@linux.ibm.com>
|
||||
M: Karsten Graul <kgraul@linux.ibm.com>
|
||||
M: Ursula Braun <ubraun@linux.ibm.com>
|
||||
L: linux-s390@vger.kernel.org
|
||||
S: Supported
|
||||
W: http://www.ibm.com/developerworks/linux/linux390/
|
||||
|
@ -15828,7 +15827,6 @@ S: Maintained
|
|||
F: drivers/misc/sgi-xp/
|
||||
|
||||
SHARED MEMORY COMMUNICATIONS (SMC) SOCKETS
|
||||
M: Ursula Braun <ubraun@linux.ibm.com>
|
||||
M: Karsten Graul <kgraul@linux.ibm.com>
|
||||
L: linux-s390@vger.kernel.org
|
||||
S: Supported
|
||||
|
|
2
Makefile
2
Makefile
|
@ -2,7 +2,7 @@
|
|||
VERSION = 5
|
||||
PATCHLEVEL = 10
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc2
|
||||
EXTRAVERSION = -rc3
|
||||
NAME = Kleptomaniac Octopus
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
&enetc_port0 {
|
||||
phy-handle = <&phy0>;
|
||||
phy-connection-type = "sgmii";
|
||||
managed = "in-band-status";
|
||||
status = "okay";
|
||||
|
||||
mdio {
|
||||
|
|
|
@ -788,10 +788,12 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
|||
}
|
||||
|
||||
switch (vma_shift) {
|
||||
#ifndef __PAGETABLE_PMD_FOLDED
|
||||
case PUD_SHIFT:
|
||||
if (fault_supports_stage2_huge_mapping(memslot, hva, PUD_SIZE))
|
||||
break;
|
||||
fallthrough;
|
||||
#endif
|
||||
case CONT_PMD_SHIFT:
|
||||
vma_shift = PMD_SHIFT;
|
||||
fallthrough;
|
||||
|
|
|
@ -1069,7 +1069,7 @@ static bool trap_ptrauth(struct kvm_vcpu *vcpu,
|
|||
static unsigned int ptrauth_visibility(const struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *rd)
|
||||
{
|
||||
return vcpu_has_ptrauth(vcpu) ? 0 : REG_HIDDEN_USER | REG_HIDDEN_GUEST;
|
||||
return vcpu_has_ptrauth(vcpu) ? 0 : REG_HIDDEN;
|
||||
}
|
||||
|
||||
#define __PTRAUTH_KEY(k) \
|
||||
|
@ -1153,6 +1153,22 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
|
|||
return val;
|
||||
}
|
||||
|
||||
static unsigned int id_visibility(const struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
u32 id = sys_reg((u32)r->Op0, (u32)r->Op1,
|
||||
(u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
|
||||
|
||||
switch (id) {
|
||||
case SYS_ID_AA64ZFR0_EL1:
|
||||
if (!vcpu_has_sve(vcpu))
|
||||
return REG_RAZ;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* cpufeature ID register access trap handlers */
|
||||
|
||||
static bool __access_id_reg(struct kvm_vcpu *vcpu,
|
||||
|
@ -1171,7 +1187,9 @@ static bool access_id_reg(struct kvm_vcpu *vcpu,
|
|||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
return __access_id_reg(vcpu, p, r, false);
|
||||
bool raz = sysreg_visible_as_raz(vcpu, r);
|
||||
|
||||
return __access_id_reg(vcpu, p, r, raz);
|
||||
}
|
||||
|
||||
static bool access_raz_id_reg(struct kvm_vcpu *vcpu,
|
||||
|
@ -1192,72 +1210,7 @@ static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
|
|||
if (vcpu_has_sve(vcpu))
|
||||
return 0;
|
||||
|
||||
return REG_HIDDEN_USER | REG_HIDDEN_GUEST;
|
||||
}
|
||||
|
||||
/* Visibility overrides for SVE-specific ID registers */
|
||||
static unsigned int sve_id_visibility(const struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *rd)
|
||||
{
|
||||
if (vcpu_has_sve(vcpu))
|
||||
return 0;
|
||||
|
||||
return REG_HIDDEN_USER;
|
||||
}
|
||||
|
||||
/* Generate the emulated ID_AA64ZFR0_EL1 value exposed to the guest */
|
||||
static u64 guest_id_aa64zfr0_el1(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (!vcpu_has_sve(vcpu))
|
||||
return 0;
|
||||
|
||||
return read_sanitised_ftr_reg(SYS_ID_AA64ZFR0_EL1);
|
||||
}
|
||||
|
||||
static bool access_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *rd)
|
||||
{
|
||||
if (p->is_write)
|
||||
return write_to_read_only(vcpu, p, rd);
|
||||
|
||||
p->regval = guest_id_aa64zfr0_el1(vcpu);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *rd,
|
||||
const struct kvm_one_reg *reg, void __user *uaddr)
|
||||
{
|
||||
u64 val;
|
||||
|
||||
if (WARN_ON(!vcpu_has_sve(vcpu)))
|
||||
return -ENOENT;
|
||||
|
||||
val = guest_id_aa64zfr0_el1(vcpu);
|
||||
return reg_to_user(uaddr, &val, reg->id);
|
||||
}
|
||||
|
||||
static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *rd,
|
||||
const struct kvm_one_reg *reg, void __user *uaddr)
|
||||
{
|
||||
const u64 id = sys_reg_to_index(rd);
|
||||
int err;
|
||||
u64 val;
|
||||
|
||||
if (WARN_ON(!vcpu_has_sve(vcpu)))
|
||||
return -ENOENT;
|
||||
|
||||
err = reg_from_user(&val, uaddr, id);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* This is what we mean by invariant: you can't change it. */
|
||||
if (val != guest_id_aa64zfr0_el1(vcpu))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
return REG_HIDDEN;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1299,13 +1252,17 @@ static int __set_id_reg(const struct kvm_vcpu *vcpu,
|
|||
static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
|
||||
const struct kvm_one_reg *reg, void __user *uaddr)
|
||||
{
|
||||
return __get_id_reg(vcpu, rd, uaddr, false);
|
||||
bool raz = sysreg_visible_as_raz(vcpu, rd);
|
||||
|
||||
return __get_id_reg(vcpu, rd, uaddr, raz);
|
||||
}
|
||||
|
||||
static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
|
||||
const struct kvm_one_reg *reg, void __user *uaddr)
|
||||
{
|
||||
return __set_id_reg(vcpu, rd, uaddr, false);
|
||||
bool raz = sysreg_visible_as_raz(vcpu, rd);
|
||||
|
||||
return __set_id_reg(vcpu, rd, uaddr, raz);
|
||||
}
|
||||
|
||||
static int get_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
|
||||
|
@ -1397,6 +1354,7 @@ static bool access_mte_regs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
|||
.access = access_id_reg, \
|
||||
.get_user = get_id_reg, \
|
||||
.set_user = set_id_reg, \
|
||||
.visibility = id_visibility, \
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1518,7 +1476,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
|||
ID_SANITISED(ID_AA64PFR1_EL1),
|
||||
ID_UNALLOCATED(4,2),
|
||||
ID_UNALLOCATED(4,3),
|
||||
{ SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility },
|
||||
ID_SANITISED(ID_AA64ZFR0_EL1),
|
||||
ID_UNALLOCATED(4,5),
|
||||
ID_UNALLOCATED(4,6),
|
||||
ID_UNALLOCATED(4,7),
|
||||
|
@ -2185,7 +2143,7 @@ static void perform_access(struct kvm_vcpu *vcpu,
|
|||
trace_kvm_sys_access(*vcpu_pc(vcpu), params, r);
|
||||
|
||||
/* Check for regs disabled by runtime config */
|
||||
if (sysreg_hidden_from_guest(vcpu, r)) {
|
||||
if (sysreg_hidden(vcpu, r)) {
|
||||
kvm_inject_undefined(vcpu);
|
||||
return;
|
||||
}
|
||||
|
@ -2684,7 +2642,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
|
|||
return get_invariant_sys_reg(reg->id, uaddr);
|
||||
|
||||
/* Check for regs disabled by runtime config */
|
||||
if (sysreg_hidden_from_user(vcpu, r))
|
||||
if (sysreg_hidden(vcpu, r))
|
||||
return -ENOENT;
|
||||
|
||||
if (r->get_user)
|
||||
|
@ -2709,7 +2667,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
|
|||
return set_invariant_sys_reg(reg->id, uaddr);
|
||||
|
||||
/* Check for regs disabled by runtime config */
|
||||
if (sysreg_hidden_from_user(vcpu, r))
|
||||
if (sysreg_hidden(vcpu, r))
|
||||
return -ENOENT;
|
||||
|
||||
if (r->set_user)
|
||||
|
@ -2780,7 +2738,7 @@ static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
|
|||
if (!(rd->reg || rd->get_user))
|
||||
return 0;
|
||||
|
||||
if (sysreg_hidden_from_user(vcpu, rd))
|
||||
if (sysreg_hidden(vcpu, rd))
|
||||
return 0;
|
||||
|
||||
if (!copy_reg_to_user(rd, uind))
|
||||
|
|
|
@ -59,8 +59,8 @@ struct sys_reg_desc {
|
|||
const struct sys_reg_desc *rd);
|
||||
};
|
||||
|
||||
#define REG_HIDDEN_USER (1 << 0) /* hidden from userspace ioctls */
|
||||
#define REG_HIDDEN_GUEST (1 << 1) /* hidden from guest */
|
||||
#define REG_HIDDEN (1 << 0) /* hidden from userspace and guest */
|
||||
#define REG_RAZ (1 << 1) /* RAZ from userspace and guest */
|
||||
|
||||
static __printf(2, 3)
|
||||
inline void print_sys_reg_msg(const struct sys_reg_params *p,
|
||||
|
@ -111,22 +111,22 @@ static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r
|
|||
__vcpu_sys_reg(vcpu, r->reg) = r->val;
|
||||
}
|
||||
|
||||
static inline bool sysreg_hidden_from_guest(const struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *r)
|
||||
static inline bool sysreg_hidden(const struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (likely(!r->visibility))
|
||||
return false;
|
||||
|
||||
return r->visibility(vcpu, r) & REG_HIDDEN_GUEST;
|
||||
return r->visibility(vcpu, r) & REG_HIDDEN;
|
||||
}
|
||||
|
||||
static inline bool sysreg_hidden_from_user(const struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *r)
|
||||
static inline bool sysreg_visible_as_raz(const struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (likely(!r->visibility))
|
||||
return false;
|
||||
|
||||
return r->visibility(vcpu, r) & REG_HIDDEN_USER;
|
||||
return r->visibility(vcpu, r) & REG_RAZ;
|
||||
}
|
||||
|
||||
static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
|
||||
|
|
|
@ -63,7 +63,7 @@ static inline void restore_user_access(unsigned long flags)
|
|||
static inline bool
|
||||
bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
|
||||
{
|
||||
return WARN(!((regs->kuap ^ MD_APG_KUAP) & 0xf0000000),
|
||||
return WARN(!((regs->kuap ^ MD_APG_KUAP) & 0xff000000),
|
||||
"Bug: fault blocked by AP register !");
|
||||
}
|
||||
|
||||
|
|
|
@ -33,19 +33,18 @@
|
|||
* respectively NA for All or X for Supervisor and no access for User.
|
||||
* Then we use the APG to say whether accesses are according to Page rules or
|
||||
* "all Supervisor" rules (Access to all)
|
||||
* Therefore, we define 2 APG groups. lsb is _PMD_USER
|
||||
* 0 => Kernel => 01 (all accesses performed according to page definition)
|
||||
* 1 => User => 00 (all accesses performed as supervisor iaw page definition)
|
||||
* 2-15 => Not Used
|
||||
* _PAGE_ACCESSED is also managed via APG. When _PAGE_ACCESSED is not set, say
|
||||
* "all User" rules, that will lead to NA for all.
|
||||
* Therefore, we define 4 APG groups. lsb is _PAGE_ACCESSED
|
||||
* 0 => Kernel => 11 (all accesses performed according as user iaw page definition)
|
||||
* 1 => Kernel+Accessed => 01 (all accesses performed according to page definition)
|
||||
* 2 => User => 11 (all accesses performed according as user iaw page definition)
|
||||
* 3 => User+Accessed => 00 (all accesses performed as supervisor iaw page definition) for INIT
|
||||
* => 10 (all accesses performed according to swaped page definition) for KUEP
|
||||
* 4-15 => Not Used
|
||||
*/
|
||||
#define MI_APG_INIT 0x40000000
|
||||
|
||||
/*
|
||||
* 0 => Kernel => 01 (all accesses performed according to page definition)
|
||||
* 1 => User => 10 (all accesses performed according to swaped page definition)
|
||||
* 2-15 => Not Used
|
||||
*/
|
||||
#define MI_APG_KUEP 0x60000000
|
||||
#define MI_APG_INIT 0xdc000000
|
||||
#define MI_APG_KUEP 0xde000000
|
||||
|
||||
/* The effective page number register. When read, contains the information
|
||||
* about the last instruction TLB miss. When MI_RPN is written, bits in
|
||||
|
@ -106,25 +105,9 @@
|
|||
#define MD_Ks 0x80000000 /* Should not be set */
|
||||
#define MD_Kp 0x40000000 /* Should always be set */
|
||||
|
||||
/*
|
||||
* All pages' PP data bits are set to either 000 or 011 or 001, which means
|
||||
* respectively RW for Supervisor and no access for User, or RO for
|
||||
* Supervisor and no access for user and NA for ALL.
|
||||
* Then we use the APG to say whether accesses are according to Page rules or
|
||||
* "all Supervisor" rules (Access to all)
|
||||
* Therefore, we define 2 APG groups. lsb is _PMD_USER
|
||||
* 0 => Kernel => 01 (all accesses performed according to page definition)
|
||||
* 1 => User => 00 (all accesses performed as supervisor iaw page definition)
|
||||
* 2-15 => Not Used
|
||||
*/
|
||||
#define MD_APG_INIT 0x40000000
|
||||
|
||||
/*
|
||||
* 0 => No user => 01 (all accesses performed according to page definition)
|
||||
* 1 => User => 10 (all accesses performed according to swaped page definition)
|
||||
* 2-15 => Not Used
|
||||
*/
|
||||
#define MD_APG_KUAP 0x60000000
|
||||
/* See explanation above at the definition of MI_APG_INIT */
|
||||
#define MD_APG_INIT 0xdc000000
|
||||
#define MD_APG_KUAP 0xde000000
|
||||
|
||||
/* The effective page number register. When read, contains the information
|
||||
* about the last instruction TLB miss. When MD_RPN is written, bits in
|
||||
|
|
|
@ -39,9 +39,9 @@
|
|||
* into the TLB.
|
||||
*/
|
||||
#define _PAGE_GUARDED 0x0010 /* Copied to L1 G entry in DTLB */
|
||||
#define _PAGE_SPECIAL 0x0020 /* SW entry */
|
||||
#define _PAGE_ACCESSED 0x0020 /* Copied to L1 APG 1 entry in I/DTLB */
|
||||
#define _PAGE_EXEC 0x0040 /* Copied to PP (bit 21) in ITLB */
|
||||
#define _PAGE_ACCESSED 0x0080 /* software: page referenced */
|
||||
#define _PAGE_SPECIAL 0x0080 /* SW entry */
|
||||
|
||||
#define _PAGE_NA 0x0200 /* Supervisor NA, User no access */
|
||||
#define _PAGE_RO 0x0600 /* Supervisor RO, User no access */
|
||||
|
@ -59,11 +59,12 @@
|
|||
|
||||
#define _PMD_PRESENT 0x0001
|
||||
#define _PMD_PRESENT_MASK _PMD_PRESENT
|
||||
#define _PMD_BAD 0x0fd0
|
||||
#define _PMD_BAD 0x0f90
|
||||
#define _PMD_PAGE_MASK 0x000c
|
||||
#define _PMD_PAGE_8M 0x000c
|
||||
#define _PMD_PAGE_512K 0x0004
|
||||
#define _PMD_USER 0x0020 /* APG 1 */
|
||||
#define _PMD_ACCESSED 0x0020 /* APG 1 */
|
||||
#define _PMD_USER 0x0040 /* APG 2 */
|
||||
|
||||
#define _PTE_NONE_MASK 0
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
struct device;
|
||||
struct device_node;
|
||||
struct drmem_lmb;
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
|
||||
|
@ -61,6 +62,9 @@ static inline int early_cpu_to_node(int cpu)
|
|||
*/
|
||||
return (nid < 0) ? 0 : nid;
|
||||
}
|
||||
|
||||
int of_drconf_to_nid_single(struct drmem_lmb *lmb);
|
||||
|
||||
#else
|
||||
|
||||
static inline int early_cpu_to_node(int cpu) { return 0; }
|
||||
|
@ -84,10 +88,12 @@ static inline int cpu_distance(__be32 *cpu1_assoc, __be32 *cpu2_assoc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NUMA */
|
||||
static inline int of_drconf_to_nid_single(struct drmem_lmb *lmb)
|
||||
{
|
||||
return first_online_node;
|
||||
}
|
||||
|
||||
struct drmem_lmb;
|
||||
int of_drconf_to_nid_single(struct drmem_lmb *lmb);
|
||||
#endif /* CONFIG_NUMA */
|
||||
|
||||
#if defined(CONFIG_NUMA) && defined(CONFIG_PPC_SPLPAR)
|
||||
extern int find_and_online_cpu_nid(int cpu);
|
||||
|
|
|
@ -178,7 +178,7 @@ do { \
|
|||
* are no aliasing issues.
|
||||
*/
|
||||
#define __put_user_asm_goto(x, addr, label, op) \
|
||||
asm volatile goto( \
|
||||
asm_volatile_goto( \
|
||||
"1: " op "%U1%X1 %0,%1 # put_user\n" \
|
||||
EX_TABLE(1b, %l2) \
|
||||
: \
|
||||
|
@ -191,7 +191,7 @@ do { \
|
|||
__put_user_asm_goto(x, ptr, label, "std")
|
||||
#else /* __powerpc64__ */
|
||||
#define __put_user_asm2_goto(x, addr, label) \
|
||||
asm volatile goto( \
|
||||
asm_volatile_goto( \
|
||||
"1: stw%X1 %0, %1\n" \
|
||||
"2: stw%X1 %L0, %L1\n" \
|
||||
EX_TABLE(1b, %l2) \
|
||||
|
|
|
@ -264,8 +264,9 @@ static int eeh_addr_cache_show(struct seq_file *s, void *v)
|
|||
{
|
||||
struct pci_io_addr_range *piar;
|
||||
struct rb_node *n;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&pci_io_addr_cache_root.piar_lock);
|
||||
spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags);
|
||||
for (n = rb_first(&pci_io_addr_cache_root.rb_root); n; n = rb_next(n)) {
|
||||
piar = rb_entry(n, struct pci_io_addr_range, rb_node);
|
||||
|
||||
|
@ -273,7 +274,7 @@ static int eeh_addr_cache_show(struct seq_file *s, void *v)
|
|||
(piar->flags & IORESOURCE_IO) ? "i/o" : "mem",
|
||||
&piar->addr_lo, &piar->addr_hi, pci_name(piar->pcidev));
|
||||
}
|
||||
spin_unlock(&pci_io_addr_cache_root.piar_lock);
|
||||
spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -284,11 +284,7 @@ _ENTRY(saved_ksp_limit)
|
|||
|
||||
rlwimi r11, r10, 22, 20, 29 /* Compute PTE address */
|
||||
lwz r11, 0(r11) /* Get Linux PTE */
|
||||
#ifdef CONFIG_SWAP
|
||||
li r9, _PAGE_PRESENT | _PAGE_ACCESSED
|
||||
#else
|
||||
li r9, _PAGE_PRESENT
|
||||
#endif
|
||||
andc. r9, r9, r11 /* Check permission */
|
||||
bne 5f
|
||||
|
||||
|
@ -369,11 +365,7 @@ _ENTRY(saved_ksp_limit)
|
|||
|
||||
rlwimi r11, r10, 22, 20, 29 /* Compute PTE address */
|
||||
lwz r11, 0(r11) /* Get Linux PTE */
|
||||
#ifdef CONFIG_SWAP
|
||||
li r9, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
|
||||
#else
|
||||
li r9, _PAGE_PRESENT | _PAGE_EXEC
|
||||
#endif
|
||||
andc. r9, r9, r11 /* Check permission */
|
||||
bne 5f
|
||||
|
||||
|
|
|
@ -202,9 +202,7 @@ SystemCall:
|
|||
|
||||
InstructionTLBMiss:
|
||||
mtspr SPRN_SPRG_SCRATCH0, r10
|
||||
#if defined(ITLB_MISS_KERNEL) || defined(CONFIG_SWAP) || defined(CONFIG_HUGETLBFS)
|
||||
mtspr SPRN_SPRG_SCRATCH1, r11
|
||||
#endif
|
||||
|
||||
/* If we are faulting a kernel address, we have to use the
|
||||
* kernel page tables.
|
||||
|
@ -224,25 +222,13 @@ InstructionTLBMiss:
|
|||
3:
|
||||
mtcr r11
|
||||
#endif
|
||||
#if defined(CONFIG_HUGETLBFS) || !defined(CONFIG_PIN_TLB_TEXT)
|
||||
lwz r11, (swapper_pg_dir-PAGE_OFFSET)@l(r10) /* Get level 1 entry */
|
||||
mtspr SPRN_MD_TWC, r11
|
||||
#else
|
||||
lwz r10, (swapper_pg_dir-PAGE_OFFSET)@l(r10) /* Get level 1 entry */
|
||||
mtspr SPRN_MI_TWC, r10 /* Set segment attributes */
|
||||
mtspr SPRN_MD_TWC, r10
|
||||
#endif
|
||||
mfspr r10, SPRN_MD_TWC
|
||||
lwz r10, 0(r10) /* Get the pte */
|
||||
#if defined(CONFIG_HUGETLBFS) || !defined(CONFIG_PIN_TLB_TEXT)
|
||||
rlwimi r11, r10, 0, _PAGE_GUARDED | _PAGE_ACCESSED
|
||||
rlwimi r11, r10, 32 - 9, _PMD_PAGE_512K
|
||||
mtspr SPRN_MI_TWC, r11
|
||||
#endif
|
||||
#ifdef CONFIG_SWAP
|
||||
rlwinm r11, r10, 32-5, _PAGE_PRESENT
|
||||
and r11, r11, r10
|
||||
rlwimi r10, r11, 0, _PAGE_PRESENT
|
||||
#endif
|
||||
/* The Linux PTE won't go exactly into the MMU TLB.
|
||||
* Software indicator bits 20 and 23 must be clear.
|
||||
* Software indicator bits 22, 24, 25, 26, and 27 must be
|
||||
|
@ -256,9 +242,7 @@ InstructionTLBMiss:
|
|||
|
||||
/* Restore registers */
|
||||
0: mfspr r10, SPRN_SPRG_SCRATCH0
|
||||
#if defined(ITLB_MISS_KERNEL) || defined(CONFIG_SWAP) || defined(CONFIG_HUGETLBFS)
|
||||
mfspr r11, SPRN_SPRG_SCRATCH1
|
||||
#endif
|
||||
rfi
|
||||
patch_site 0b, patch__itlbmiss_exit_1
|
||||
|
||||
|
@ -268,9 +252,7 @@ InstructionTLBMiss:
|
|||
addi r10, r10, 1
|
||||
stw r10, (itlb_miss_counter - PAGE_OFFSET)@l(0)
|
||||
mfspr r10, SPRN_SPRG_SCRATCH0
|
||||
#if defined(ITLB_MISS_KERNEL) || defined(CONFIG_SWAP)
|
||||
mfspr r11, SPRN_SPRG_SCRATCH1
|
||||
#endif
|
||||
rfi
|
||||
#endif
|
||||
|
||||
|
@ -297,30 +279,16 @@ DataStoreTLBMiss:
|
|||
mfspr r10, SPRN_MD_TWC
|
||||
lwz r10, 0(r10) /* Get the pte */
|
||||
|
||||
/* Insert the Guarded flag into the TWC from the Linux PTE.
|
||||
/* Insert Guarded and Accessed flags into the TWC from the Linux PTE.
|
||||
* It is bit 27 of both the Linux PTE and the TWC (at least
|
||||
* I got that right :-). It will be better when we can put
|
||||
* this into the Linux pgd/pmd and load it in the operation
|
||||
* above.
|
||||
*/
|
||||
rlwimi r11, r10, 0, _PAGE_GUARDED
|
||||
rlwimi r11, r10, 0, _PAGE_GUARDED | _PAGE_ACCESSED
|
||||
rlwimi r11, r10, 32 - 9, _PMD_PAGE_512K
|
||||
mtspr SPRN_MD_TWC, r11
|
||||
|
||||
/* Both _PAGE_ACCESSED and _PAGE_PRESENT has to be set.
|
||||
* We also need to know if the insn is a load/store, so:
|
||||
* Clear _PAGE_PRESENT and load that which will
|
||||
* trap into DTLB Error with store bit set accordinly.
|
||||
*/
|
||||
/* PRESENT=0x1, ACCESSED=0x20
|
||||
* r11 = ((r10 & PRESENT) & ((r10 & ACCESSED) >> 5));
|
||||
* r10 = (r10 & ~PRESENT) | r11;
|
||||
*/
|
||||
#ifdef CONFIG_SWAP
|
||||
rlwinm r11, r10, 32-5, _PAGE_PRESENT
|
||||
and r11, r11, r10
|
||||
rlwimi r10, r11, 0, _PAGE_PRESENT
|
||||
#endif
|
||||
/* The Linux PTE won't go exactly into the MMU TLB.
|
||||
* Software indicator bits 24, 25, 26, and 27 must be
|
||||
* set. All other Linux PTE bits control the behavior
|
||||
|
@ -711,7 +679,7 @@ initial_mmu:
|
|||
li r9, 4 /* up to 4 pages of 8M */
|
||||
mtctr r9
|
||||
lis r9, KERNELBASE@h /* Create vaddr for TLB */
|
||||
li r10, MI_PS8MEG | MI_SVALID /* Set 8M byte page */
|
||||
li r10, MI_PS8MEG | _PMD_ACCESSED | MI_SVALID
|
||||
li r11, MI_BOOTINIT /* Create RPN for address 0 */
|
||||
1:
|
||||
mtspr SPRN_MI_CTR, r8 /* Set instruction MMU control */
|
||||
|
@ -775,7 +743,7 @@ _GLOBAL(mmu_pin_tlb)
|
|||
#ifdef CONFIG_PIN_TLB_TEXT
|
||||
LOAD_REG_IMMEDIATE(r5, 28 << 8)
|
||||
LOAD_REG_IMMEDIATE(r6, PAGE_OFFSET)
|
||||
LOAD_REG_IMMEDIATE(r7, MI_SVALID | MI_PS8MEG)
|
||||
LOAD_REG_IMMEDIATE(r7, MI_SVALID | MI_PS8MEG | _PMD_ACCESSED)
|
||||
LOAD_REG_IMMEDIATE(r8, 0xf0 | _PAGE_RO | _PAGE_SPS | _PAGE_SH | _PAGE_PRESENT)
|
||||
LOAD_REG_ADDR(r9, _sinittext)
|
||||
li r0, 4
|
||||
|
@ -797,7 +765,7 @@ _GLOBAL(mmu_pin_tlb)
|
|||
LOAD_REG_IMMEDIATE(r5, 28 << 8 | MD_TWAM)
|
||||
#ifdef CONFIG_PIN_TLB_DATA
|
||||
LOAD_REG_IMMEDIATE(r6, PAGE_OFFSET)
|
||||
LOAD_REG_IMMEDIATE(r7, MI_SVALID | MI_PS8MEG)
|
||||
LOAD_REG_IMMEDIATE(r7, MI_SVALID | MI_PS8MEG | _PMD_ACCESSED)
|
||||
#ifdef CONFIG_PIN_TLB_IMMR
|
||||
li r0, 3
|
||||
#else
|
||||
|
@ -834,7 +802,7 @@ _GLOBAL(mmu_pin_tlb)
|
|||
#endif
|
||||
#ifdef CONFIG_PIN_TLB_IMMR
|
||||
LOAD_REG_IMMEDIATE(r0, VIRT_IMMR_BASE | MD_EVALID)
|
||||
LOAD_REG_IMMEDIATE(r7, MD_SVALID | MD_PS512K | MD_GUARDED)
|
||||
LOAD_REG_IMMEDIATE(r7, MD_SVALID | MD_PS512K | MD_GUARDED | _PMD_ACCESSED)
|
||||
mfspr r8, SPRN_IMMR
|
||||
rlwinm r8, r8, 0, 0xfff80000
|
||||
ori r8, r8, 0xf0 | _PAGE_DIRTY | _PAGE_SPS | _PAGE_SH | \
|
||||
|
|
|
@ -457,11 +457,7 @@ InstructionTLBMiss:
|
|||
cmplw 0,r1,r3
|
||||
#endif
|
||||
mfspr r2, SPRN_SPRG_PGDIR
|
||||
#ifdef CONFIG_SWAP
|
||||
li r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
|
||||
#else
|
||||
li r1,_PAGE_PRESENT | _PAGE_EXEC
|
||||
#endif
|
||||
#if defined(CONFIG_MODULES) || defined(CONFIG_DEBUG_PAGEALLOC)
|
||||
bgt- 112f
|
||||
lis r2, (swapper_pg_dir - PAGE_OFFSET)@ha /* if kernel address, use */
|
||||
|
@ -523,11 +519,7 @@ DataLoadTLBMiss:
|
|||
lis r1, TASK_SIZE@h /* check if kernel address */
|
||||
cmplw 0,r1,r3
|
||||
mfspr r2, SPRN_SPRG_PGDIR
|
||||
#ifdef CONFIG_SWAP
|
||||
li r1, _PAGE_PRESENT | _PAGE_ACCESSED
|
||||
#else
|
||||
li r1, _PAGE_PRESENT
|
||||
#endif
|
||||
bgt- 112f
|
||||
lis r2, (swapper_pg_dir - PAGE_OFFSET)@ha /* if kernel address, use */
|
||||
addi r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l /* kernel page table */
|
||||
|
@ -603,11 +595,7 @@ DataStoreTLBMiss:
|
|||
lis r1, TASK_SIZE@h /* check if kernel address */
|
||||
cmplw 0,r1,r3
|
||||
mfspr r2, SPRN_SPRG_PGDIR
|
||||
#ifdef CONFIG_SWAP
|
||||
li r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED
|
||||
#else
|
||||
li r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT
|
||||
#endif
|
||||
bgt- 112f
|
||||
lis r2, (swapper_pg_dir - PAGE_OFFSET)@ha /* if kernel address, use */
|
||||
addi r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l /* kernel page table */
|
||||
|
|
|
@ -1393,13 +1393,14 @@ static void add_cpu_to_masks(int cpu)
|
|||
/* Activate a secondary processor. */
|
||||
void start_secondary(void *unused)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
unsigned int cpu = raw_smp_processor_id();
|
||||
|
||||
mmgrab(&init_mm);
|
||||
current->active_mm = &init_mm;
|
||||
|
||||
smp_store_cpu_info(cpu);
|
||||
set_dec(tb_ticks_per_jiffy);
|
||||
rcu_cpu_starting(cpu);
|
||||
preempt_disable();
|
||||
cpu_callin_map[cpu] = 1;
|
||||
|
||||
|
|
|
@ -476,7 +476,7 @@ do { \
|
|||
do { \
|
||||
long __kr_err; \
|
||||
\
|
||||
__put_user_nocheck(*((type *)(dst)), (type *)(src), __kr_err); \
|
||||
__put_user_nocheck(*((type *)(src)), (type *)(dst), __kr_err); \
|
||||
if (unlikely(__kr_err)) \
|
||||
goto err_label; \
|
||||
} while (0)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2013 Linaro Limited
|
||||
* Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
|
||||
|
|
|
@ -35,12 +35,17 @@ ENTRY(_start)
|
|||
.word 0
|
||||
#endif
|
||||
.balign 8
|
||||
#ifdef CONFIG_RISCV_M_MODE
|
||||
/* Image load offset (0MB) from start of RAM for M-mode */
|
||||
.dword 0
|
||||
#else
|
||||
#if __riscv_xlen == 64
|
||||
/* Image load offset(2MB) from start of RAM */
|
||||
.dword 0x200000
|
||||
#else
|
||||
/* Image load offset(4MB) from start of RAM */
|
||||
.dword 0x400000
|
||||
#endif
|
||||
#endif
|
||||
/* Effective size of kernel image */
|
||||
.dword _end - _start
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
vdso.lds
|
||||
*.tmp
|
||||
vdso-syms.S
|
||||
|
|
|
@ -43,19 +43,14 @@ $(obj)/vdso.o: $(obj)/vdso.so
|
|||
SYSCFLAGS_vdso.so.dbg = $(c_flags)
|
||||
$(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso) FORCE
|
||||
$(call if_changed,vdsold)
|
||||
SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \
|
||||
-Wl,--build-id -Wl,--hash-style=both
|
||||
|
||||
# We also create a special relocatable object that should mirror the symbol
|
||||
# table and layout of the linked DSO. With ld --just-symbols we can then
|
||||
# refer to these symbols in the kernel code rather than hand-coded addresses.
|
||||
|
||||
SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \
|
||||
-Wl,--build-id=sha1 -Wl,--hash-style=both
|
||||
$(obj)/vdso-dummy.o: $(src)/vdso.lds $(obj)/rt_sigreturn.o FORCE
|
||||
$(call if_changed,vdsold)
|
||||
|
||||
LDFLAGS_vdso-syms.o := -r --just-symbols
|
||||
$(obj)/vdso-syms.o: $(obj)/vdso-dummy.o FORCE
|
||||
$(call if_changed,ld)
|
||||
$(obj)/vdso-syms.S: $(obj)/vdso.so FORCE
|
||||
$(call if_changed,so2s)
|
||||
|
||||
# strip rule for the .so file
|
||||
$(obj)/%.so: OBJCOPYFLAGS := -S
|
||||
|
@ -73,6 +68,11 @@ quiet_cmd_vdsold = VDSOLD $@
|
|||
$(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@ && \
|
||||
rm $@.tmp
|
||||
|
||||
# Extracts symbol offsets from the VDSO, converting them into an assembly file
|
||||
# that contains the same symbols at the same offsets.
|
||||
quiet_cmd_so2s = SO2S $@
|
||||
cmd_so2s = $(NM) -D $< | $(srctree)/$(src)/so2s.sh > $@
|
||||
|
||||
# install commands for the unstripped file
|
||||
quiet_cmd_vdso_install = INSTALL $@
|
||||
cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright 2020 Palmer Dabbelt <palmerdabbelt@google.com>
|
||||
|
||||
sed 's!\([0-9a-f]*\) T \([a-z0-9_]*\)\(@@LINUX_4.15\)*!.global \2\n.set \2,0x\1!' \
|
||||
| grep '^\.'
|
|
@ -86,6 +86,7 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a
|
|||
pmd_t *pmd, *pmd_k;
|
||||
pte_t *pte_k;
|
||||
int index;
|
||||
unsigned long pfn;
|
||||
|
||||
/* User mode accesses just cause a SIGSEGV */
|
||||
if (user_mode(regs))
|
||||
|
@ -100,7 +101,8 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a
|
|||
* of a task switch.
|
||||
*/
|
||||
index = pgd_index(addr);
|
||||
pgd = (pgd_t *)pfn_to_virt(csr_read(CSR_SATP)) + index;
|
||||
pfn = csr_read(CSR_SATP) & SATP_PPN;
|
||||
pgd = (pgd_t *)pfn_to_virt(pfn) + index;
|
||||
pgd_k = init_mm.pgd + index;
|
||||
|
||||
if (!pgd_present(*pgd_k)) {
|
||||
|
|
|
@ -154,9 +154,8 @@ disable:
|
|||
|
||||
void __init setup_bootmem(void)
|
||||
{
|
||||
phys_addr_t mem_size = 0;
|
||||
phys_addr_t total_mem = 0;
|
||||
phys_addr_t mem_start, start, end = 0;
|
||||
phys_addr_t mem_start = 0;
|
||||
phys_addr_t start, end = 0;
|
||||
phys_addr_t vmlinux_end = __pa_symbol(&_end);
|
||||
phys_addr_t vmlinux_start = __pa_symbol(&_start);
|
||||
u64 i;
|
||||
|
@ -164,21 +163,18 @@ void __init setup_bootmem(void)
|
|||
/* Find the memory region containing the kernel */
|
||||
for_each_mem_range(i, &start, &end) {
|
||||
phys_addr_t size = end - start;
|
||||
if (!total_mem)
|
||||
if (!mem_start)
|
||||
mem_start = start;
|
||||
if (start <= vmlinux_start && vmlinux_end <= end)
|
||||
BUG_ON(size == 0);
|
||||
total_mem = total_mem + size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove memblock from the end of usable area to the
|
||||
* end of region
|
||||
* The maximal physical memory size is -PAGE_OFFSET.
|
||||
* Make sure that any memory beyond mem_start + (-PAGE_OFFSET) is removed
|
||||
* as it is unusable by kernel.
|
||||
*/
|
||||
mem_size = min(total_mem, (phys_addr_t)-PAGE_OFFSET);
|
||||
if (mem_start + mem_size < end)
|
||||
memblock_remove(mem_start + mem_size,
|
||||
end - mem_start - mem_size);
|
||||
memblock_enforce_memory_limit(mem_start - PAGE_OFFSET);
|
||||
|
||||
/* Reserve from the start of the kernel to the end of the kernel */
|
||||
memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start);
|
||||
|
@ -297,6 +293,7 @@ pmd_t fixmap_pmd[PTRS_PER_PMD] __page_aligned_bss;
|
|||
#define NUM_EARLY_PMDS (1UL + MAX_EARLY_MAPPING_SIZE / PGDIR_SIZE)
|
||||
#endif
|
||||
pmd_t early_pmd[PTRS_PER_PMD * NUM_EARLY_PMDS] __initdata __aligned(PAGE_SIZE);
|
||||
pmd_t early_dtb_pmd[PTRS_PER_PMD] __initdata __aligned(PAGE_SIZE);
|
||||
|
||||
static pmd_t *__init get_pmd_virt_early(phys_addr_t pa)
|
||||
{
|
||||
|
@ -494,6 +491,18 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
|
|||
load_pa + (va - PAGE_OFFSET),
|
||||
map_size, PAGE_KERNEL_EXEC);
|
||||
|
||||
#ifndef __PAGETABLE_PMD_FOLDED
|
||||
/* Setup early PMD for DTB */
|
||||
create_pgd_mapping(early_pg_dir, DTB_EARLY_BASE_VA,
|
||||
(uintptr_t)early_dtb_pmd, PGDIR_SIZE, PAGE_TABLE);
|
||||
/* Create two consecutive PMD mappings for FDT early scan */
|
||||
pa = dtb_pa & ~(PMD_SIZE - 1);
|
||||
create_pmd_mapping(early_dtb_pmd, DTB_EARLY_BASE_VA,
|
||||
pa, PMD_SIZE, PAGE_KERNEL);
|
||||
create_pmd_mapping(early_dtb_pmd, DTB_EARLY_BASE_VA + PMD_SIZE,
|
||||
pa + PMD_SIZE, PMD_SIZE, PAGE_KERNEL);
|
||||
dtb_early_va = (void *)DTB_EARLY_BASE_VA + (dtb_pa & (PMD_SIZE - 1));
|
||||
#else
|
||||
/* Create two consecutive PGD mappings for FDT early scan */
|
||||
pa = dtb_pa & ~(PGDIR_SIZE - 1);
|
||||
create_pgd_mapping(early_pg_dir, DTB_EARLY_BASE_VA,
|
||||
|
@ -501,6 +510,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
|
|||
create_pgd_mapping(early_pg_dir, DTB_EARLY_BASE_VA + PGDIR_SIZE,
|
||||
pa + PGDIR_SIZE, PGDIR_SIZE, PAGE_KERNEL);
|
||||
dtb_early_va = (void *)DTB_EARLY_BASE_VA + (dtb_pa & (PGDIR_SIZE - 1));
|
||||
#endif
|
||||
dtb_early_pa = dtb_pa;
|
||||
|
||||
/*
|
||||
|
|
|
@ -290,6 +290,9 @@ static void __init uv_stringify(int len, char *to, char *from)
|
|||
{
|
||||
/* Relies on 'to' being NULL chars so result will be NULL terminated */
|
||||
strncpy(to, from, len-1);
|
||||
|
||||
/* Trim trailing spaces */
|
||||
(void)strim(to);
|
||||
}
|
||||
|
||||
/* Find UV arch type entry in UVsystab */
|
||||
|
@ -366,7 +369,7 @@ static int __init early_get_arch_type(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __init uv_set_system_type(char *_oem_id)
|
||||
static int __init uv_set_system_type(char *_oem_id, char *_oem_table_id)
|
||||
{
|
||||
/* Save OEM_ID passed from ACPI MADT */
|
||||
uv_stringify(sizeof(oem_id), oem_id, _oem_id);
|
||||
|
@ -386,13 +389,23 @@ static int __init uv_set_system_type(char *_oem_id)
|
|||
/* (Not hubless), not a UV */
|
||||
return 0;
|
||||
|
||||
/* Is UV hubless system */
|
||||
uv_hubless_system = 0x01;
|
||||
|
||||
/* UV5 Hubless */
|
||||
if (strncmp(uv_archtype, "NSGI5", 5) == 0)
|
||||
uv_hubless_system |= 0x20;
|
||||
|
||||
/* UV4 Hubless: CH */
|
||||
if (strncmp(uv_archtype, "NSGI4", 5) == 0)
|
||||
uv_hubless_system = 0x11;
|
||||
else if (strncmp(uv_archtype, "NSGI4", 5) == 0)
|
||||
uv_hubless_system |= 0x10;
|
||||
|
||||
/* UV3 Hubless: UV300/MC990X w/o hub */
|
||||
else
|
||||
uv_hubless_system = 0x9;
|
||||
uv_hubless_system |= 0x8;
|
||||
|
||||
/* Copy APIC type */
|
||||
uv_stringify(sizeof(oem_table_id), oem_table_id, _oem_table_id);
|
||||
|
||||
pr_info("UV: OEM IDs %s/%s, SystemType %d, HUBLESS ID %x\n",
|
||||
oem_id, oem_table_id, uv_system_type, uv_hubless_system);
|
||||
|
@ -456,7 +469,7 @@ static int __init uv_acpi_madt_oem_check(char *_oem_id, char *_oem_table_id)
|
|||
uv_cpu_info->p_uv_hub_info = &uv_hub_info_node0;
|
||||
|
||||
/* If not UV, return. */
|
||||
if (likely(uv_set_system_type(_oem_id) == 0))
|
||||
if (uv_set_system_type(_oem_id, _oem_table_id) == 0)
|
||||
return 0;
|
||||
|
||||
/* Save and Decode OEM Table ID */
|
||||
|
|
|
@ -1254,6 +1254,14 @@ static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool is_spec_ib_user_controlled(void)
|
||||
{
|
||||
return spectre_v2_user_ibpb == SPECTRE_V2_USER_PRCTL ||
|
||||
spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP ||
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_PRCTL ||
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_SECCOMP;
|
||||
}
|
||||
|
||||
static int ib_prctl_set(struct task_struct *task, unsigned long ctrl)
|
||||
{
|
||||
switch (ctrl) {
|
||||
|
@ -1261,16 +1269,26 @@ static int ib_prctl_set(struct task_struct *task, unsigned long ctrl)
|
|||
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Indirect branch speculation is always disabled in strict
|
||||
* mode. It can neither be enabled if it was force-disabled
|
||||
* by a previous prctl call.
|
||||
* With strict mode for both IBPB and STIBP, the instruction
|
||||
* code paths avoid checking this task flag and instead,
|
||||
* unconditionally run the instruction. However, STIBP and IBPB
|
||||
* are independent and either can be set to conditionally
|
||||
* enabled regardless of the mode of the other.
|
||||
*
|
||||
* If either is set to conditional, allow the task flag to be
|
||||
* updated, unless it was force-disabled by a previous prctl
|
||||
* call. Currently, this is possible on an AMD CPU which has the
|
||||
* feature X86_FEATURE_AMD_STIBP_ALWAYS_ON. In this case, if the
|
||||
* kernel is booted with 'spectre_v2_user=seccomp', then
|
||||
* spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP and
|
||||
* spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED.
|
||||
*/
|
||||
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED ||
|
||||
if (!is_spec_ib_user_controlled() ||
|
||||
task_spec_ib_force_disable(task))
|
||||
return -EPERM;
|
||||
|
||||
task_clear_spec_ib_disable(task);
|
||||
task_update_spec_tif(task);
|
||||
break;
|
||||
|
@ -1283,10 +1301,10 @@ static int ib_prctl_set(struct task_struct *task, unsigned long ctrl)
|
|||
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
|
||||
return -EPERM;
|
||||
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED)
|
||||
|
||||
if (!is_spec_ib_user_controlled())
|
||||
return 0;
|
||||
|
||||
task_set_spec_ib_disable(task);
|
||||
if (ctrl == PR_SPEC_FORCE_DISABLE)
|
||||
task_set_spec_ib_force_disable(task);
|
||||
|
@ -1351,20 +1369,17 @@ static int ib_prctl_get(struct task_struct *task)
|
|||
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
|
||||
return PR_SPEC_ENABLE;
|
||||
else if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED)
|
||||
return PR_SPEC_DISABLE;
|
||||
else if (spectre_v2_user_ibpb == SPECTRE_V2_USER_PRCTL ||
|
||||
spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP ||
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_PRCTL ||
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_SECCOMP) {
|
||||
else if (is_spec_ib_user_controlled()) {
|
||||
if (task_spec_ib_force_disable(task))
|
||||
return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
|
||||
if (task_spec_ib_disable(task))
|
||||
return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
|
||||
return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
|
||||
} else
|
||||
} else if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
|
||||
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED)
|
||||
return PR_SPEC_DISABLE;
|
||||
else
|
||||
return PR_SPEC_NOT_AFFECTED;
|
||||
}
|
||||
|
||||
|
|
|
@ -90,6 +90,20 @@ static int kvm_check_cpuid(struct kvm_cpuid_entry2 *entries, int nent)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void kvm_update_pv_runtime(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_cpuid_entry2 *best;
|
||||
|
||||
best = kvm_find_cpuid_entry(vcpu, KVM_CPUID_FEATURES, 0);
|
||||
|
||||
/*
|
||||
* save the feature bitmap to avoid cpuid lookup for every PV
|
||||
* operation
|
||||
*/
|
||||
if (best)
|
||||
vcpu->arch.pv_cpuid.features = best->eax;
|
||||
}
|
||||
|
||||
void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_cpuid_entry2 *best;
|
||||
|
@ -124,13 +138,6 @@ void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu)
|
|||
(best->eax & (1 << KVM_FEATURE_PV_UNHALT)))
|
||||
best->eax &= ~(1 << KVM_FEATURE_PV_UNHALT);
|
||||
|
||||
/*
|
||||
* save the feature bitmap to avoid cpuid lookup for every PV
|
||||
* operation
|
||||
*/
|
||||
if (best)
|
||||
vcpu->arch.pv_cpuid.features = best->eax;
|
||||
|
||||
if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT)) {
|
||||
best = kvm_find_cpuid_entry(vcpu, 0x1, 0);
|
||||
if (best)
|
||||
|
@ -162,6 +169,8 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
|
|||
vcpu->arch.guest_supported_xcr0 =
|
||||
(best->eax | ((u64)best->edx << 32)) & supported_xcr0;
|
||||
|
||||
kvm_update_pv_runtime(vcpu);
|
||||
|
||||
vcpu->arch.maxphyaddr = cpuid_query_maxphyaddr(vcpu);
|
||||
kvm_mmu_reset_context(vcpu);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ extern u32 kvm_cpu_caps[NCAPINTS] __read_mostly;
|
|||
void kvm_set_cpu_caps(void);
|
||||
|
||||
void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu);
|
||||
void kvm_update_pv_runtime(struct kvm_vcpu *vcpu);
|
||||
struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
|
||||
u32 function, u32 index);
|
||||
int kvm_dev_ioctl_get_cpuid(struct kvm_cpuid2 *cpuid,
|
||||
|
|
|
@ -856,12 +856,14 @@ static int pte_list_add(struct kvm_vcpu *vcpu, u64 *spte,
|
|||
} else {
|
||||
rmap_printk("pte_list_add: %p %llx many->many\n", spte, *spte);
|
||||
desc = (struct pte_list_desc *)(rmap_head->val & ~1ul);
|
||||
while (desc->sptes[PTE_LIST_EXT-1] && desc->more) {
|
||||
desc = desc->more;
|
||||
while (desc->sptes[PTE_LIST_EXT-1]) {
|
||||
count += PTE_LIST_EXT;
|
||||
}
|
||||
if (desc->sptes[PTE_LIST_EXT-1]) {
|
||||
desc->more = mmu_alloc_pte_list_desc(vcpu);
|
||||
|
||||
if (!desc->more) {
|
||||
desc->more = mmu_alloc_pte_list_desc(vcpu);
|
||||
desc = desc->more;
|
||||
break;
|
||||
}
|
||||
desc = desc->more;
|
||||
}
|
||||
for (i = 0; desc->sptes[i]; ++i)
|
||||
|
|
|
@ -255,11 +255,10 @@ static struct kmem_cache *x86_emulator_cache;
|
|||
|
||||
/*
|
||||
* When called, it means the previous get/set msr reached an invalid msr.
|
||||
* Return 0 if we want to ignore/silent this failed msr access, or 1 if we want
|
||||
* to fail the caller.
|
||||
* Return true if we want to ignore/silent this failed msr access.
|
||||
*/
|
||||
static int kvm_msr_ignored_check(struct kvm_vcpu *vcpu, u32 msr,
|
||||
u64 data, bool write)
|
||||
static bool kvm_msr_ignored_check(struct kvm_vcpu *vcpu, u32 msr,
|
||||
u64 data, bool write)
|
||||
{
|
||||
const char *op = write ? "wrmsr" : "rdmsr";
|
||||
|
||||
|
@ -268,11 +267,11 @@ static int kvm_msr_ignored_check(struct kvm_vcpu *vcpu, u32 msr,
|
|||
kvm_pr_unimpl("ignored %s: 0x%x data 0x%llx\n",
|
||||
op, msr, data);
|
||||
/* Mask the error */
|
||||
return 0;
|
||||
return true;
|
||||
} else {
|
||||
kvm_debug_ratelimited("unhandled %s: 0x%x data 0x%llx\n",
|
||||
op, msr, data);
|
||||
return -ENOENT;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1416,7 +1415,8 @@ static int do_get_msr_feature(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
|
|||
if (r == KVM_MSR_RET_INVALID) {
|
||||
/* Unconditionally clear the output for simplicity */
|
||||
*data = 0;
|
||||
r = kvm_msr_ignored_check(vcpu, index, 0, false);
|
||||
if (kvm_msr_ignored_check(vcpu, index, 0, false))
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (r)
|
||||
|
@ -1540,7 +1540,7 @@ static int __kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data,
|
|||
struct msr_data msr;
|
||||
|
||||
if (!host_initiated && !kvm_msr_allowed(vcpu, index, KVM_MSR_FILTER_WRITE))
|
||||
return -EPERM;
|
||||
return KVM_MSR_RET_FILTERED;
|
||||
|
||||
switch (index) {
|
||||
case MSR_FS_BASE:
|
||||
|
@ -1581,7 +1581,8 @@ static int kvm_set_msr_ignored_check(struct kvm_vcpu *vcpu,
|
|||
int ret = __kvm_set_msr(vcpu, index, data, host_initiated);
|
||||
|
||||
if (ret == KVM_MSR_RET_INVALID)
|
||||
ret = kvm_msr_ignored_check(vcpu, index, data, true);
|
||||
if (kvm_msr_ignored_check(vcpu, index, data, true))
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1599,7 +1600,7 @@ int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data,
|
|||
int ret;
|
||||
|
||||
if (!host_initiated && !kvm_msr_allowed(vcpu, index, KVM_MSR_FILTER_READ))
|
||||
return -EPERM;
|
||||
return KVM_MSR_RET_FILTERED;
|
||||
|
||||
msr.index = index;
|
||||
msr.host_initiated = host_initiated;
|
||||
|
@ -1618,7 +1619,8 @@ static int kvm_get_msr_ignored_check(struct kvm_vcpu *vcpu,
|
|||
if (ret == KVM_MSR_RET_INVALID) {
|
||||
/* Unconditionally clear *data for simplicity */
|
||||
*data = 0;
|
||||
ret = kvm_msr_ignored_check(vcpu, index, 0, false);
|
||||
if (kvm_msr_ignored_check(vcpu, index, 0, false))
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1662,9 +1664,9 @@ static int complete_emulated_wrmsr(struct kvm_vcpu *vcpu)
|
|||
static u64 kvm_msr_reason(int r)
|
||||
{
|
||||
switch (r) {
|
||||
case -ENOENT:
|
||||
case KVM_MSR_RET_INVALID:
|
||||
return KVM_MSR_EXIT_REASON_UNKNOWN;
|
||||
case -EPERM:
|
||||
case KVM_MSR_RET_FILTERED:
|
||||
return KVM_MSR_EXIT_REASON_FILTER;
|
||||
default:
|
||||
return KVM_MSR_EXIT_REASON_INVAL;
|
||||
|
@ -1965,7 +1967,7 @@ static void kvm_write_system_time(struct kvm_vcpu *vcpu, gpa_t system_time,
|
|||
struct kvm_arch *ka = &vcpu->kvm->arch;
|
||||
|
||||
if (vcpu->vcpu_id == 0 && !host_initiated) {
|
||||
if (ka->boot_vcpu_runs_old_kvmclock && old_msr)
|
||||
if (ka->boot_vcpu_runs_old_kvmclock != old_msr)
|
||||
kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
|
||||
|
||||
ka->boot_vcpu_runs_old_kvmclock = old_msr;
|
||||
|
@ -3063,9 +3065,9 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|||
/* Values other than LBR and BTF are vendor-specific,
|
||||
thus reserved and should throw a #GP */
|
||||
return 1;
|
||||
}
|
||||
vcpu_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTLMSR 0x%llx, nop\n",
|
||||
__func__, data);
|
||||
} else if (report_ignored_msrs)
|
||||
vcpu_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTLMSR 0x%llx, nop\n",
|
||||
__func__, data);
|
||||
break;
|
||||
case 0x200 ... 0x2ff:
|
||||
return kvm_mtrr_set_msr(vcpu, msr, data);
|
||||
|
@ -3463,29 +3465,63 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|||
msr_info->data = vcpu->arch.efer;
|
||||
break;
|
||||
case MSR_KVM_WALL_CLOCK:
|
||||
if (!guest_pv_has(vcpu, KVM_FEATURE_CLOCKSOURCE))
|
||||
return 1;
|
||||
|
||||
msr_info->data = vcpu->kvm->arch.wall_clock;
|
||||
break;
|
||||
case MSR_KVM_WALL_CLOCK_NEW:
|
||||
if (!guest_pv_has(vcpu, KVM_FEATURE_CLOCKSOURCE2))
|
||||
return 1;
|
||||
|
||||
msr_info->data = vcpu->kvm->arch.wall_clock;
|
||||
break;
|
||||
case MSR_KVM_SYSTEM_TIME:
|
||||
if (!guest_pv_has(vcpu, KVM_FEATURE_CLOCKSOURCE))
|
||||
return 1;
|
||||
|
||||
msr_info->data = vcpu->arch.time;
|
||||
break;
|
||||
case MSR_KVM_SYSTEM_TIME_NEW:
|
||||
if (!guest_pv_has(vcpu, KVM_FEATURE_CLOCKSOURCE2))
|
||||
return 1;
|
||||
|
||||
msr_info->data = vcpu->arch.time;
|
||||
break;
|
||||
case MSR_KVM_ASYNC_PF_EN:
|
||||
if (!guest_pv_has(vcpu, KVM_FEATURE_ASYNC_PF))
|
||||
return 1;
|
||||
|
||||
msr_info->data = vcpu->arch.apf.msr_en_val;
|
||||
break;
|
||||
case MSR_KVM_ASYNC_PF_INT:
|
||||
if (!guest_pv_has(vcpu, KVM_FEATURE_ASYNC_PF_INT))
|
||||
return 1;
|
||||
|
||||
msr_info->data = vcpu->arch.apf.msr_int_val;
|
||||
break;
|
||||
case MSR_KVM_ASYNC_PF_ACK:
|
||||
if (!guest_pv_has(vcpu, KVM_FEATURE_ASYNC_PF))
|
||||
return 1;
|
||||
|
||||
msr_info->data = 0;
|
||||
break;
|
||||
case MSR_KVM_STEAL_TIME:
|
||||
if (!guest_pv_has(vcpu, KVM_FEATURE_STEAL_TIME))
|
||||
return 1;
|
||||
|
||||
msr_info->data = vcpu->arch.st.msr_val;
|
||||
break;
|
||||
case MSR_KVM_PV_EOI_EN:
|
||||
if (!guest_pv_has(vcpu, KVM_FEATURE_PV_EOI))
|
||||
return 1;
|
||||
|
||||
msr_info->data = vcpu->arch.pv_eoi.msr_val;
|
||||
break;
|
||||
case MSR_KVM_POLL_CONTROL:
|
||||
if (!guest_pv_has(vcpu, KVM_FEATURE_POLL_CONTROL))
|
||||
return 1;
|
||||
|
||||
msr_info->data = vcpu->arch.msr_kvm_poll_control;
|
||||
break;
|
||||
case MSR_IA32_P5_MC_ADDR:
|
||||
|
@ -4575,6 +4611,8 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
|
|||
|
||||
case KVM_CAP_ENFORCE_PV_FEATURE_CPUID:
|
||||
vcpu->arch.pv_cpuid.enforce = cap->args[0];
|
||||
if (vcpu->arch.pv_cpuid.enforce)
|
||||
kvm_update_pv_runtime(vcpu);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -376,7 +376,13 @@ int kvm_handle_memory_failure(struct kvm_vcpu *vcpu, int r,
|
|||
int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva);
|
||||
bool kvm_msr_allowed(struct kvm_vcpu *vcpu, u32 index, u32 type);
|
||||
|
||||
#define KVM_MSR_RET_INVALID 2
|
||||
/*
|
||||
* Internal error codes that are used to indicate that MSR emulation encountered
|
||||
* an error that should result in #GP in the guest, unless userspace
|
||||
* handles it.
|
||||
*/
|
||||
#define KVM_MSR_RET_INVALID 2 /* in-kernel MSR emulation #GP condition */
|
||||
#define KVM_MSR_RET_FILTERED 3 /* #GP due to userspace MSR filter */
|
||||
|
||||
#define __cr4_reserved_bits(__cpu_has, __c) \
|
||||
({ \
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
* to a jmp to memcpy_erms which does the REP; MOVSB mem copy.
|
||||
*/
|
||||
|
||||
.weak memcpy
|
||||
|
||||
/*
|
||||
* memcpy - Copy a memory block.
|
||||
*
|
||||
|
@ -30,7 +28,7 @@
|
|||
* rax original destination
|
||||
*/
|
||||
SYM_FUNC_START_ALIAS(__memcpy)
|
||||
SYM_FUNC_START_LOCAL(memcpy)
|
||||
SYM_FUNC_START_WEAK(memcpy)
|
||||
ALTERNATIVE_2 "jmp memcpy_orig", "", X86_FEATURE_REP_GOOD, \
|
||||
"jmp memcpy_erms", X86_FEATURE_ERMS
|
||||
|
||||
|
|
|
@ -24,9 +24,7 @@
|
|||
* Output:
|
||||
* rax: dest
|
||||
*/
|
||||
.weak memmove
|
||||
|
||||
SYM_FUNC_START_ALIAS(memmove)
|
||||
SYM_FUNC_START_WEAK(memmove)
|
||||
SYM_FUNC_START(__memmove)
|
||||
|
||||
mov %rdi, %rax
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
#include <asm/alternative-asm.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
.weak memset
|
||||
|
||||
/*
|
||||
* ISO C memset - set a memory block to a byte value. This function uses fast
|
||||
* string to get better performance than the original function. The code is
|
||||
|
@ -19,7 +17,7 @@
|
|||
*
|
||||
* rax original destination
|
||||
*/
|
||||
SYM_FUNC_START_ALIAS(memset)
|
||||
SYM_FUNC_START_WEAK(memset)
|
||||
SYM_FUNC_START(__memset)
|
||||
/*
|
||||
* Some CPUs support enhanced REP MOVSB/STOSB feature. It is recommended
|
||||
|
|
|
@ -578,7 +578,7 @@ acpi_video_bqc_value_to_level(struct acpi_video_device *device,
|
|||
ACPI_VIDEO_FIRST_LEVEL - 1 - bqc_value;
|
||||
|
||||
level = device->brightness->levels[bqc_value +
|
||||
ACPI_VIDEO_FIRST_LEVEL];
|
||||
ACPI_VIDEO_FIRST_LEVEL];
|
||||
} else {
|
||||
level = bqc_value;
|
||||
}
|
||||
|
@ -990,8 +990,8 @@ set_level:
|
|||
goto out_free_levels;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"found %d brightness levels\n",
|
||||
br->count - ACPI_VIDEO_FIRST_LEVEL));
|
||||
"found %d brightness levels\n",
|
||||
br->count - ACPI_VIDEO_FIRST_LEVEL));
|
||||
return 0;
|
||||
|
||||
out_free_levels:
|
||||
|
|
|
@ -987,7 +987,7 @@ static int acpi_battery_update(struct acpi_battery *battery, bool resume)
|
|||
*/
|
||||
if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) ||
|
||||
(test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
|
||||
(battery->capacity_now <= battery->alarm)))
|
||||
(battery->capacity_now <= battery->alarm)))
|
||||
acpi_pm_wakeup_event(&battery->device->dev);
|
||||
|
||||
return result;
|
||||
|
|
|
@ -89,7 +89,18 @@ static const struct dmi_system_id dmi_lid_quirks[] = {
|
|||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "E2215T MD60198"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "E2215T"),
|
||||
},
|
||||
.driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Medion Akoya E2228T, notification of the LID device only
|
||||
* happens on close, not on open and _LID always returns closed.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "E2228T"),
|
||||
},
|
||||
.driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
|
||||
},
|
||||
|
|
|
@ -106,6 +106,7 @@ static int pch_fivr_remove(struct platform_device *pdev)
|
|||
|
||||
static const struct acpi_device_id pch_fivr_device_ids[] = {
|
||||
{"INTC1045", 0},
|
||||
{"INTC1049", 0},
|
||||
{"", 0},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, pch_fivr_device_ids);
|
||||
|
|
|
@ -229,6 +229,8 @@ static const struct acpi_device_id int3407_device_ids[] = {
|
|||
{"INT3532", 0},
|
||||
{"INTC1047", 0},
|
||||
{"INTC1050", 0},
|
||||
{"INTC1060", 0},
|
||||
{"INTC1061", 0},
|
||||
{"", 0},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, int3407_device_ids);
|
||||
|
|
|
@ -25,10 +25,16 @@ static const struct acpi_device_id int340x_thermal_device_ids[] = {
|
|||
{"INT340A"},
|
||||
{"INT340B"},
|
||||
{"INTC1040"},
|
||||
{"INTC1041"},
|
||||
{"INTC1043"},
|
||||
{"INTC1044"},
|
||||
{"INTC1045"},
|
||||
{"INTC1046"},
|
||||
{"INTC1047"},
|
||||
{"INTC1048"},
|
||||
{"INTC1049"},
|
||||
{"INTC1060"},
|
||||
{"INTC1061"},
|
||||
{""},
|
||||
};
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data)
|
|||
event.type = type;
|
||||
event.data = data;
|
||||
return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event)
|
||||
== NOTIFY_BAD) ? -EINVAL : 0;
|
||||
== NOTIFY_BAD) ? -EINVAL : 0;
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_notifier_call_chain);
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares,
|
|||
|
||||
switch (gsi) {
|
||||
case 0 ... 255:
|
||||
sprintf(ev_name, "_%c%02hhX",
|
||||
sprintf(ev_name, "_%c%02X",
|
||||
trigger == ACPI_EDGE_SENSITIVE ? 'E' : 'L', gsi);
|
||||
|
||||
if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle)))
|
||||
|
|
|
@ -27,6 +27,7 @@ static const struct acpi_device_id fan_device_ids[] = {
|
|||
{"PNP0C0B", 0},
|
||||
{"INT3404", 0},
|
||||
{"INTC1044", 0},
|
||||
{"INTC1048", 0},
|
||||
{"", 0},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, fan_device_ids);
|
||||
|
|
|
@ -134,7 +134,7 @@ int acpi_add_power_resource(acpi_handle handle);
|
|||
void acpi_power_add_remove_device(struct acpi_device *adev, bool add);
|
||||
int acpi_power_wakeup_list_init(struct list_head *list, int *system_level);
|
||||
int acpi_device_sleep_wake(struct acpi_device *dev,
|
||||
int enable, int sleep_state, int dev_state);
|
||||
int enable, int sleep_state, int dev_state);
|
||||
int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
|
||||
int acpi_power_on_resources(struct acpi_device *device, int state);
|
||||
int acpi_power_transition(struct acpi_device *device, int state);
|
||||
|
|
|
@ -2175,10 +2175,10 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
|
|||
* these commands.
|
||||
*/
|
||||
enum nfit_aux_cmds {
|
||||
NFIT_CMD_TRANSLATE_SPA = 5,
|
||||
NFIT_CMD_ARS_INJECT_SET = 7,
|
||||
NFIT_CMD_ARS_INJECT_CLEAR = 8,
|
||||
NFIT_CMD_ARS_INJECT_GET = 9,
|
||||
NFIT_CMD_TRANSLATE_SPA = 5,
|
||||
NFIT_CMD_ARS_INJECT_SET = 7,
|
||||
NFIT_CMD_ARS_INJECT_CLEAR = 8,
|
||||
NFIT_CMD_ARS_INJECT_GET = 9,
|
||||
};
|
||||
|
||||
static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
|
||||
|
@ -2632,7 +2632,7 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
|
|||
nfit_blk->bdw_offset = nfit_mem->bdw->offset;
|
||||
mmio = &nfit_blk->mmio[BDW];
|
||||
mmio->addr.base = devm_nvdimm_memremap(dev, nfit_mem->spa_bdw->address,
|
||||
nfit_mem->spa_bdw->length, nd_blk_memremap_flags(ndbr));
|
||||
nfit_mem->spa_bdw->length, nd_blk_memremap_flags(ndbr));
|
||||
if (!mmio->addr.base) {
|
||||
dev_dbg(dev, "%s failed to map bdw\n",
|
||||
nvdimm_name(nvdimm));
|
||||
|
|
|
@ -175,7 +175,7 @@ static int acpi_pci_irq_check_entry(acpi_handle handle, struct pci_dev *dev,
|
|||
* configure the IRQ assigned to this slot|dev|pin. The 'source_index'
|
||||
* indicates which resource descriptor in the resource template (of
|
||||
* the link device) this interrupt is allocated from.
|
||||
*
|
||||
*
|
||||
* NOTE: Don't query the Link Device for IRQ information at this time
|
||||
* because Link Device enumeration may not have occurred yet
|
||||
* (e.g. exists somewhere 'below' this _PRT entry in the ACPI
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
|
||||
* Copyright (C) 2002 Dominik Brodowski <devel@brodo.de>
|
||||
*
|
||||
* TBD:
|
||||
* 1. Support more than one IRQ resource entry per link device (index).
|
||||
* TBD:
|
||||
* 1. Support more than one IRQ resource entry per link device (index).
|
||||
* 2. Implement start/stop mechanism and use ACPI Bus Driver facilities
|
||||
* for IRQ management (e.g. start()->_SRS).
|
||||
*/
|
||||
|
@ -249,8 +249,8 @@ static int acpi_pci_link_get_current(struct acpi_pci_link *link)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Query and parse _CRS to get the current IRQ assignment.
|
||||
/*
|
||||
* Query and parse _CRS to get the current IRQ assignment.
|
||||
*/
|
||||
|
||||
status = acpi_walk_resources(link->device->handle, METHOD_NAME__CRS,
|
||||
|
@ -396,7 +396,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
|
|||
/*
|
||||
* "acpi_irq_balance" (default in APIC mode) enables ACPI to use PIC Interrupt
|
||||
* Link Devices to move the PIRQs around to minimize sharing.
|
||||
*
|
||||
*
|
||||
* "acpi_irq_nobalance" (default in PIC mode) tells ACPI not to move any PIC IRQs
|
||||
* that the BIOS has already set to active. This is necessary because
|
||||
* ACPI has no automatic means of knowing what ISA IRQs are used. Note that
|
||||
|
@ -414,7 +414,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
|
|||
*
|
||||
* Note that PCI IRQ routers have a list of possible IRQs,
|
||||
* which may not include the IRQs this table says are available.
|
||||
*
|
||||
*
|
||||
* Since this heuristic can't tell the difference between a link
|
||||
* that no device will attach to, vs. a link which may be shared
|
||||
* by multiple active devices -- it is not optimal.
|
||||
|
|
|
@ -173,7 +173,7 @@ static int pci_mcfg_quirk_matches(struct mcfg_fixup *f, u16 segment,
|
|||
{
|
||||
if (!memcmp(f->oem_id, mcfg_oem_id, ACPI_OEM_ID_SIZE) &&
|
||||
!memcmp(f->oem_table_id, mcfg_oem_table_id,
|
||||
ACPI_OEM_TABLE_ID_SIZE) &&
|
||||
ACPI_OEM_TABLE_ID_SIZE) &&
|
||||
f->oem_revision == mcfg_oem_revision &&
|
||||
f->segment == segment &&
|
||||
resource_contains(&f->bus_range, bus_range))
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
* 1. via "Device Specific (D-State) Control"
|
||||
* 2. via "Power Resource Control".
|
||||
* The code below deals with ACPI Power Resources control.
|
||||
*
|
||||
*
|
||||
* An ACPI "power resource object" represents a software controllable power
|
||||
* plane, clock plane, or other resource depended on by a device.
|
||||
*
|
||||
|
@ -645,7 +645,7 @@ int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p)
|
|||
* -ENODEV if the execution of either _DSW or _PSW has failed
|
||||
*/
|
||||
int acpi_device_sleep_wake(struct acpi_device *dev,
|
||||
int enable, int sleep_state, int dev_state)
|
||||
int enable, int sleep_state, int dev_state)
|
||||
{
|
||||
union acpi_object in_arg[3];
|
||||
struct acpi_object_list arg_list = { 3, in_arg };
|
||||
|
@ -690,7 +690,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev,
|
|||
|
||||
/*
|
||||
* Prepare a wakeup device, two steps (Ref ACPI 2.0:P229):
|
||||
* 1. Power on the power resources required for the wakeup device
|
||||
* 1. Power on the power resources required for the wakeup device
|
||||
* 2. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
|
||||
* State Wake) for the device, if present
|
||||
*/
|
||||
|
|
|
@ -354,7 +354,7 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
|
|||
(u32) px->control, (u32) px->status));
|
||||
|
||||
/*
|
||||
* Check that ACPI's u64 MHz will be valid as u32 KHz in cpufreq
|
||||
* Check that ACPI's u64 MHz will be valid as u32 KHz in cpufreq
|
||||
*/
|
||||
if (!px->core_frequency ||
|
||||
((u32)(px->core_frequency * 1000) !=
|
||||
|
@ -627,7 +627,7 @@ int acpi_processor_preregister_performance(
|
|||
goto err_ret;
|
||||
|
||||
/*
|
||||
* Now that we have _PSD data from all CPUs, lets setup P-state
|
||||
* Now that we have _PSD data from all CPUs, lets setup P-state
|
||||
* domain info.
|
||||
*/
|
||||
for_each_possible_cpu(i) {
|
||||
|
@ -693,7 +693,7 @@ int acpi_processor_preregister_performance(
|
|||
if (match_pdomain->domain != pdomain->domain)
|
||||
continue;
|
||||
|
||||
match_pr->performance->shared_type =
|
||||
match_pr->performance->shared_type =
|
||||
pr->performance->shared_type;
|
||||
cpumask_copy(match_pr->performance->shared_cpu_map,
|
||||
pr->performance->shared_cpu_map);
|
||||
|
|
|
@ -366,7 +366,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
|
|||
state_readers[i].mode,
|
||||
ACPI_SBS_BATTERY,
|
||||
state_readers[i].command,
|
||||
(u8 *)battery +
|
||||
(u8 *)battery +
|
||||
state_readers[i].offset);
|
||||
if (result)
|
||||
goto end;
|
||||
|
|
|
@ -176,7 +176,7 @@ int acpi_smbus_write(struct acpi_smb_hc *hc, u8 protocol, u8 address,
|
|||
EXPORT_SYMBOL_GPL(acpi_smbus_write);
|
||||
|
||||
int acpi_smbus_register_callback(struct acpi_smb_hc *hc,
|
||||
smbus_alarm_callback callback, void *context)
|
||||
smbus_alarm_callback callback, void *context)
|
||||
{
|
||||
mutex_lock(&hc->lock);
|
||||
hc->callback = callback;
|
||||
|
|
|
@ -24,9 +24,9 @@ enum acpi_sbs_device_addr {
|
|||
typedef void (*smbus_alarm_callback)(void *context);
|
||||
|
||||
extern int acpi_smbus_read(struct acpi_smb_hc *hc, u8 protocol, u8 address,
|
||||
u8 command, u8 * data);
|
||||
u8 command, u8 *data);
|
||||
extern int acpi_smbus_write(struct acpi_smb_hc *hc, u8 protocol, u8 slave_address,
|
||||
u8 command, u8 * data, u8 length);
|
||||
u8 command, u8 *data, u8 length);
|
||||
extern int acpi_smbus_register_callback(struct acpi_smb_hc *hc,
|
||||
smbus_alarm_callback callback, void *context);
|
||||
smbus_alarm_callback callback, void *context);
|
||||
extern int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc);
|
||||
|
|
|
@ -1453,7 +1453,7 @@ int acpi_dma_get_range(struct device *dev, u64 *dma_addr, u64 *offset,
|
|||
}
|
||||
|
||||
/**
|
||||
* acpi_dma_configure - Set-up DMA configuration for the device.
|
||||
* acpi_dma_configure_id - Set-up DMA configuration for the device.
|
||||
* @dev: The pointer to the device
|
||||
* @attr: device dma attributes
|
||||
* @input_id: input device id const value pointer
|
||||
|
|
|
@ -178,14 +178,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
|
|||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = video_detect_force_video,
|
||||
.ident = "ThinkPad X201T",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201T"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = video_detect_force_video,
|
||||
.ident = "ThinkPad X201T",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201T"),
|
||||
},
|
||||
},
|
||||
|
||||
/* The native backlight controls do not work on some older machines */
|
||||
{
|
||||
|
|
|
@ -44,7 +44,7 @@ void acpi_enable_wakeup_devices(u8 sleep_state)
|
|||
if (!dev->wakeup.flags.valid
|
||||
|| sleep_state > (u32) dev->wakeup.sleep_state
|
||||
|| !(device_may_wakeup(&dev->dev)
|
||||
|| dev->wakeup.prepare_count))
|
||||
|| dev->wakeup.prepare_count))
|
||||
continue;
|
||||
|
||||
if (device_may_wakeup(&dev->dev))
|
||||
|
@ -69,7 +69,7 @@ void acpi_disable_wakeup_devices(u8 sleep_state)
|
|||
if (!dev->wakeup.flags.valid
|
||||
|| sleep_state > (u32) dev->wakeup.sleep_state
|
||||
|| !(device_may_wakeup(&dev->dev)
|
||||
|| dev->wakeup.prepare_count))
|
||||
|| dev->wakeup.prepare_count))
|
||||
continue;
|
||||
|
||||
acpi_set_gpe_wake_mask(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
|
||||
|
|
|
@ -47,7 +47,7 @@ struct nullb_device {
|
|||
unsigned int nr_zones_closed;
|
||||
struct blk_zone *zones;
|
||||
sector_t zone_size_sects;
|
||||
spinlock_t zone_dev_lock;
|
||||
spinlock_t zone_lock;
|
||||
unsigned long *zone_locks;
|
||||
|
||||
unsigned long size; /* device size in MB */
|
||||
|
|
|
@ -46,11 +46,20 @@ int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q)
|
|||
if (!dev->zones)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&dev->zone_dev_lock);
|
||||
dev->zone_locks = bitmap_zalloc(dev->nr_zones, GFP_KERNEL);
|
||||
if (!dev->zone_locks) {
|
||||
kvfree(dev->zones);
|
||||
return -ENOMEM;
|
||||
/*
|
||||
* With memory backing, the zone_lock spinlock needs to be temporarily
|
||||
* released to avoid scheduling in atomic context. To guarantee zone
|
||||
* information protection, use a bitmap to lock zones with
|
||||
* wait_on_bit_lock_io(). Sleeping on the lock is OK as memory backing
|
||||
* implies that the queue is marked with BLK_MQ_F_BLOCKING.
|
||||
*/
|
||||
spin_lock_init(&dev->zone_lock);
|
||||
if (dev->memory_backed) {
|
||||
dev->zone_locks = bitmap_zalloc(dev->nr_zones, GFP_KERNEL);
|
||||
if (!dev->zone_locks) {
|
||||
kvfree(dev->zones);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->zone_nr_conv >= dev->nr_zones) {
|
||||
|
@ -137,12 +146,17 @@ void null_free_zoned_dev(struct nullb_device *dev)
|
|||
|
||||
static inline void null_lock_zone(struct nullb_device *dev, unsigned int zno)
|
||||
{
|
||||
wait_on_bit_lock_io(dev->zone_locks, zno, TASK_UNINTERRUPTIBLE);
|
||||
if (dev->memory_backed)
|
||||
wait_on_bit_lock_io(dev->zone_locks, zno, TASK_UNINTERRUPTIBLE);
|
||||
spin_lock_irq(&dev->zone_lock);
|
||||
}
|
||||
|
||||
static inline void null_unlock_zone(struct nullb_device *dev, unsigned int zno)
|
||||
{
|
||||
clear_and_wake_up_bit(zno, dev->zone_locks);
|
||||
spin_unlock_irq(&dev->zone_lock);
|
||||
|
||||
if (dev->memory_backed)
|
||||
clear_and_wake_up_bit(zno, dev->zone_locks);
|
||||
}
|
||||
|
||||
int null_report_zones(struct gendisk *disk, sector_t sector,
|
||||
|
@ -322,7 +336,6 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
|
|||
return null_process_cmd(cmd, REQ_OP_WRITE, sector, nr_sectors);
|
||||
|
||||
null_lock_zone(dev, zno);
|
||||
spin_lock(&dev->zone_dev_lock);
|
||||
|
||||
switch (zone->cond) {
|
||||
case BLK_ZONE_COND_FULL:
|
||||
|
@ -375,9 +388,17 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
|
|||
if (zone->cond != BLK_ZONE_COND_EXP_OPEN)
|
||||
zone->cond = BLK_ZONE_COND_IMP_OPEN;
|
||||
|
||||
spin_unlock(&dev->zone_dev_lock);
|
||||
/*
|
||||
* Memory backing allocation may sleep: release the zone_lock spinlock
|
||||
* to avoid scheduling in atomic context. Zone operation atomicity is
|
||||
* still guaranteed through the zone_locks bitmap.
|
||||
*/
|
||||
if (dev->memory_backed)
|
||||
spin_unlock_irq(&dev->zone_lock);
|
||||
ret = null_process_cmd(cmd, REQ_OP_WRITE, sector, nr_sectors);
|
||||
spin_lock(&dev->zone_dev_lock);
|
||||
if (dev->memory_backed)
|
||||
spin_lock_irq(&dev->zone_lock);
|
||||
|
||||
if (ret != BLK_STS_OK)
|
||||
goto unlock;
|
||||
|
||||
|
@ -392,7 +413,6 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
|
|||
ret = BLK_STS_OK;
|
||||
|
||||
unlock:
|
||||
spin_unlock(&dev->zone_dev_lock);
|
||||
null_unlock_zone(dev, zno);
|
||||
|
||||
return ret;
|
||||
|
@ -516,9 +536,7 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_opf op,
|
|||
null_lock_zone(dev, i);
|
||||
zone = &dev->zones[i];
|
||||
if (zone->cond != BLK_ZONE_COND_EMPTY) {
|
||||
spin_lock(&dev->zone_dev_lock);
|
||||
null_reset_zone(dev, zone);
|
||||
spin_unlock(&dev->zone_dev_lock);
|
||||
trace_nullb_zone_op(cmd, i, zone->cond);
|
||||
}
|
||||
null_unlock_zone(dev, i);
|
||||
|
@ -530,7 +548,6 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_opf op,
|
|||
zone = &dev->zones[zone_no];
|
||||
|
||||
null_lock_zone(dev, zone_no);
|
||||
spin_lock(&dev->zone_dev_lock);
|
||||
|
||||
switch (op) {
|
||||
case REQ_OP_ZONE_RESET:
|
||||
|
@ -550,8 +567,6 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_opf op,
|
|||
break;
|
||||
}
|
||||
|
||||
spin_unlock(&dev->zone_dev_lock);
|
||||
|
||||
if (ret == BLK_STS_OK)
|
||||
trace_nullb_zone_op(cmd, zone_no, zone->cond);
|
||||
|
||||
|
|
|
@ -2254,7 +2254,7 @@ static int cpufreq_init_governor(struct cpufreq_policy *policy)
|
|||
return -EINVAL;
|
||||
|
||||
/* Platform doesn't want dynamic frequency switching ? */
|
||||
if (policy->governor->dynamic_switching &&
|
||||
if (policy->governor->flags & CPUFREQ_GOV_DYNAMIC_SWITCHING &&
|
||||
cpufreq_driver->flags & CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING) {
|
||||
struct cpufreq_governor *gov = cpufreq_fallback_governor();
|
||||
|
||||
|
@ -2280,6 +2280,8 @@ static int cpufreq_init_governor(struct cpufreq_policy *policy)
|
|||
}
|
||||
}
|
||||
|
||||
policy->strict_target = !!(policy->governor->flags & CPUFREQ_GOV_STRICT_TARGET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -156,7 +156,7 @@ void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy);
|
|||
#define CPUFREQ_DBS_GOVERNOR_INITIALIZER(_name_) \
|
||||
{ \
|
||||
.name = _name_, \
|
||||
.dynamic_switching = true, \
|
||||
.flags = CPUFREQ_GOV_DYNAMIC_SWITCHING, \
|
||||
.owner = THIS_MODULE, \
|
||||
.init = cpufreq_dbs_governor_init, \
|
||||
.exit = cpufreq_dbs_governor_exit, \
|
||||
|
|
|
@ -20,6 +20,7 @@ static void cpufreq_gov_performance_limits(struct cpufreq_policy *policy)
|
|||
static struct cpufreq_governor cpufreq_gov_performance = {
|
||||
.name = "performance",
|
||||
.owner = THIS_MODULE,
|
||||
.flags = CPUFREQ_GOV_STRICT_TARGET,
|
||||
.limits = cpufreq_gov_performance_limits,
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ static struct cpufreq_governor cpufreq_gov_powersave = {
|
|||
.name = "powersave",
|
||||
.limits = cpufreq_gov_powersave_limits,
|
||||
.owner = THIS_MODULE,
|
||||
.flags = CPUFREQ_GOV_STRICT_TARGET,
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
|
||||
|
|
|
@ -2527,7 +2527,7 @@ static void intel_cpufreq_trace(struct cpudata *cpu, unsigned int trace_type, in
|
|||
}
|
||||
|
||||
static void intel_cpufreq_adjust_hwp(struct cpudata *cpu, u32 target_pstate,
|
||||
bool fast_switch)
|
||||
bool strict, bool fast_switch)
|
||||
{
|
||||
u64 prev = READ_ONCE(cpu->hwp_req_cached), value = prev;
|
||||
|
||||
|
@ -2539,7 +2539,7 @@ static void intel_cpufreq_adjust_hwp(struct cpudata *cpu, u32 target_pstate,
|
|||
* field in it, so opportunistically update the max too if needed.
|
||||
*/
|
||||
value &= ~HWP_MAX_PERF(~0L);
|
||||
value |= HWP_MAX_PERF(cpu->max_perf_ratio);
|
||||
value |= HWP_MAX_PERF(strict ? target_pstate : cpu->max_perf_ratio);
|
||||
|
||||
if (value == prev)
|
||||
return;
|
||||
|
@ -2562,14 +2562,16 @@ static void intel_cpufreq_adjust_perf_ctl(struct cpudata *cpu,
|
|||
pstate_funcs.get_val(cpu, target_pstate));
|
||||
}
|
||||
|
||||
static int intel_cpufreq_update_pstate(struct cpudata *cpu, int target_pstate,
|
||||
bool fast_switch)
|
||||
static int intel_cpufreq_update_pstate(struct cpufreq_policy *policy,
|
||||
int target_pstate, bool fast_switch)
|
||||
{
|
||||
struct cpudata *cpu = all_cpu_data[policy->cpu];
|
||||
int old_pstate = cpu->pstate.current_pstate;
|
||||
|
||||
target_pstate = intel_pstate_prepare_request(cpu, target_pstate);
|
||||
if (hwp_active) {
|
||||
intel_cpufreq_adjust_hwp(cpu, target_pstate, fast_switch);
|
||||
intel_cpufreq_adjust_hwp(cpu, target_pstate,
|
||||
policy->strict_target, fast_switch);
|
||||
cpu->pstate.current_pstate = target_pstate;
|
||||
} else if (target_pstate != old_pstate) {
|
||||
intel_cpufreq_adjust_perf_ctl(cpu, target_pstate, fast_switch);
|
||||
|
@ -2609,7 +2611,7 @@ static int intel_cpufreq_target(struct cpufreq_policy *policy,
|
|||
break;
|
||||
}
|
||||
|
||||
target_pstate = intel_cpufreq_update_pstate(cpu, target_pstate, false);
|
||||
target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, false);
|
||||
|
||||
freqs.new = target_pstate * cpu->pstate.scaling;
|
||||
|
||||
|
@ -2628,7 +2630,7 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy,
|
|||
|
||||
target_pstate = DIV_ROUND_UP(target_freq, cpu->pstate.scaling);
|
||||
|
||||
target_pstate = intel_cpufreq_update_pstate(cpu, target_pstate, true);
|
||||
target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, true);
|
||||
|
||||
return target_pstate * cpu->pstate.scaling;
|
||||
}
|
||||
|
|
|
@ -733,7 +733,7 @@ config I2C_LPC2K
|
|||
|
||||
config I2C_MLXBF
|
||||
tristate "Mellanox BlueField I2C controller"
|
||||
depends on ARM64
|
||||
depends on MELLANOX_PLATFORM && ARM64
|
||||
help
|
||||
Enabling this option will add I2C SMBus support for Mellanox BlueField
|
||||
system.
|
||||
|
|
|
@ -159,7 +159,6 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
|
|||
u32 raw_stat, stat, enabled, tmp;
|
||||
u8 val = 0, slave_activity;
|
||||
|
||||
regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
|
||||
regmap_read(dev->map, DW_IC_ENABLE, &enabled);
|
||||
regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &raw_stat);
|
||||
regmap_read(dev->map, DW_IC_STATUS, &tmp);
|
||||
|
@ -168,32 +167,30 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
|
|||
if (!enabled || !(raw_stat & ~DW_IC_INTR_ACTIVITY) || !dev->slave)
|
||||
return 0;
|
||||
|
||||
stat = i2c_dw_read_clear_intrbits_slave(dev);
|
||||
dev_dbg(dev->dev,
|
||||
"%#x STATUS SLAVE_ACTIVITY=%#x : RAW_INTR_STAT=%#x : INTR_STAT=%#x\n",
|
||||
enabled, slave_activity, raw_stat, stat);
|
||||
|
||||
if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET))
|
||||
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
|
||||
if (stat & DW_IC_INTR_RX_FULL) {
|
||||
if (dev->status != STATUS_WRITE_IN_PROGRESS) {
|
||||
dev->status = STATUS_WRITE_IN_PROGRESS;
|
||||
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED,
|
||||
&val);
|
||||
}
|
||||
|
||||
regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
|
||||
val = tmp;
|
||||
if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
|
||||
&val))
|
||||
dev_vdbg(dev->dev, "Byte %X acked!", val);
|
||||
}
|
||||
|
||||
if (stat & DW_IC_INTR_RD_REQ) {
|
||||
if (slave_activity) {
|
||||
if (stat & DW_IC_INTR_RX_FULL) {
|
||||
regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
|
||||
val = tmp;
|
||||
regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
|
||||
|
||||
if (!i2c_slave_event(dev->slave,
|
||||
I2C_SLAVE_WRITE_RECEIVED,
|
||||
&val)) {
|
||||
dev_vdbg(dev->dev, "Byte %X acked!",
|
||||
val);
|
||||
}
|
||||
regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
|
||||
stat = i2c_dw_read_clear_intrbits_slave(dev);
|
||||
} else {
|
||||
regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
|
||||
regmap_read(dev->map, DW_IC_CLR_RX_UNDER, &tmp);
|
||||
stat = i2c_dw_read_clear_intrbits_slave(dev);
|
||||
}
|
||||
dev->status = STATUS_READ_IN_PROGRESS;
|
||||
if (!i2c_slave_event(dev->slave,
|
||||
I2C_SLAVE_READ_REQUESTED,
|
||||
&val))
|
||||
|
@ -205,21 +202,11 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
|
|||
if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
|
||||
&val))
|
||||
regmap_read(dev->map, DW_IC_CLR_RX_DONE, &tmp);
|
||||
|
||||
i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
|
||||
stat = i2c_dw_read_clear_intrbits_slave(dev);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (stat & DW_IC_INTR_RX_FULL) {
|
||||
regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
|
||||
val = tmp;
|
||||
if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
|
||||
&val))
|
||||
dev_vdbg(dev->dev, "Byte %X acked!", val);
|
||||
} else {
|
||||
if (stat & DW_IC_INTR_STOP_DET) {
|
||||
dev->status = STATUS_IDLE;
|
||||
i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
|
||||
stat = i2c_dw_read_clear_intrbits_slave(dev);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -230,7 +217,6 @@ static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
|
|||
struct dw_i2c_dev *dev = dev_id;
|
||||
int ret;
|
||||
|
||||
i2c_dw_read_clear_intrbits_slave(dev);
|
||||
ret = i2c_dw_irq_handler_slave(dev);
|
||||
if (ret > 0)
|
||||
complete(&dev->cmd_complete);
|
||||
|
|
|
@ -62,10 +62,8 @@
|
|||
* Master. Default value is set to 400MHz.
|
||||
*/
|
||||
#define MLXBF_I2C_TYU_PLL_OUT_FREQ (400 * 1000 * 1000)
|
||||
/* Reference clock for Bluefield 1 - 156 MHz. */
|
||||
#define MLXBF_I2C_TYU_PLL_IN_FREQ (156 * 1000 * 1000)
|
||||
/* Reference clock for BlueField 2 - 200 MHz. */
|
||||
#define MLXBF_I2C_YU_PLL_IN_FREQ (200 * 1000 * 1000)
|
||||
/* Reference clock for Bluefield - 156 MHz. */
|
||||
#define MLXBF_I2C_PLL_IN_FREQ (156 * 1000 * 1000)
|
||||
|
||||
/* Constant used to determine the PLL frequency. */
|
||||
#define MLNXBF_I2C_COREPLL_CONST 16384
|
||||
|
@ -489,44 +487,6 @@ static struct mutex mlxbf_i2c_bus_lock;
|
|||
|
||||
#define MLXBF_I2C_FREQUENCY_1GHZ 1000000000
|
||||
|
||||
static void mlxbf_i2c_write(void __iomem *io, int reg, u32 val)
|
||||
{
|
||||
writel(val, io + reg);
|
||||
}
|
||||
|
||||
static u32 mlxbf_i2c_read(void __iomem *io, int reg)
|
||||
{
|
||||
return readl(io + reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to read data from Master GW Data Descriptor.
|
||||
* Data bytes in the Master GW Data Descriptor are shifted left so the
|
||||
* data starts at the MSB of the descriptor registers as set by the
|
||||
* underlying hardware. TYU_READ_DATA enables byte swapping while
|
||||
* reading data bytes, and MUST be called by the SMBus read routines
|
||||
* to copy data from the 32 * 32-bit HW Data registers a.k.a Master GW
|
||||
* Data Descriptor.
|
||||
*/
|
||||
static u32 mlxbf_i2c_read_data(void __iomem *io, int reg)
|
||||
{
|
||||
return (u32)be32_to_cpu(mlxbf_i2c_read(io, reg));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to write data to the Master GW Data Descriptor.
|
||||
* Data copied to the Master GW Data Descriptor MUST be shifted left so
|
||||
* the data starts at the MSB of the descriptor registers as required by
|
||||
* the underlying hardware. TYU_WRITE_DATA enables byte swapping when
|
||||
* writing data bytes, and MUST be called by the SMBus write routines to
|
||||
* copy data to the 32 * 32-bit HW Data registers a.k.a Master GW Data
|
||||
* Descriptor.
|
||||
*/
|
||||
static void mlxbf_i2c_write_data(void __iomem *io, int reg, u32 val)
|
||||
{
|
||||
mlxbf_i2c_write(io, reg, (u32)cpu_to_be32(val));
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to poll a set of bits at a specific address; it checks whether
|
||||
* the bits are equal to zero when eq_zero is set to 'true', and not equal
|
||||
|
@ -541,7 +501,7 @@ static u32 mlxbf_smbus_poll(void __iomem *io, u32 addr, u32 mask,
|
|||
timeout = (timeout / MLXBF_I2C_POLL_FREQ_IN_USEC) + 1;
|
||||
|
||||
do {
|
||||
bits = mlxbf_i2c_read(io, addr) & mask;
|
||||
bits = readl(io + addr) & mask;
|
||||
if (eq_zero ? bits == 0 : bits != 0)
|
||||
return eq_zero ? 1 : bits;
|
||||
udelay(MLXBF_I2C_POLL_FREQ_IN_USEC);
|
||||
|
@ -609,16 +569,16 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv)
|
|||
MLXBF_I2C_SMBUS_TIMEOUT);
|
||||
|
||||
/* Read cause status bits. */
|
||||
cause_status_bits = mlxbf_i2c_read(priv->mst_cause->io,
|
||||
MLXBF_I2C_CAUSE_ARBITER);
|
||||
cause_status_bits = readl(priv->mst_cause->io +
|
||||
MLXBF_I2C_CAUSE_ARBITER);
|
||||
cause_status_bits &= MLXBF_I2C_CAUSE_MASTER_ARBITER_BITS_MASK;
|
||||
|
||||
/*
|
||||
* Parse both Cause and Master GW bits, then return transaction status.
|
||||
*/
|
||||
|
||||
master_status_bits = mlxbf_i2c_read(priv->smbus->io,
|
||||
MLXBF_I2C_SMBUS_MASTER_STATUS);
|
||||
master_status_bits = readl(priv->smbus->io +
|
||||
MLXBF_I2C_SMBUS_MASTER_STATUS);
|
||||
master_status_bits &= MLXBF_I2C_SMBUS_MASTER_STATUS_MASK;
|
||||
|
||||
if (mlxbf_i2c_smbus_transaction_success(master_status_bits,
|
||||
|
@ -649,10 +609,17 @@ static void mlxbf_i2c_smbus_write_data(struct mlxbf_i2c_priv *priv,
|
|||
|
||||
aligned_length = round_up(length, 4);
|
||||
|
||||
/* Copy data bytes from 4-byte aligned source buffer. */
|
||||
/*
|
||||
* Copy data bytes from 4-byte aligned source buffer.
|
||||
* Data copied to the Master GW Data Descriptor MUST be shifted
|
||||
* left so the data starts at the MSB of the descriptor registers
|
||||
* as required by the underlying hardware. Enable byte swapping
|
||||
* when writing data bytes to the 32 * 32-bit HW Data registers
|
||||
* a.k.a Master GW Data Descriptor.
|
||||
*/
|
||||
for (offset = 0; offset < aligned_length; offset += sizeof(u32)) {
|
||||
data32 = *((u32 *)(data + offset));
|
||||
mlxbf_i2c_write_data(priv->smbus->io, addr + offset, data32);
|
||||
iowrite32be(data32, priv->smbus->io + addr + offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -664,15 +631,23 @@ static void mlxbf_i2c_smbus_read_data(struct mlxbf_i2c_priv *priv,
|
|||
|
||||
mask = sizeof(u32) - 1;
|
||||
|
||||
/*
|
||||
* Data bytes in the Master GW Data Descriptor are shifted left
|
||||
* so the data starts at the MSB of the descriptor registers as
|
||||
* set by the underlying hardware. Enable byte swapping while
|
||||
* reading data bytes from the 32 * 32-bit HW Data registers
|
||||
* a.k.a Master GW Data Descriptor.
|
||||
*/
|
||||
|
||||
for (offset = 0; offset < (length & ~mask); offset += sizeof(u32)) {
|
||||
data32 = mlxbf_i2c_read_data(priv->smbus->io, addr + offset);
|
||||
data32 = ioread32be(priv->smbus->io + addr + offset);
|
||||
*((u32 *)(data + offset)) = data32;
|
||||
}
|
||||
|
||||
if (!(length & mask))
|
||||
return;
|
||||
|
||||
data32 = mlxbf_i2c_read_data(priv->smbus->io, addr + offset);
|
||||
data32 = ioread32be(priv->smbus->io + addr + offset);
|
||||
|
||||
for (byte = 0; byte < (length & mask); byte++) {
|
||||
data[offset + byte] = data32 & GENMASK(7, 0);
|
||||
|
@ -698,16 +673,16 @@ static int mlxbf_i2c_smbus_enable(struct mlxbf_i2c_priv *priv, u8 slave,
|
|||
command |= rol32(pec_en, MLXBF_I2C_MASTER_SEND_PEC_SHIFT);
|
||||
|
||||
/* Clear status bits. */
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_STATUS, 0x0);
|
||||
writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_STATUS);
|
||||
/* Set the cause data. */
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_CAUSE_OR_CLEAR, ~0x0);
|
||||
writel(~0x0, priv->smbus->io + MLXBF_I2C_CAUSE_OR_CLEAR);
|
||||
/* Zero PEC byte. */
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_PEC, 0x0);
|
||||
writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_PEC);
|
||||
/* Zero byte count. */
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_RS_BYTES, 0x0);
|
||||
writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_RS_BYTES);
|
||||
|
||||
/* GW activation. */
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_GW, command);
|
||||
writel(command, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_GW);
|
||||
|
||||
/*
|
||||
* Poll master status and check status bits. An ACK is sent when
|
||||
|
@ -823,8 +798,8 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
|
|||
* needs to be 'manually' reset. This should be removed in
|
||||
* next tag integration.
|
||||
*/
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_FSM,
|
||||
MLXBF_I2C_SMBUS_MASTER_FSM_PS_STATE_MASK);
|
||||
writel(MLXBF_I2C_SMBUS_MASTER_FSM_PS_STATE_MASK,
|
||||
priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_FSM);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1113,8 +1088,8 @@ static void mlxbf_i2c_set_timings(struct mlxbf_i2c_priv *priv,
|
|||
timer |= mlxbf_i2c_set_timer(priv, timings->scl_low,
|
||||
false, MLXBF_I2C_MASK_16,
|
||||
MLXBF_I2C_SHIFT_16);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH,
|
||||
timer);
|
||||
writel(timer, priv->smbus->io +
|
||||
MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH);
|
||||
|
||||
timer = mlxbf_i2c_set_timer(priv, timings->sda_rise, false,
|
||||
MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_0);
|
||||
|
@ -1124,37 +1099,34 @@ static void mlxbf_i2c_set_timings(struct mlxbf_i2c_priv *priv,
|
|||
MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_16);
|
||||
timer |= mlxbf_i2c_set_timer(priv, timings->scl_fall, false,
|
||||
MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_24);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE,
|
||||
timer);
|
||||
writel(timer, priv->smbus->io +
|
||||
MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE);
|
||||
|
||||
timer = mlxbf_i2c_set_timer(priv, timings->hold_start, true,
|
||||
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0);
|
||||
timer |= mlxbf_i2c_set_timer(priv, timings->hold_data, true,
|
||||
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_TIMER_THOLD, timer);
|
||||
writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_TIMER_THOLD);
|
||||
|
||||
timer = mlxbf_i2c_set_timer(priv, timings->setup_start, true,
|
||||
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0);
|
||||
timer |= mlxbf_i2c_set_timer(priv, timings->setup_stop, true,
|
||||
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16);
|
||||
mlxbf_i2c_write(priv->smbus->io,
|
||||
MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP, timer);
|
||||
writel(timer, priv->smbus->io +
|
||||
MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP);
|
||||
|
||||
timer = mlxbf_i2c_set_timer(priv, timings->setup_data, true,
|
||||
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA,
|
||||
timer);
|
||||
writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA);
|
||||
|
||||
timer = mlxbf_i2c_set_timer(priv, timings->buf, false,
|
||||
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0);
|
||||
timer |= mlxbf_i2c_set_timer(priv, timings->thigh_max, false,
|
||||
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_THIGH_MAX_TBUF,
|
||||
timer);
|
||||
writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_THIGH_MAX_TBUF);
|
||||
|
||||
timer = timings->timeout;
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT,
|
||||
timer);
|
||||
writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT);
|
||||
}
|
||||
|
||||
enum mlxbf_i2c_timings_config {
|
||||
|
@ -1426,19 +1398,15 @@ static int mlxbf_i2c_init_master(struct platform_device *pdev,
|
|||
* platform firmware; disabling the bus might compromise the system
|
||||
* functionality.
|
||||
*/
|
||||
config_reg = mlxbf_i2c_read(gpio_res->io,
|
||||
MLXBF_I2C_GPIO_0_FUNC_EN_0);
|
||||
config_reg = readl(gpio_res->io + MLXBF_I2C_GPIO_0_FUNC_EN_0);
|
||||
config_reg = MLXBF_I2C_GPIO_SMBUS_GW_ASSERT_PINS(priv->bus,
|
||||
config_reg);
|
||||
mlxbf_i2c_write(gpio_res->io, MLXBF_I2C_GPIO_0_FUNC_EN_0,
|
||||
config_reg);
|
||||
writel(config_reg, gpio_res->io + MLXBF_I2C_GPIO_0_FUNC_EN_0);
|
||||
|
||||
config_reg = mlxbf_i2c_read(gpio_res->io,
|
||||
MLXBF_I2C_GPIO_0_FORCE_OE_EN);
|
||||
config_reg = readl(gpio_res->io + MLXBF_I2C_GPIO_0_FORCE_OE_EN);
|
||||
config_reg = MLXBF_I2C_GPIO_SMBUS_GW_RESET_PINS(priv->bus,
|
||||
config_reg);
|
||||
mlxbf_i2c_write(gpio_res->io, MLXBF_I2C_GPIO_0_FORCE_OE_EN,
|
||||
config_reg);
|
||||
writel(config_reg, gpio_res->io + MLXBF_I2C_GPIO_0_FORCE_OE_EN);
|
||||
|
||||
mutex_unlock(gpio_res->lock);
|
||||
|
||||
|
@ -1452,10 +1420,9 @@ static u64 mlxbf_calculate_freq_from_tyu(struct mlxbf_i2c_resource *corepll_res)
|
|||
u32 corepll_val;
|
||||
u16 core_f;
|
||||
|
||||
pad_frequency = MLXBF_I2C_TYU_PLL_IN_FREQ;
|
||||
pad_frequency = MLXBF_I2C_PLL_IN_FREQ;
|
||||
|
||||
corepll_val = mlxbf_i2c_read(corepll_res->io,
|
||||
MLXBF_I2C_CORE_PLL_REG1);
|
||||
corepll_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG1);
|
||||
|
||||
/* Get Core PLL configuration bits. */
|
||||
core_f = rol32(corepll_val, MLXBF_I2C_COREPLL_CORE_F_TYU_SHIFT) &
|
||||
|
@ -1488,12 +1455,10 @@ static u64 mlxbf_calculate_freq_from_yu(struct mlxbf_i2c_resource *corepll_res)
|
|||
u8 core_od, core_r;
|
||||
u32 core_f;
|
||||
|
||||
pad_frequency = MLXBF_I2C_YU_PLL_IN_FREQ;
|
||||
pad_frequency = MLXBF_I2C_PLL_IN_FREQ;
|
||||
|
||||
corepll_reg1_val = mlxbf_i2c_read(corepll_res->io,
|
||||
MLXBF_I2C_CORE_PLL_REG1);
|
||||
corepll_reg2_val = mlxbf_i2c_read(corepll_res->io,
|
||||
MLXBF_I2C_CORE_PLL_REG2);
|
||||
corepll_reg1_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG1);
|
||||
corepll_reg2_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG2);
|
||||
|
||||
/* Get Core PLL configuration bits */
|
||||
core_f = rol32(corepll_reg1_val, MLXBF_I2C_COREPLL_CORE_F_YU_SHIFT) &
|
||||
|
@ -1585,7 +1550,7 @@ static int mlxbf_slave_enable(struct mlxbf_i2c_priv *priv, u8 addr)
|
|||
* (7-bit address, 1 status bit (1 if enabled, 0 if not)).
|
||||
*/
|
||||
for (reg = 0; reg < reg_cnt; reg++) {
|
||||
slave_reg = mlxbf_i2c_read(priv->smbus->io,
|
||||
slave_reg = readl(priv->smbus->io +
|
||||
MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4);
|
||||
/*
|
||||
* Each register holds 4 slave addresses. So, we have to keep
|
||||
|
@ -1643,8 +1608,8 @@ static int mlxbf_slave_enable(struct mlxbf_i2c_priv *priv, u8 addr)
|
|||
|
||||
/* Enable the slave address and update the register. */
|
||||
slave_reg |= (1 << MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT) << (byte * 8);
|
||||
mlxbf_i2c_write(priv->smbus->io,
|
||||
MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4, slave_reg);
|
||||
writel(slave_reg, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG +
|
||||
reg * 0x4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1668,7 +1633,7 @@ static int mlxbf_slave_disable(struct mlxbf_i2c_priv *priv)
|
|||
* (7-bit address, 1 status bit (1 if enabled, 0 if not)).
|
||||
*/
|
||||
for (reg = 0; reg < reg_cnt; reg++) {
|
||||
slave_reg = mlxbf_i2c_read(priv->smbus->io,
|
||||
slave_reg = readl(priv->smbus->io +
|
||||
MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4);
|
||||
|
||||
/* Check whether the address slots are empty. */
|
||||
|
@ -1708,8 +1673,8 @@ static int mlxbf_slave_disable(struct mlxbf_i2c_priv *priv)
|
|||
|
||||
/* Cleanup the slave address slot. */
|
||||
slave_reg &= ~(GENMASK(7, 0) << (slave_byte * 8));
|
||||
mlxbf_i2c_write(priv->smbus->io,
|
||||
MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4, slave_reg);
|
||||
writel(slave_reg, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG +
|
||||
reg * 0x4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1801,7 +1766,7 @@ static int mlxbf_i2c_init_slave(struct platform_device *pdev,
|
|||
int ret;
|
||||
|
||||
/* Reset FSM. */
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SLAVE_FSM, 0);
|
||||
writel(0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_FSM);
|
||||
|
||||
/*
|
||||
* Enable slave cause interrupt bits. Drive
|
||||
|
@ -1810,15 +1775,13 @@ static int mlxbf_i2c_init_slave(struct platform_device *pdev,
|
|||
* masters issue a Read and Write, respectively. But, clear all
|
||||
* interrupts first.
|
||||
*/
|
||||
mlxbf_i2c_write(priv->slv_cause->io,
|
||||
MLXBF_I2C_CAUSE_OR_CLEAR, ~0);
|
||||
writel(~0, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_CLEAR);
|
||||
int_reg = MLXBF_I2C_CAUSE_READ_WAIT_FW_RESPONSE;
|
||||
int_reg |= MLXBF_I2C_CAUSE_WRITE_SUCCESS;
|
||||
mlxbf_i2c_write(priv->slv_cause->io,
|
||||
MLXBF_I2C_CAUSE_OR_EVTEN0, int_reg);
|
||||
writel(int_reg, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_EVTEN0);
|
||||
|
||||
/* Finally, set the 'ready' bit to start handling transactions. */
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SLAVE_READY, 0x1);
|
||||
writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY);
|
||||
|
||||
/* Initialize the cause coalesce resource. */
|
||||
ret = mlxbf_i2c_init_coalesce(pdev, priv);
|
||||
|
@ -1844,23 +1807,21 @@ static bool mlxbf_i2c_has_coalesce(struct mlxbf_i2c_priv *priv, bool *read,
|
|||
MLXBF_I2C_CAUSE_YU_SLAVE_BIT :
|
||||
priv->bus + MLXBF_I2C_CAUSE_TYU_SLAVE_BIT;
|
||||
|
||||
coalesce0_reg = mlxbf_i2c_read(priv->coalesce->io,
|
||||
MLXBF_I2C_CAUSE_COALESCE_0);
|
||||
coalesce0_reg = readl(priv->coalesce->io + MLXBF_I2C_CAUSE_COALESCE_0);
|
||||
is_set = coalesce0_reg & (1 << slave_shift);
|
||||
|
||||
if (!is_set)
|
||||
return false;
|
||||
|
||||
/* Check the source of the interrupt, i.e. whether a Read or Write. */
|
||||
cause_reg = mlxbf_i2c_read(priv->slv_cause->io,
|
||||
MLXBF_I2C_CAUSE_ARBITER);
|
||||
cause_reg = readl(priv->slv_cause->io + MLXBF_I2C_CAUSE_ARBITER);
|
||||
if (cause_reg & MLXBF_I2C_CAUSE_READ_WAIT_FW_RESPONSE)
|
||||
*read = true;
|
||||
else if (cause_reg & MLXBF_I2C_CAUSE_WRITE_SUCCESS)
|
||||
*write = true;
|
||||
|
||||
/* Clear cause bits. */
|
||||
mlxbf_i2c_write(priv->slv_cause->io, MLXBF_I2C_CAUSE_OR_CLEAR, ~0x0);
|
||||
writel(~0x0, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_CLEAR);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1900,8 +1861,8 @@ static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
|
|||
* address, if supplied.
|
||||
*/
|
||||
if (recv_bytes > 0) {
|
||||
data32 = mlxbf_i2c_read_data(priv->smbus->io,
|
||||
MLXBF_I2C_SLAVE_DATA_DESC_ADDR);
|
||||
data32 = ioread32be(priv->smbus->io +
|
||||
MLXBF_I2C_SLAVE_DATA_DESC_ADDR);
|
||||
|
||||
/* Parse the received bytes. */
|
||||
switch (recv_bytes) {
|
||||
|
@ -1966,7 +1927,7 @@ static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
|
|||
control32 |= rol32(write_size, MLXBF_I2C_SLAVE_WRITE_BYTES_SHIFT);
|
||||
control32 |= rol32(pec_en, MLXBF_I2C_SLAVE_SEND_PEC_SHIFT);
|
||||
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SLAVE_GW, control32);
|
||||
writel(control32, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_GW);
|
||||
|
||||
/*
|
||||
* Wait until the transfer is completed; the driver will wait
|
||||
|
@ -1975,10 +1936,9 @@ static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
|
|||
mlxbf_smbus_slave_wait_for_idle(priv, MLXBF_I2C_SMBUS_TIMEOUT);
|
||||
|
||||
/* Release the Slave GW. */
|
||||
mlxbf_i2c_write(priv->smbus->io,
|
||||
MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES, 0x0);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SLAVE_PEC, 0x0);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SLAVE_READY, 0x1);
|
||||
writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES);
|
||||
writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_PEC);
|
||||
writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2023,10 +1983,9 @@ static int mlxbf_smbus_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
|
|||
i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
|
||||
|
||||
/* Release the Slave GW. */
|
||||
mlxbf_i2c_write(priv->smbus->io,
|
||||
MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES, 0x0);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SLAVE_PEC, 0x0);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SLAVE_READY, 0x1);
|
||||
writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES);
|
||||
writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_PEC);
|
||||
writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -2061,8 +2020,8 @@ static irqreturn_t mlxbf_smbus_irq(int irq, void *ptr)
|
|||
* slave, if the higher 8 bits are sent then the slave expect N bytes
|
||||
* from the master.
|
||||
*/
|
||||
rw_bytes_reg = mlxbf_i2c_read(priv->smbus->io,
|
||||
MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES);
|
||||
rw_bytes_reg = readl(priv->smbus->io +
|
||||
MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES);
|
||||
recv_bytes = (rw_bytes_reg >> 8) & GENMASK(7, 0);
|
||||
|
||||
/*
|
||||
|
@ -2264,6 +2223,7 @@ static const struct of_device_id mlxbf_i2c_dt_ids[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(of, mlxbf_i2c_dt_ids);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id mlxbf_i2c_acpi_ids[] = {
|
||||
{ "MLNXBF03", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_1] },
|
||||
{ "MLNXBF23", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_2] },
|
||||
|
@ -2305,6 +2265,12 @@ static int mlxbf_i2c_acpi_probe(struct device *dev, struct mlxbf_i2c_priv *priv)
|
|||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static int mlxbf_i2c_acpi_probe(struct device *dev, struct mlxbf_i2c_priv *priv)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
static int mlxbf_i2c_of_probe(struct device *dev, struct mlxbf_i2c_priv *priv)
|
||||
{
|
||||
|
@ -2473,7 +2439,9 @@ static struct platform_driver mlxbf_i2c_driver = {
|
|||
.driver = {
|
||||
.name = "i2c-mlxbf",
|
||||
.of_match_table = mlxbf_i2c_dt_ids,
|
||||
#ifdef CONFIG_ACPI
|
||||
.acpi_match_table = ACPI_PTR(mlxbf_i2c_acpi_ids),
|
||||
#endif /* CONFIG_ACPI */
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -2502,5 +2470,5 @@ static void __exit mlxbf_i2c_exit(void)
|
|||
module_exit(mlxbf_i2c_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Mellanox BlueField I2C bus driver");
|
||||
MODULE_AUTHOR("Khalil Blaiech <kblaiech@mellanox.com>");
|
||||
MODULE_AUTHOR("Khalil Blaiech <kblaiech@nvidia.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -475,6 +475,10 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
|
|||
{
|
||||
u16 control_reg;
|
||||
|
||||
writel(I2C_DMA_HARD_RST, i2c->pdmabase + OFFSET_RST);
|
||||
udelay(50);
|
||||
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST);
|
||||
|
||||
mtk_i2c_writew(i2c, I2C_SOFT_RST, OFFSET_SOFTRESET);
|
||||
|
||||
/* Set ioconfig */
|
||||
|
@ -529,10 +533,6 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
|
|||
|
||||
mtk_i2c_writew(i2c, control_reg, OFFSET_CONTROL);
|
||||
mtk_i2c_writew(i2c, I2C_DELAY_LEN, OFFSET_DELAY_LEN);
|
||||
|
||||
writel(I2C_DMA_HARD_RST, i2c->pdmabase + OFFSET_RST);
|
||||
udelay(50);
|
||||
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST);
|
||||
}
|
||||
|
||||
static const struct i2c_spec_values *mtk_i2c_get_spec(unsigned int speed)
|
||||
|
|
|
@ -129,6 +129,7 @@ struct sh_mobile_i2c_data {
|
|||
int sr;
|
||||
bool send_stop;
|
||||
bool stop_after_dma;
|
||||
bool atomic_xfer;
|
||||
|
||||
struct resource *res;
|
||||
struct dma_chan *dma_tx;
|
||||
|
@ -330,13 +331,15 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, enum sh_mobile_i2c_op
|
|||
ret = iic_rd(pd, ICDR);
|
||||
break;
|
||||
case OP_RX_STOP: /* enable DTE interrupt, issue stop */
|
||||
iic_wr(pd, ICIC,
|
||||
ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
|
||||
if (!pd->atomic_xfer)
|
||||
iic_wr(pd, ICIC,
|
||||
ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
|
||||
iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
|
||||
break;
|
||||
case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
|
||||
iic_wr(pd, ICIC,
|
||||
ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
|
||||
if (!pd->atomic_xfer)
|
||||
iic_wr(pd, ICIC,
|
||||
ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
|
||||
ret = iic_rd(pd, ICDR);
|
||||
iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
|
||||
break;
|
||||
|
@ -429,7 +432,8 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
|
|||
|
||||
if (wakeup) {
|
||||
pd->sr |= SW_DONE;
|
||||
wake_up(&pd->wait);
|
||||
if (!pd->atomic_xfer)
|
||||
wake_up(&pd->wait);
|
||||
}
|
||||
|
||||
/* defeat write posting to avoid spurious WAIT interrupts */
|
||||
|
@ -581,6 +585,9 @@ static void start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
|
|||
pd->pos = -1;
|
||||
pd->sr = 0;
|
||||
|
||||
if (pd->atomic_xfer)
|
||||
return;
|
||||
|
||||
pd->dma_buf = i2c_get_dma_safe_msg_buf(pd->msg, 8);
|
||||
if (pd->dma_buf)
|
||||
sh_mobile_i2c_xfer_dma(pd);
|
||||
|
@ -637,15 +644,13 @@ static int poll_busy(struct sh_mobile_i2c_data *pd)
|
|||
return i ? 0 : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
|
||||
struct i2c_msg *msgs,
|
||||
int num)
|
||||
static int sh_mobile_xfer(struct sh_mobile_i2c_data *pd,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
|
||||
struct i2c_msg *msg;
|
||||
int err = 0;
|
||||
int i;
|
||||
long timeout;
|
||||
long time_left;
|
||||
|
||||
/* Wake up device and enable clock */
|
||||
pm_runtime_get_sync(pd->dev);
|
||||
|
@ -662,15 +667,35 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
|
|||
if (do_start)
|
||||
i2c_op(pd, OP_START);
|
||||
|
||||
/* The interrupt handler takes care of the rest... */
|
||||
timeout = wait_event_timeout(pd->wait,
|
||||
pd->sr & (ICSR_TACK | SW_DONE),
|
||||
adapter->timeout);
|
||||
if (pd->atomic_xfer) {
|
||||
unsigned long j = jiffies + pd->adap.timeout;
|
||||
|
||||
/* 'stop_after_dma' tells if DMA transfer was complete */
|
||||
i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg, pd->stop_after_dma);
|
||||
time_left = time_before_eq(jiffies, j);
|
||||
while (time_left &&
|
||||
!(pd->sr & (ICSR_TACK | SW_DONE))) {
|
||||
unsigned char sr = iic_rd(pd, ICSR);
|
||||
|
||||
if (!timeout) {
|
||||
if (sr & (ICSR_AL | ICSR_TACK |
|
||||
ICSR_WAIT | ICSR_DTE)) {
|
||||
sh_mobile_i2c_isr(0, pd);
|
||||
udelay(150);
|
||||
} else {
|
||||
cpu_relax();
|
||||
}
|
||||
time_left = time_before_eq(jiffies, j);
|
||||
}
|
||||
} else {
|
||||
/* The interrupt handler takes care of the rest... */
|
||||
time_left = wait_event_timeout(pd->wait,
|
||||
pd->sr & (ICSR_TACK | SW_DONE),
|
||||
pd->adap.timeout);
|
||||
|
||||
/* 'stop_after_dma' tells if DMA xfer was complete */
|
||||
i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg,
|
||||
pd->stop_after_dma);
|
||||
}
|
||||
|
||||
if (!time_left) {
|
||||
dev_err(pd->dev, "Transfer request timed out\n");
|
||||
if (pd->dma_direction != DMA_NONE)
|
||||
sh_mobile_i2c_cleanup_dma(pd);
|
||||
|
@ -696,14 +721,35 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
|
|||
return err ?: num;
|
||||
}
|
||||
|
||||
static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
|
||||
struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
|
||||
|
||||
pd->atomic_xfer = false;
|
||||
return sh_mobile_xfer(pd, msgs, num);
|
||||
}
|
||||
|
||||
static int sh_mobile_i2c_xfer_atomic(struct i2c_adapter *adapter,
|
||||
struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
|
||||
|
||||
pd->atomic_xfer = true;
|
||||
return sh_mobile_xfer(pd, msgs, num);
|
||||
}
|
||||
|
||||
static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm sh_mobile_i2c_algorithm = {
|
||||
.functionality = sh_mobile_i2c_func,
|
||||
.master_xfer = sh_mobile_i2c_xfer,
|
||||
.functionality = sh_mobile_i2c_func,
|
||||
.master_xfer = sh_mobile_i2c_xfer,
|
||||
.master_xfer_atomic = sh_mobile_i2c_xfer_atomic,
|
||||
};
|
||||
|
||||
static const struct i2c_adapter_quirks sh_mobile_i2c_quirks = {
|
||||
|
|
|
@ -3818,9 +3818,8 @@ bounce_map_single(struct device *dev, phys_addr_t paddr, size_t size,
|
|||
* page aligned, we don't need to use a bounce page.
|
||||
*/
|
||||
if (!IS_ALIGNED(paddr | size, VTD_PAGE_SIZE)) {
|
||||
tlb_addr = swiotlb_tbl_map_single(dev,
|
||||
phys_to_dma_unencrypted(dev, io_tlb_start),
|
||||
paddr, size, aligned_size, dir, attrs);
|
||||
tlb_addr = swiotlb_tbl_map_single(dev, paddr, size,
|
||||
aligned_size, dir, attrs);
|
||||
if (tlb_addr == DMA_MAPPING_ERROR) {
|
||||
goto swiotlb_error;
|
||||
} else {
|
||||
|
|
|
@ -180,7 +180,6 @@ config IRQ_MIPS_CPU
|
|||
select GENERIC_IRQ_CHIP
|
||||
select GENERIC_IRQ_IPI if SYS_SUPPORTS_MULTITHREADING
|
||||
select IRQ_DOMAIN
|
||||
select IRQ_DOMAIN_HIERARCHY if GENERIC_IRQ_IPI
|
||||
select GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
||||
|
||||
config CLPS711X_IRQCHIP
|
||||
|
@ -315,7 +314,6 @@ config KEYSTONE_IRQ
|
|||
config MIPS_GIC
|
||||
bool
|
||||
select GENERIC_IRQ_IPI
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select MIPS_CM
|
||||
|
||||
config INGENIC_IRQ
|
||||
|
@ -591,6 +589,7 @@ config LOONGSON_PCH_MSI
|
|||
|
||||
config MST_IRQ
|
||||
bool "MStar Interrupt Controller"
|
||||
depends on ARCH_MEDIATEK || ARCH_MSTARV7 || COMPILE_TEST
|
||||
default ARCH_MEDIATEK
|
||||
select IRQ_DOMAIN
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
|
|
|
@ -244,7 +244,7 @@ static int bcm2836_cpu_dying(unsigned int cpu)
|
|||
|
||||
#define BITS_PER_MBOX 32
|
||||
|
||||
static void bcm2836_arm_irqchip_smp_init(void)
|
||||
static void __init bcm2836_arm_irqchip_smp_init(void)
|
||||
{
|
||||
struct irq_fwspec ipi_fwspec = {
|
||||
.fwnode = intc.domain->fwnode,
|
||||
|
|
|
@ -154,8 +154,8 @@ static const struct irq_domain_ops mst_intc_domain_ops = {
|
|||
.free = irq_domain_free_irqs_common,
|
||||
};
|
||||
|
||||
int __init
|
||||
mst_intc_of_init(struct device_node *dn, struct device_node *parent)
|
||||
static int __init mst_intc_of_init(struct device_node *dn,
|
||||
struct device_node *parent)
|
||||
{
|
||||
struct irq_domain *domain, *domain_parent;
|
||||
struct mst_intc_chip_data *cd;
|
||||
|
|
|
@ -71,8 +71,7 @@ struct intc_irqpin_priv {
|
|||
};
|
||||
|
||||
struct intc_irqpin_config {
|
||||
unsigned int irlm_bit;
|
||||
unsigned needs_irlm:1;
|
||||
int irlm_bit; /* -1 if non-existent */
|
||||
};
|
||||
|
||||
static unsigned long intc_irqpin_read32(void __iomem *iomem)
|
||||
|
@ -349,11 +348,10 @@ static const struct irq_domain_ops intc_irqpin_irq_domain_ops = {
|
|||
|
||||
static const struct intc_irqpin_config intc_irqpin_irlm_r8a777x = {
|
||||
.irlm_bit = 23, /* ICR0.IRLM0 */
|
||||
.needs_irlm = 1,
|
||||
};
|
||||
|
||||
static const struct intc_irqpin_config intc_irqpin_rmobile = {
|
||||
.needs_irlm = 0,
|
||||
.irlm_bit = -1,
|
||||
};
|
||||
|
||||
static const struct of_device_id intc_irqpin_dt_ids[] = {
|
||||
|
@ -470,7 +468,7 @@ static int intc_irqpin_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* configure "individual IRQ mode" where needed */
|
||||
if (config && config->needs_irlm) {
|
||||
if (config && config->irlm_bit >= 0) {
|
||||
if (io[INTC_IRQPIN_REG_IRLM])
|
||||
intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_IRLM,
|
||||
config->irlm_bit, 1, 1);
|
||||
|
|
|
@ -99,7 +99,7 @@ static inline void plic_irq_toggle(const struct cpumask *mask,
|
|||
struct irq_data *d, int enable)
|
||||
{
|
||||
int cpu;
|
||||
struct plic_priv *priv = irq_get_chip_data(d->irq);
|
||||
struct plic_priv *priv = irq_data_get_irq_chip_data(d);
|
||||
|
||||
writel(enable, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID);
|
||||
for_each_cpu(cpu, mask) {
|
||||
|
@ -115,7 +115,7 @@ static void plic_irq_unmask(struct irq_data *d)
|
|||
{
|
||||
struct cpumask amask;
|
||||
unsigned int cpu;
|
||||
struct plic_priv *priv = irq_get_chip_data(d->irq);
|
||||
struct plic_priv *priv = irq_data_get_irq_chip_data(d);
|
||||
|
||||
cpumask_and(&amask, &priv->lmask, cpu_online_mask);
|
||||
cpu = cpumask_any_and(irq_data_get_affinity_mask(d),
|
||||
|
@ -127,7 +127,7 @@ static void plic_irq_unmask(struct irq_data *d)
|
|||
|
||||
static void plic_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct plic_priv *priv = irq_get_chip_data(d->irq);
|
||||
struct plic_priv *priv = irq_data_get_irq_chip_data(d);
|
||||
|
||||
plic_irq_toggle(&priv->lmask, d, 0);
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ static int plic_set_affinity(struct irq_data *d,
|
|||
{
|
||||
unsigned int cpu;
|
||||
struct cpumask amask;
|
||||
struct plic_priv *priv = irq_get_chip_data(d->irq);
|
||||
struct plic_priv *priv = irq_data_get_irq_chip_data(d);
|
||||
|
||||
cpumask_and(&amask, &priv->lmask, mask_val);
|
||||
|
||||
|
@ -151,7 +151,7 @@ static int plic_set_affinity(struct irq_data *d,
|
|||
return -EINVAL;
|
||||
|
||||
plic_irq_toggle(&priv->lmask, d, 0);
|
||||
plic_irq_toggle(cpumask_of(cpu), d, 1);
|
||||
plic_irq_toggle(cpumask_of(cpu), d, !irqd_irq_masked(d));
|
||||
|
||||
irq_data_update_effective_affinity(d, cpumask_of(cpu));
|
||||
|
||||
|
|
|
@ -195,6 +195,10 @@ static const struct stm32_desc_irq stm32mp1_desc_irq[] = {
|
|||
{ .exti = 25, .irq_parent = 107, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 30, .irq_parent = 52, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 47, .irq_parent = 93, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 48, .irq_parent = 138, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 50, .irq_parent = 139, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 52, .irq_parent = 140, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 53, .irq_parent = 141, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 54, .irq_parent = 135, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 61, .irq_parent = 100, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 65, .irq_parent = 144, .chip = &stm32_exti_h_chip },
|
||||
|
|
|
@ -85,6 +85,17 @@ struct ti_sci_inta_vint_desc {
|
|||
* @base: Base address of the memory mapped IO registers
|
||||
* @pdev: Pointer to platform device.
|
||||
* @ti_sci_id: TI-SCI device identifier
|
||||
* @unmapped_cnt: Number of @unmapped_dev_ids entries
|
||||
* @unmapped_dev_ids: Pointer to an array of TI-SCI device identifiers of
|
||||
* unmapped event sources.
|
||||
* Unmapped Events are not part of the Global Event Map and
|
||||
* they are converted to Global event within INTA to be
|
||||
* received by the same INTA to generate an interrupt.
|
||||
* In case an interrupt request comes for a device which is
|
||||
* generating Unmapped Event, we must use the INTA's TI-SCI
|
||||
* device identifier in place of the source device
|
||||
* identifier to let sysfw know where it has to program the
|
||||
* Global Event number.
|
||||
*/
|
||||
struct ti_sci_inta_irq_domain {
|
||||
const struct ti_sci_handle *sci;
|
||||
|
@ -96,11 +107,37 @@ struct ti_sci_inta_irq_domain {
|
|||
void __iomem *base;
|
||||
struct platform_device *pdev;
|
||||
u32 ti_sci_id;
|
||||
|
||||
int unmapped_cnt;
|
||||
u16 *unmapped_dev_ids;
|
||||
};
|
||||
|
||||
#define to_vint_desc(e, i) container_of(e, struct ti_sci_inta_vint_desc, \
|
||||
events[i])
|
||||
|
||||
static u16 ti_sci_inta_get_dev_id(struct ti_sci_inta_irq_domain *inta, u32 hwirq)
|
||||
{
|
||||
u16 dev_id = HWIRQ_TO_DEVID(hwirq);
|
||||
int i;
|
||||
|
||||
if (inta->unmapped_cnt == 0)
|
||||
return dev_id;
|
||||
|
||||
/*
|
||||
* For devices sending Unmapped Events we must use the INTA's TI-SCI
|
||||
* device identifier number to be able to convert it to a Global Event
|
||||
* and map it to an interrupt.
|
||||
*/
|
||||
for (i = 0; i < inta->unmapped_cnt; i++) {
|
||||
if (dev_id == inta->unmapped_dev_ids[i]) {
|
||||
dev_id = inta->ti_sci_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return dev_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_inta_irq_handler() - Chained IRQ handler for the vint irqs
|
||||
* @desc: Pointer to irq_desc corresponding to the irq
|
||||
|
@ -251,7 +288,7 @@ static struct ti_sci_inta_event_desc *ti_sci_inta_alloc_event(struct ti_sci_inta
|
|||
u16 dev_id, dev_index;
|
||||
int err;
|
||||
|
||||
dev_id = HWIRQ_TO_DEVID(hwirq);
|
||||
dev_id = ti_sci_inta_get_dev_id(inta, hwirq);
|
||||
dev_index = HWIRQ_TO_IRQID(hwirq);
|
||||
|
||||
event_desc = &vint_desc->events[free_bit];
|
||||
|
@ -352,14 +389,15 @@ static void ti_sci_inta_free_irq(struct ti_sci_inta_event_desc *event_desc,
|
|||
{
|
||||
struct ti_sci_inta_vint_desc *vint_desc;
|
||||
struct ti_sci_inta_irq_domain *inta;
|
||||
u16 dev_id;
|
||||
|
||||
vint_desc = to_vint_desc(event_desc, event_desc->vint_bit);
|
||||
inta = vint_desc->domain->host_data;
|
||||
dev_id = ti_sci_inta_get_dev_id(inta, hwirq);
|
||||
/* free event irq */
|
||||
mutex_lock(&inta->vint_mutex);
|
||||
inta->sci->ops.rm_irq_ops.free_event_map(inta->sci,
|
||||
HWIRQ_TO_DEVID(hwirq),
|
||||
HWIRQ_TO_IRQID(hwirq),
|
||||
dev_id, HWIRQ_TO_IRQID(hwirq),
|
||||
inta->ti_sci_id,
|
||||
vint_desc->vint_id,
|
||||
event_desc->global_event,
|
||||
|
@ -574,6 +612,41 @@ static struct msi_domain_info ti_sci_inta_msi_domain_info = {
|
|||
.chip = &ti_sci_inta_msi_irq_chip,
|
||||
};
|
||||
|
||||
static int ti_sci_inta_get_unmapped_sources(struct ti_sci_inta_irq_domain *inta)
|
||||
{
|
||||
struct device *dev = &inta->pdev->dev;
|
||||
struct device_node *node = dev_of_node(dev);
|
||||
struct of_phandle_iterator it;
|
||||
int count, err, ret, i;
|
||||
|
||||
count = of_count_phandle_with_args(node, "ti,unmapped-event-sources", NULL);
|
||||
if (count <= 0)
|
||||
return 0;
|
||||
|
||||
inta->unmapped_dev_ids = devm_kcalloc(dev, count,
|
||||
sizeof(*inta->unmapped_dev_ids),
|
||||
GFP_KERNEL);
|
||||
if (!inta->unmapped_dev_ids)
|
||||
return -ENOMEM;
|
||||
|
||||
i = 0;
|
||||
of_for_each_phandle(&it, err, node, "ti,unmapped-event-sources", NULL, 0) {
|
||||
u32 dev_id;
|
||||
|
||||
ret = of_property_read_u32(it.node, "ti,sci-dev-id", &dev_id);
|
||||
if (ret) {
|
||||
dev_err(dev, "ti,sci-dev-id read failure for %pOFf\n", it.node);
|
||||
of_node_put(it.node);
|
||||
return ret;
|
||||
}
|
||||
inta->unmapped_dev_ids[i++] = dev_id;
|
||||
}
|
||||
|
||||
inta->unmapped_cnt = count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct irq_domain *parent_domain, *domain, *msi_domain;
|
||||
|
@ -629,6 +702,10 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(inta->base))
|
||||
return PTR_ERR(inta->base);
|
||||
|
||||
ret = ti_sci_inta_get_unmapped_sources(inta);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
domain = irq_domain_add_linear(dev_of_node(dev),
|
||||
ti_sci_get_num_resources(inta->vint),
|
||||
&ti_sci_inta_irq_domain_ops, inta);
|
||||
|
|
|
@ -393,8 +393,10 @@ static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,
|
|||
mv88e6xxx_reg_lock(chip);
|
||||
|
||||
err = mv88e6xxx_fid_map(chip, fid_bitmap);
|
||||
if (err)
|
||||
if (err) {
|
||||
kfree(table);
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
fid = find_next_bit(fid_bitmap, MV88E6XXX_N_FID, fid + 1);
|
||||
|
|
|
@ -2124,6 +2124,9 @@ void cxgb4_inline_tx_skb(const struct sk_buff *skb, const struct sge_txq *q,
|
|||
void cxgb4_write_sgl(const struct sk_buff *skb, struct sge_txq *q,
|
||||
struct ulptx_sgl *sgl, u64 *end, unsigned int start,
|
||||
const dma_addr_t *addr);
|
||||
void cxgb4_write_partial_sgl(const struct sk_buff *skb, struct sge_txq *q,
|
||||
struct ulptx_sgl *sgl, u64 *end,
|
||||
const dma_addr_t *addr, u32 start, u32 send_len);
|
||||
void cxgb4_ring_tx_db(struct adapter *adap, struct sge_txq *q, int n);
|
||||
int t4_set_vlan_acl(struct adapter *adap, unsigned int mbox, unsigned int vf,
|
||||
u16 vlan);
|
||||
|
|
|
@ -3573,6 +3573,8 @@ static int chcr_stats_show(struct seq_file *seq, void *v)
|
|||
atomic64_read(&adap->ch_ktls_stats.ktls_tx_complete_pkts));
|
||||
seq_printf(seq, "TX trim pkts : %20llu\n",
|
||||
atomic64_read(&adap->ch_ktls_stats.ktls_tx_trimmed_pkts));
|
||||
seq_printf(seq, "TX sw fallback : %20llu\n",
|
||||
atomic64_read(&adap->ch_ktls_stats.ktls_tx_fallback));
|
||||
while (i < MAX_NPORTS) {
|
||||
ktls_port = &adap->ch_ktls_stats.ktls_port[i];
|
||||
seq_printf(seq, "Port %d\n", i);
|
||||
|
|
|
@ -1176,6 +1176,7 @@ static u16 cxgb_select_queue(struct net_device *dev, struct sk_buff *skb,
|
|||
txq = netdev_pick_tx(dev, skb, sb_dev);
|
||||
if (xfrm_offload(skb) || is_ptp_enabled(skb, dev) ||
|
||||
skb->encapsulation ||
|
||||
cxgb4_is_ktls_skb(skb) ||
|
||||
(proto != IPPROTO_TCP && proto != IPPROTO_UDP))
|
||||
txq = txq % pi->nqsets;
|
||||
|
||||
|
|
|
@ -388,6 +388,7 @@ struct ch_ktls_stats_debug {
|
|||
atomic64_t ktls_tx_retransmit_pkts;
|
||||
atomic64_t ktls_tx_complete_pkts;
|
||||
atomic64_t ktls_tx_trimmed_pkts;
|
||||
atomic64_t ktls_tx_fallback;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -493,6 +494,11 @@ struct cxgb4_uld_info {
|
|||
#endif
|
||||
};
|
||||
|
||||
static inline bool cxgb4_is_ktls_skb(struct sk_buff *skb)
|
||||
{
|
||||
return skb->sk && tls_is_sk_tx_device_offloaded(skb->sk);
|
||||
}
|
||||
|
||||
void cxgb4_uld_enable(struct adapter *adap);
|
||||
void cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p);
|
||||
int cxgb4_unregister_uld(enum cxgb4_uld type);
|
||||
|
|
|
@ -890,6 +890,114 @@ void cxgb4_write_sgl(const struct sk_buff *skb, struct sge_txq *q,
|
|||
}
|
||||
EXPORT_SYMBOL(cxgb4_write_sgl);
|
||||
|
||||
/* cxgb4_write_partial_sgl - populate SGL for partial packet
|
||||
* @skb: the packet
|
||||
* @q: the Tx queue we are writing into
|
||||
* @sgl: starting location for writing the SGL
|
||||
* @end: points right after the end of the SGL
|
||||
* @addr: the list of bus addresses for the SGL elements
|
||||
* @start: start offset in the SKB where partial data starts
|
||||
* @len: length of data from @start to send out
|
||||
*
|
||||
* This API will handle sending out partial data of a skb if required.
|
||||
* Unlike cxgb4_write_sgl, @start can be any offset into the skb data,
|
||||
* and @len will decide how much data after @start offset to send out.
|
||||
*/
|
||||
void cxgb4_write_partial_sgl(const struct sk_buff *skb, struct sge_txq *q,
|
||||
struct ulptx_sgl *sgl, u64 *end,
|
||||
const dma_addr_t *addr, u32 start, u32 len)
|
||||
{
|
||||
struct ulptx_sge_pair buf[MAX_SKB_FRAGS / 2 + 1] = {0}, *to;
|
||||
u32 frag_size, skb_linear_data_len = skb_headlen(skb);
|
||||
struct skb_shared_info *si = skb_shinfo(skb);
|
||||
u8 i = 0, frag_idx = 0, nfrags = 0;
|
||||
skb_frag_t *frag;
|
||||
|
||||
/* Fill the first SGL either from linear data or from partial
|
||||
* frag based on @start.
|
||||
*/
|
||||
if (unlikely(start < skb_linear_data_len)) {
|
||||
frag_size = min(len, skb_linear_data_len - start);
|
||||
sgl->len0 = htonl(frag_size);
|
||||
sgl->addr0 = cpu_to_be64(addr[0] + start);
|
||||
len -= frag_size;
|
||||
nfrags++;
|
||||
} else {
|
||||
start -= skb_linear_data_len;
|
||||
frag = &si->frags[frag_idx];
|
||||
frag_size = skb_frag_size(frag);
|
||||
/* find the first frag */
|
||||
while (start >= frag_size) {
|
||||
start -= frag_size;
|
||||
frag_idx++;
|
||||
frag = &si->frags[frag_idx];
|
||||
frag_size = skb_frag_size(frag);
|
||||
}
|
||||
|
||||
frag_size = min(len, skb_frag_size(frag) - start);
|
||||
sgl->len0 = cpu_to_be32(frag_size);
|
||||
sgl->addr0 = cpu_to_be64(addr[frag_idx + 1] + start);
|
||||
len -= frag_size;
|
||||
nfrags++;
|
||||
frag_idx++;
|
||||
}
|
||||
|
||||
/* If the entire partial data fit in one SGL, then send it out
|
||||
* now.
|
||||
*/
|
||||
if (!len)
|
||||
goto done;
|
||||
|
||||
/* Most of the complexity below deals with the possibility we hit the
|
||||
* end of the queue in the middle of writing the SGL. For this case
|
||||
* only we create the SGL in a temporary buffer and then copy it.
|
||||
*/
|
||||
to = (u8 *)end > (u8 *)q->stat ? buf : sgl->sge;
|
||||
|
||||
/* If the skb couldn't fit in first SGL completely, fill the
|
||||
* rest of the frags in subsequent SGLs. Note that each SGL
|
||||
* pair can store 2 frags.
|
||||
*/
|
||||
while (len) {
|
||||
frag_size = min(len, skb_frag_size(&si->frags[frag_idx]));
|
||||
to->len[i & 1] = cpu_to_be32(frag_size);
|
||||
to->addr[i & 1] = cpu_to_be64(addr[frag_idx + 1]);
|
||||
if (i && (i & 1))
|
||||
to++;
|
||||
nfrags++;
|
||||
frag_idx++;
|
||||
i++;
|
||||
len -= frag_size;
|
||||
}
|
||||
|
||||
/* If we ended in an odd boundary, then set the second SGL's
|
||||
* length in the pair to 0.
|
||||
*/
|
||||
if (i & 1)
|
||||
to->len[1] = cpu_to_be32(0);
|
||||
|
||||
/* Copy from temporary buffer to Tx ring, in case we hit the
|
||||
* end of the queue in the middle of writing the SGL.
|
||||
*/
|
||||
if (unlikely((u8 *)end > (u8 *)q->stat)) {
|
||||
u32 part0 = (u8 *)q->stat - (u8 *)sgl->sge, part1;
|
||||
|
||||
if (likely(part0))
|
||||
memcpy(sgl->sge, buf, part0);
|
||||
part1 = (u8 *)end - (u8 *)q->stat;
|
||||
memcpy(q->desc, (u8 *)buf + part0, part1);
|
||||
end = (void *)q->desc + part1;
|
||||
}
|
||||
|
||||
/* 0-pad to multiple of 16 */
|
||||
if ((uintptr_t)end & 8)
|
||||
*end = 0;
|
||||
done:
|
||||
sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) |
|
||||
ULPTX_NSGE_V(nfrags));
|
||||
}
|
||||
EXPORT_SYMBOL(cxgb4_write_partial_sgl);
|
||||
|
||||
/* This function copies 64 byte coalesced work request to
|
||||
* memory mapped BAR2 space. For coalesced WR SGE fetches
|
||||
* data from the FIFO instead of from Host.
|
||||
|
@ -1422,7 +1530,8 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
#endif /* CHELSIO_IPSEC_INLINE */
|
||||
|
||||
#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE)
|
||||
if (skb->decrypted)
|
||||
if (cxgb4_is_ktls_skb(skb) &&
|
||||
(skb->len - (skb_transport_offset(skb) + tcp_hdrlen(skb))))
|
||||
return adap->uld[CXGB4_ULD_KTLS].tx_handler(skb, dev);
|
||||
#endif /* CHELSIO_TLS_DEVICE */
|
||||
|
||||
|
|
|
@ -14,6 +14,50 @@
|
|||
static LIST_HEAD(uld_ctx_list);
|
||||
static DEFINE_MUTEX(dev_mutex);
|
||||
|
||||
/* chcr_get_nfrags_to_send: get the remaining nfrags after start offset
|
||||
* @skb: skb
|
||||
* @start: start offset.
|
||||
* @len: how much data to send after @start
|
||||
*/
|
||||
static int chcr_get_nfrags_to_send(struct sk_buff *skb, u32 start, u32 len)
|
||||
{
|
||||
struct skb_shared_info *si = skb_shinfo(skb);
|
||||
u32 frag_size, skb_linear_data_len = skb_headlen(skb);
|
||||
u8 nfrags = 0, frag_idx = 0;
|
||||
skb_frag_t *frag;
|
||||
|
||||
/* if its a linear skb then return 1 */
|
||||
if (!skb_is_nonlinear(skb))
|
||||
return 1;
|
||||
|
||||
if (unlikely(start < skb_linear_data_len)) {
|
||||
frag_size = min(len, skb_linear_data_len - start);
|
||||
start = 0;
|
||||
} else {
|
||||
start -= skb_linear_data_len;
|
||||
|
||||
frag = &si->frags[frag_idx];
|
||||
frag_size = skb_frag_size(frag);
|
||||
while (start >= frag_size) {
|
||||
start -= frag_size;
|
||||
frag_idx++;
|
||||
frag = &si->frags[frag_idx];
|
||||
frag_size = skb_frag_size(frag);
|
||||
}
|
||||
frag_size = min(len, skb_frag_size(frag) - start);
|
||||
}
|
||||
len -= frag_size;
|
||||
nfrags++;
|
||||
|
||||
while (len) {
|
||||
frag_size = min(len, skb_frag_size(&si->frags[frag_idx]));
|
||||
len -= frag_size;
|
||||
nfrags++;
|
||||
frag_idx++;
|
||||
}
|
||||
return nfrags;
|
||||
}
|
||||
|
||||
static int chcr_init_tcb_fields(struct chcr_ktls_info *tx_info);
|
||||
/*
|
||||
* chcr_ktls_save_keys: calculate and save crypto keys.
|
||||
|
@ -689,7 +733,8 @@ static int chcr_ktls_cpl_set_tcb_rpl(struct adapter *adap, unsigned char *input)
|
|||
}
|
||||
|
||||
static void *__chcr_write_cpl_set_tcb_ulp(struct chcr_ktls_info *tx_info,
|
||||
u32 tid, void *pos, u16 word, u64 mask,
|
||||
u32 tid, void *pos, u16 word,
|
||||
struct sge_eth_txq *q, u64 mask,
|
||||
u64 val, u32 reply)
|
||||
{
|
||||
struct cpl_set_tcb_field_core *cpl;
|
||||
|
@ -698,7 +743,10 @@ static void *__chcr_write_cpl_set_tcb_ulp(struct chcr_ktls_info *tx_info,
|
|||
|
||||
/* ULP_TXPKT */
|
||||
txpkt = pos;
|
||||
txpkt->cmd_dest = htonl(ULPTX_CMD_V(ULP_TX_PKT) | ULP_TXPKT_DEST_V(0));
|
||||
txpkt->cmd_dest = htonl(ULPTX_CMD_V(ULP_TX_PKT) |
|
||||
ULP_TXPKT_CHANNELID_V(tx_info->port_id) |
|
||||
ULP_TXPKT_FID_V(q->q.cntxt_id) |
|
||||
ULP_TXPKT_RO_F);
|
||||
txpkt->len = htonl(DIV_ROUND_UP(CHCR_SET_TCB_FIELD_LEN, 16));
|
||||
|
||||
/* ULPTX_IDATA sub-command */
|
||||
|
@ -753,7 +801,7 @@ static void *chcr_write_cpl_set_tcb_ulp(struct chcr_ktls_info *tx_info,
|
|||
} else {
|
||||
u8 buf[48] = {0};
|
||||
|
||||
__chcr_write_cpl_set_tcb_ulp(tx_info, tid, buf, word,
|
||||
__chcr_write_cpl_set_tcb_ulp(tx_info, tid, buf, word, q,
|
||||
mask, val, reply);
|
||||
|
||||
return chcr_copy_to_txd(buf, &q->q, pos,
|
||||
|
@ -761,7 +809,7 @@ static void *chcr_write_cpl_set_tcb_ulp(struct chcr_ktls_info *tx_info,
|
|||
}
|
||||
}
|
||||
|
||||
pos = __chcr_write_cpl_set_tcb_ulp(tx_info, tid, pos, word,
|
||||
pos = __chcr_write_cpl_set_tcb_ulp(tx_info, tid, pos, word, q,
|
||||
mask, val, reply);
|
||||
|
||||
/* check again if we are at the end of the queue */
|
||||
|
@ -783,11 +831,11 @@ static void *chcr_write_cpl_set_tcb_ulp(struct chcr_ktls_info *tx_info,
|
|||
*/
|
||||
static int chcr_ktls_xmit_tcb_cpls(struct chcr_ktls_info *tx_info,
|
||||
struct sge_eth_txq *q, u64 tcp_seq,
|
||||
u64 tcp_ack, u64 tcp_win)
|
||||
u64 tcp_ack, u64 tcp_win, bool offset)
|
||||
{
|
||||
bool first_wr = ((tx_info->prev_ack == 0) && (tx_info->prev_win == 0));
|
||||
struct ch_ktls_port_stats_debug *port_stats;
|
||||
u32 len, cpl = 0, ndesc, wr_len;
|
||||
u32 len, cpl = 0, ndesc, wr_len, wr_mid = 0;
|
||||
struct fw_ulptx_wr *wr;
|
||||
int credits;
|
||||
void *pos;
|
||||
|
@ -803,6 +851,11 @@ static int chcr_ktls_xmit_tcb_cpls(struct chcr_ktls_info *tx_info,
|
|||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
if (unlikely(credits < ETHTXQ_STOP_THRES)) {
|
||||
chcr_eth_txq_stop(q);
|
||||
wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
|
||||
}
|
||||
|
||||
pos = &q->q.desc[q->q.pidx];
|
||||
/* make space for WR, we'll fill it later when we know all the cpls
|
||||
* being sent out and have complete length.
|
||||
|
@ -818,7 +871,7 @@ static int chcr_ktls_xmit_tcb_cpls(struct chcr_ktls_info *tx_info,
|
|||
cpl++;
|
||||
}
|
||||
/* reset snd una if it's a re-transmit pkt */
|
||||
if (tcp_seq != tx_info->prev_seq) {
|
||||
if (tcp_seq != tx_info->prev_seq || offset) {
|
||||
/* reset snd_una */
|
||||
port_stats =
|
||||
&tx_info->adap->ch_ktls_stats.ktls_port[tx_info->port_id];
|
||||
|
@ -827,7 +880,8 @@ static int chcr_ktls_xmit_tcb_cpls(struct chcr_ktls_info *tx_info,
|
|||
TCB_SND_UNA_RAW_V
|
||||
(TCB_SND_UNA_RAW_M),
|
||||
TCB_SND_UNA_RAW_V(0), 0);
|
||||
atomic64_inc(&port_stats->ktls_tx_ooo);
|
||||
if (tcp_seq != tx_info->prev_seq)
|
||||
atomic64_inc(&port_stats->ktls_tx_ooo);
|
||||
cpl++;
|
||||
}
|
||||
/* update ack */
|
||||
|
@ -856,7 +910,8 @@ static int chcr_ktls_xmit_tcb_cpls(struct chcr_ktls_info *tx_info,
|
|||
wr->op_to_compl = htonl(FW_WR_OP_V(FW_ULPTX_WR));
|
||||
wr->cookie = 0;
|
||||
/* fill len in wr field */
|
||||
wr->flowid_len16 = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(len, 16)));
|
||||
wr->flowid_len16 = htonl(wr_mid |
|
||||
FW_WR_LEN16_V(DIV_ROUND_UP(len, 16)));
|
||||
|
||||
ndesc = DIV_ROUND_UP(len, 64);
|
||||
chcr_txq_advance(&q->q, ndesc);
|
||||
|
@ -865,35 +920,15 @@ static int chcr_ktls_xmit_tcb_cpls(struct chcr_ktls_info *tx_info,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* chcr_ktls_skb_copy
|
||||
* @nskb - new skb where the frags to be added.
|
||||
* @skb - old skb from which frags will be copied.
|
||||
*/
|
||||
static void chcr_ktls_skb_copy(struct sk_buff *skb, struct sk_buff *nskb)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
||||
skb_shinfo(nskb)->frags[i] = skb_shinfo(skb)->frags[i];
|
||||
__skb_frag_ref(&skb_shinfo(nskb)->frags[i]);
|
||||
}
|
||||
|
||||
skb_shinfo(nskb)->nr_frags = skb_shinfo(skb)->nr_frags;
|
||||
nskb->len += skb->data_len;
|
||||
nskb->data_len = skb->data_len;
|
||||
nskb->truesize += skb->data_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* chcr_ktls_get_tx_flits
|
||||
* returns number of flits to be sent out, it includes key context length, WR
|
||||
* size and skb fragments.
|
||||
*/
|
||||
static unsigned int
|
||||
chcr_ktls_get_tx_flits(const struct sk_buff *skb, unsigned int key_ctx_len)
|
||||
chcr_ktls_get_tx_flits(u32 nr_frags, unsigned int key_ctx_len)
|
||||
{
|
||||
return chcr_sgl_len(skb_shinfo(skb)->nr_frags) +
|
||||
return chcr_sgl_len(nr_frags) +
|
||||
DIV_ROUND_UP(key_ctx_len + CHCR_KTLS_WR_SIZE, 8);
|
||||
}
|
||||
|
||||
|
@ -957,8 +992,10 @@ chcr_ktls_write_tcp_options(struct chcr_ktls_info *tx_info, struct sk_buff *skb,
|
|||
struct tcphdr *tcp;
|
||||
int len16, pktlen;
|
||||
struct iphdr *ip;
|
||||
u32 wr_mid = 0;
|
||||
int credits;
|
||||
u8 buf[150];
|
||||
u64 cntrl1;
|
||||
void *pos;
|
||||
|
||||
iplen = skb_network_header_len(skb);
|
||||
|
@ -967,7 +1004,7 @@ chcr_ktls_write_tcp_options(struct chcr_ktls_info *tx_info, struct sk_buff *skb,
|
|||
/* packet length = eth hdr len + ip hdr len + tcp hdr len
|
||||
* (including options).
|
||||
*/
|
||||
pktlen = skb->len - skb->data_len;
|
||||
pktlen = skb_transport_offset(skb) + tcp_hdrlen(skb);
|
||||
|
||||
ctrl = sizeof(*cpl) + pktlen;
|
||||
len16 = DIV_ROUND_UP(sizeof(*wr) + ctrl, 16);
|
||||
|
@ -980,6 +1017,11 @@ chcr_ktls_write_tcp_options(struct chcr_ktls_info *tx_info, struct sk_buff *skb,
|
|||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
if (unlikely(credits < ETHTXQ_STOP_THRES)) {
|
||||
chcr_eth_txq_stop(q);
|
||||
wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
|
||||
}
|
||||
|
||||
pos = &q->q.desc[q->q.pidx];
|
||||
wr = pos;
|
||||
|
||||
|
@ -987,7 +1029,7 @@ chcr_ktls_write_tcp_options(struct chcr_ktls_info *tx_info, struct sk_buff *skb,
|
|||
wr->op_immdlen = htonl(FW_WR_OP_V(FW_ETH_TX_PKT_WR) |
|
||||
FW_WR_IMMDLEN_V(ctrl));
|
||||
|
||||
wr->equiq_to_len16 = htonl(FW_WR_LEN16_V(len16));
|
||||
wr->equiq_to_len16 = htonl(wr_mid | FW_WR_LEN16_V(len16));
|
||||
wr->r3 = 0;
|
||||
|
||||
cpl = (void *)(wr + 1);
|
||||
|
@ -997,22 +1039,28 @@ chcr_ktls_write_tcp_options(struct chcr_ktls_info *tx_info, struct sk_buff *skb,
|
|||
TXPKT_PF_V(tx_info->adap->pf));
|
||||
cpl->pack = 0;
|
||||
cpl->len = htons(pktlen);
|
||||
/* checksum offload */
|
||||
cpl->ctrl1 = 0;
|
||||
|
||||
pos = cpl + 1;
|
||||
|
||||
memcpy(buf, skb->data, pktlen);
|
||||
if (tx_info->ip_family == AF_INET) {
|
||||
/* we need to correct ip header len */
|
||||
ip = (struct iphdr *)(buf + maclen);
|
||||
ip->tot_len = htons(pktlen - maclen);
|
||||
cntrl1 = TXPKT_CSUM_TYPE_V(TX_CSUM_TCPIP);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
} else {
|
||||
ip6 = (struct ipv6hdr *)(buf + maclen);
|
||||
ip6->payload_len = htons(pktlen - maclen - iplen);
|
||||
cntrl1 = TXPKT_CSUM_TYPE_V(TX_CSUM_TCPIP6);
|
||||
#endif
|
||||
}
|
||||
|
||||
cntrl1 |= T6_TXPKT_ETHHDR_LEN_V(maclen - ETH_HLEN) |
|
||||
TXPKT_IPHDR_LEN_V(iplen);
|
||||
/* checksum offload */
|
||||
cpl->ctrl1 = cpu_to_be64(cntrl1);
|
||||
|
||||
pos = cpl + 1;
|
||||
|
||||
/* now take care of the tcp header, if fin is not set then clear push
|
||||
* bit as well, and if fin is set, it will be sent at the last so we
|
||||
* need to update the tcp sequence number as per the last packet.
|
||||
|
@ -1031,71 +1079,6 @@ chcr_ktls_write_tcp_options(struct chcr_ktls_info *tx_info, struct sk_buff *skb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* chcr_ktls_skb_shift - Shifts request length paged data from skb to another.
|
||||
* @tgt- buffer into which tail data gets added
|
||||
* @skb- buffer from which the paged data comes from
|
||||
* @shiftlen- shift up to this many bytes
|
||||
*/
|
||||
static int chcr_ktls_skb_shift(struct sk_buff *tgt, struct sk_buff *skb,
|
||||
int shiftlen)
|
||||
{
|
||||
skb_frag_t *fragfrom, *fragto;
|
||||
int from, to, todo;
|
||||
|
||||
WARN_ON(shiftlen > skb->data_len);
|
||||
|
||||
todo = shiftlen;
|
||||
from = 0;
|
||||
to = 0;
|
||||
fragfrom = &skb_shinfo(skb)->frags[from];
|
||||
|
||||
while ((todo > 0) && (from < skb_shinfo(skb)->nr_frags)) {
|
||||
fragfrom = &skb_shinfo(skb)->frags[from];
|
||||
fragto = &skb_shinfo(tgt)->frags[to];
|
||||
|
||||
if (todo >= skb_frag_size(fragfrom)) {
|
||||
*fragto = *fragfrom;
|
||||
todo -= skb_frag_size(fragfrom);
|
||||
from++;
|
||||
to++;
|
||||
|
||||
} else {
|
||||
__skb_frag_ref(fragfrom);
|
||||
skb_frag_page_copy(fragto, fragfrom);
|
||||
skb_frag_off_copy(fragto, fragfrom);
|
||||
skb_frag_size_set(fragto, todo);
|
||||
|
||||
skb_frag_off_add(fragfrom, todo);
|
||||
skb_frag_size_sub(fragfrom, todo);
|
||||
todo = 0;
|
||||
|
||||
to++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ready to "commit" this state change to tgt */
|
||||
skb_shinfo(tgt)->nr_frags = to;
|
||||
|
||||
/* Reposition in the original skb */
|
||||
to = 0;
|
||||
while (from < skb_shinfo(skb)->nr_frags)
|
||||
skb_shinfo(skb)->frags[to++] = skb_shinfo(skb)->frags[from++];
|
||||
|
||||
skb_shinfo(skb)->nr_frags = to;
|
||||
|
||||
WARN_ON(todo > 0 && !skb_shinfo(skb)->nr_frags);
|
||||
|
||||
skb->len -= shiftlen;
|
||||
skb->data_len -= shiftlen;
|
||||
skb->truesize -= shiftlen;
|
||||
tgt->len += shiftlen;
|
||||
tgt->data_len += shiftlen;
|
||||
tgt->truesize += shiftlen;
|
||||
|
||||
return shiftlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* chcr_ktls_xmit_wr_complete: This sends out the complete record. If an skb
|
||||
* received has partial end part of the record, send out the complete record, so
|
||||
|
@ -1111,6 +1094,8 @@ static int chcr_ktls_skb_shift(struct sk_buff *tgt, struct sk_buff *skb,
|
|||
static int chcr_ktls_xmit_wr_complete(struct sk_buff *skb,
|
||||
struct chcr_ktls_info *tx_info,
|
||||
struct sge_eth_txq *q, u32 tcp_seq,
|
||||
bool is_last_wr, u32 data_len,
|
||||
u32 skb_offset, u32 nfrags,
|
||||
bool tcp_push, u32 mss)
|
||||
{
|
||||
u32 len16, wr_mid = 0, flits = 0, ndesc, cipher_start;
|
||||
|
@ -1126,7 +1111,7 @@ static int chcr_ktls_xmit_wr_complete(struct sk_buff *skb,
|
|||
u64 *end;
|
||||
|
||||
/* get the number of flits required */
|
||||
flits = chcr_ktls_get_tx_flits(skb, tx_info->key_ctx_len);
|
||||
flits = chcr_ktls_get_tx_flits(nfrags, tx_info->key_ctx_len);
|
||||
/* number of descriptors */
|
||||
ndesc = chcr_flits_to_desc(flits);
|
||||
/* check if enough credits available */
|
||||
|
@ -1155,6 +1140,9 @@ static int chcr_ktls_xmit_wr_complete(struct sk_buff *skb,
|
|||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
if (!is_last_wr)
|
||||
skb_get(skb);
|
||||
|
||||
pos = &q->q.desc[q->q.pidx];
|
||||
end = (u64 *)pos + flits;
|
||||
/* FW_ULPTX_WR */
|
||||
|
@ -1187,7 +1175,7 @@ static int chcr_ktls_xmit_wr_complete(struct sk_buff *skb,
|
|||
CPL_TX_SEC_PDU_CPLLEN_V(CHCR_CPL_TX_SEC_PDU_LEN_64BIT) |
|
||||
CPL_TX_SEC_PDU_PLACEHOLDER_V(1) |
|
||||
CPL_TX_SEC_PDU_IVINSRTOFST_V(TLS_HEADER_SIZE + 1));
|
||||
cpl->pldlen = htonl(skb->data_len);
|
||||
cpl->pldlen = htonl(data_len);
|
||||
|
||||
/* encryption should start after tls header size + iv size */
|
||||
cipher_start = TLS_HEADER_SIZE + tx_info->iv_size + 1;
|
||||
|
@ -1229,7 +1217,7 @@ static int chcr_ktls_xmit_wr_complete(struct sk_buff *skb,
|
|||
/* CPL_TX_DATA */
|
||||
tx_data = (void *)pos;
|
||||
OPCODE_TID(tx_data) = htonl(MK_OPCODE_TID(CPL_TX_DATA, tx_info->tid));
|
||||
tx_data->len = htonl(TX_DATA_MSS_V(mss) | TX_LENGTH_V(skb->data_len));
|
||||
tx_data->len = htonl(TX_DATA_MSS_V(mss) | TX_LENGTH_V(data_len));
|
||||
|
||||
tx_data->rsvd = htonl(tcp_seq);
|
||||
|
||||
|
@ -1249,8 +1237,8 @@ static int chcr_ktls_xmit_wr_complete(struct sk_buff *skb,
|
|||
}
|
||||
|
||||
/* send the complete packet except the header */
|
||||
cxgb4_write_sgl(skb, &q->q, pos, end, skb->len - skb->data_len,
|
||||
sgl_sdesc->addr);
|
||||
cxgb4_write_partial_sgl(skb, &q->q, pos, end, sgl_sdesc->addr,
|
||||
skb_offset, data_len);
|
||||
sgl_sdesc->skb = skb;
|
||||
|
||||
chcr_txq_advance(&q->q, ndesc);
|
||||
|
@ -1282,10 +1270,11 @@ static int chcr_ktls_xmit_wr_short(struct sk_buff *skb,
|
|||
struct sge_eth_txq *q,
|
||||
u32 tcp_seq, bool tcp_push, u32 mss,
|
||||
u32 tls_rec_offset, u8 *prior_data,
|
||||
u32 prior_data_len)
|
||||
u32 prior_data_len, u32 data_len,
|
||||
u32 skb_offset)
|
||||
{
|
||||
u32 len16, wr_mid = 0, cipher_start, nfrags;
|
||||
struct adapter *adap = tx_info->adap;
|
||||
u32 len16, wr_mid = 0, cipher_start;
|
||||
unsigned int flits = 0, ndesc;
|
||||
int credits, left, last_desc;
|
||||
struct tx_sw_desc *sgl_sdesc;
|
||||
|
@ -1298,10 +1287,11 @@ static int chcr_ktls_xmit_wr_short(struct sk_buff *skb,
|
|||
void *pos;
|
||||
u64 *end;
|
||||
|
||||
nfrags = chcr_get_nfrags_to_send(skb, skb_offset, data_len);
|
||||
/* get the number of flits required, it's a partial record so 2 flits
|
||||
* (AES_BLOCK_SIZE) will be added.
|
||||
*/
|
||||
flits = chcr_ktls_get_tx_flits(skb, tx_info->key_ctx_len) + 2;
|
||||
flits = chcr_ktls_get_tx_flits(nfrags, tx_info->key_ctx_len) + 2;
|
||||
/* get the correct 8 byte IV of this record */
|
||||
iv_record = cpu_to_be64(tx_info->iv + tx_info->record_no);
|
||||
/* If it's a middle record and not 16 byte aligned to run AES CTR, need
|
||||
|
@ -1373,7 +1363,7 @@ static int chcr_ktls_xmit_wr_short(struct sk_buff *skb,
|
|||
htonl(CPL_TX_SEC_PDU_OPCODE_V(CPL_TX_SEC_PDU) |
|
||||
CPL_TX_SEC_PDU_CPLLEN_V(CHCR_CPL_TX_SEC_PDU_LEN_64BIT) |
|
||||
CPL_TX_SEC_PDU_IVINSRTOFST_V(1));
|
||||
cpl->pldlen = htonl(skb->data_len + AES_BLOCK_LEN + prior_data_len);
|
||||
cpl->pldlen = htonl(data_len + AES_BLOCK_LEN + prior_data_len);
|
||||
cpl->aadstart_cipherstop_hi =
|
||||
htonl(CPL_TX_SEC_PDU_CIPHERSTART_V(cipher_start));
|
||||
cpl->cipherstop_lo_authinsert = 0;
|
||||
|
@ -1404,7 +1394,7 @@ static int chcr_ktls_xmit_wr_short(struct sk_buff *skb,
|
|||
tx_data = (void *)pos;
|
||||
OPCODE_TID(tx_data) = htonl(MK_OPCODE_TID(CPL_TX_DATA, tx_info->tid));
|
||||
tx_data->len = htonl(TX_DATA_MSS_V(mss) |
|
||||
TX_LENGTH_V(skb->data_len + prior_data_len));
|
||||
TX_LENGTH_V(data_len + prior_data_len));
|
||||
tx_data->rsvd = htonl(tcp_seq);
|
||||
tx_data->flags = htonl(TX_BYPASS_F);
|
||||
if (tcp_push)
|
||||
|
@ -1437,8 +1427,8 @@ static int chcr_ktls_xmit_wr_short(struct sk_buff *skb,
|
|||
if (prior_data_len)
|
||||
pos = chcr_copy_to_txd(prior_data, &q->q, pos, 16);
|
||||
/* send the complete packet except the header */
|
||||
cxgb4_write_sgl(skb, &q->q, pos, end, skb->len - skb->data_len,
|
||||
sgl_sdesc->addr);
|
||||
cxgb4_write_partial_sgl(skb, &q->q, pos, end, sgl_sdesc->addr,
|
||||
skb_offset, data_len);
|
||||
sgl_sdesc->skb = skb;
|
||||
|
||||
chcr_txq_advance(&q->q, ndesc);
|
||||
|
@ -1466,6 +1456,7 @@ static int chcr_ktls_tx_plaintxt(struct chcr_ktls_info *tx_info,
|
|||
struct sk_buff *skb, u32 tcp_seq, u32 mss,
|
||||
bool tcp_push, struct sge_eth_txq *q,
|
||||
u32 port_id, u8 *prior_data,
|
||||
u32 data_len, u32 skb_offset,
|
||||
u32 prior_data_len)
|
||||
{
|
||||
int credits, left, len16, last_desc;
|
||||
|
@ -1475,14 +1466,16 @@ static int chcr_ktls_tx_plaintxt(struct chcr_ktls_info *tx_info,
|
|||
struct ulptx_idata *idata;
|
||||
struct ulp_txpkt *ulptx;
|
||||
struct fw_ulptx_wr *wr;
|
||||
u32 wr_mid = 0;
|
||||
u32 wr_mid = 0, nfrags;
|
||||
void *pos;
|
||||
u64 *end;
|
||||
|
||||
flits = DIV_ROUND_UP(CHCR_PLAIN_TX_DATA_LEN, 8);
|
||||
flits += chcr_sgl_len(skb_shinfo(skb)->nr_frags);
|
||||
nfrags = chcr_get_nfrags_to_send(skb, skb_offset, data_len);
|
||||
flits += chcr_sgl_len(nfrags);
|
||||
if (prior_data_len)
|
||||
flits += 2;
|
||||
|
||||
/* WR will need len16 */
|
||||
len16 = DIV_ROUND_UP(flits, 2);
|
||||
/* check how many descriptors needed */
|
||||
|
@ -1535,7 +1528,7 @@ static int chcr_ktls_tx_plaintxt(struct chcr_ktls_info *tx_info,
|
|||
tx_data = (struct cpl_tx_data *)(idata + 1);
|
||||
OPCODE_TID(tx_data) = htonl(MK_OPCODE_TID(CPL_TX_DATA, tx_info->tid));
|
||||
tx_data->len = htonl(TX_DATA_MSS_V(mss) |
|
||||
TX_LENGTH_V(skb->data_len + prior_data_len));
|
||||
TX_LENGTH_V(data_len + prior_data_len));
|
||||
/* set tcp seq number */
|
||||
tx_data->rsvd = htonl(tcp_seq);
|
||||
tx_data->flags = htonl(TX_BYPASS_F);
|
||||
|
@ -1559,8 +1552,8 @@ static int chcr_ktls_tx_plaintxt(struct chcr_ktls_info *tx_info,
|
|||
end = pos + left;
|
||||
}
|
||||
/* send the complete packet including the header */
|
||||
cxgb4_write_sgl(skb, &q->q, pos, end, skb->len - skb->data_len,
|
||||
sgl_sdesc->addr);
|
||||
cxgb4_write_partial_sgl(skb, &q->q, pos, end, sgl_sdesc->addr,
|
||||
skb_offset, data_len);
|
||||
sgl_sdesc->skb = skb;
|
||||
|
||||
chcr_txq_advance(&q->q, ndesc);
|
||||
|
@ -1568,12 +1561,96 @@ static int chcr_ktls_tx_plaintxt(struct chcr_ktls_info *tx_info,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int chcr_ktls_tunnel_pkt(struct chcr_ktls_info *tx_info,
|
||||
struct sk_buff *skb,
|
||||
struct sge_eth_txq *q)
|
||||
{
|
||||
u32 ctrl, iplen, maclen, wr_mid = 0, len16;
|
||||
struct tx_sw_desc *sgl_sdesc;
|
||||
struct fw_eth_tx_pkt_wr *wr;
|
||||
struct cpl_tx_pkt_core *cpl;
|
||||
unsigned int flits, ndesc;
|
||||
int credits, last_desc;
|
||||
u64 cntrl1, *end;
|
||||
void *pos;
|
||||
|
||||
ctrl = sizeof(*cpl);
|
||||
flits = DIV_ROUND_UP(sizeof(*wr) + ctrl, 8);
|
||||
|
||||
flits += chcr_sgl_len(skb_shinfo(skb)->nr_frags + 1);
|
||||
len16 = DIV_ROUND_UP(flits, 2);
|
||||
/* check how many descriptors needed */
|
||||
ndesc = DIV_ROUND_UP(flits, 8);
|
||||
|
||||
credits = chcr_txq_avail(&q->q) - ndesc;
|
||||
if (unlikely(credits < 0)) {
|
||||
chcr_eth_txq_stop(q);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (unlikely(credits < ETHTXQ_STOP_THRES)) {
|
||||
chcr_eth_txq_stop(q);
|
||||
wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
|
||||
}
|
||||
|
||||
last_desc = q->q.pidx + ndesc - 1;
|
||||
if (last_desc >= q->q.size)
|
||||
last_desc -= q->q.size;
|
||||
sgl_sdesc = &q->q.sdesc[last_desc];
|
||||
|
||||
if (unlikely(cxgb4_map_skb(tx_info->adap->pdev_dev, skb,
|
||||
sgl_sdesc->addr) < 0)) {
|
||||
memset(sgl_sdesc->addr, 0, sizeof(sgl_sdesc->addr));
|
||||
q->mapping_err++;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
iplen = skb_network_header_len(skb);
|
||||
maclen = skb_mac_header_len(skb);
|
||||
|
||||
pos = &q->q.desc[q->q.pidx];
|
||||
end = (u64 *)pos + flits;
|
||||
wr = pos;
|
||||
|
||||
/* Firmware work request header */
|
||||
wr->op_immdlen = htonl(FW_WR_OP_V(FW_ETH_TX_PKT_WR) |
|
||||
FW_WR_IMMDLEN_V(ctrl));
|
||||
|
||||
wr->equiq_to_len16 = htonl(wr_mid | FW_WR_LEN16_V(len16));
|
||||
wr->r3 = 0;
|
||||
|
||||
cpl = (void *)(wr + 1);
|
||||
|
||||
/* CPL header */
|
||||
cpl->ctrl0 = htonl(TXPKT_OPCODE_V(CPL_TX_PKT) |
|
||||
TXPKT_INTF_V(tx_info->tx_chan) |
|
||||
TXPKT_PF_V(tx_info->adap->pf));
|
||||
cpl->pack = 0;
|
||||
cntrl1 = TXPKT_CSUM_TYPE_V(tx_info->ip_family == AF_INET ?
|
||||
TX_CSUM_TCPIP : TX_CSUM_TCPIP6);
|
||||
cntrl1 |= T6_TXPKT_ETHHDR_LEN_V(maclen - ETH_HLEN) |
|
||||
TXPKT_IPHDR_LEN_V(iplen);
|
||||
/* checksum offload */
|
||||
cpl->ctrl1 = cpu_to_be64(cntrl1);
|
||||
cpl->len = htons(skb->len);
|
||||
|
||||
pos = cpl + 1;
|
||||
|
||||
cxgb4_write_sgl(skb, &q->q, pos, end, 0, sgl_sdesc->addr);
|
||||
sgl_sdesc->skb = skb;
|
||||
chcr_txq_advance(&q->q, ndesc);
|
||||
cxgb4_ring_tx_db(tx_info->adap, &q->q, ndesc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* chcr_ktls_copy_record_in_skb
|
||||
* @nskb - new skb where the frags to be added.
|
||||
* @skb - old skb, to copy socket and destructor details.
|
||||
* @record - specific record which has complete 16k record in frags.
|
||||
*/
|
||||
static void chcr_ktls_copy_record_in_skb(struct sk_buff *nskb,
|
||||
struct sk_buff *skb,
|
||||
struct tls_record_info *record)
|
||||
{
|
||||
int i = 0;
|
||||
|
@ -1588,6 +1665,9 @@ static void chcr_ktls_copy_record_in_skb(struct sk_buff *nskb,
|
|||
nskb->data_len = record->len;
|
||||
nskb->len += record->len;
|
||||
nskb->truesize += record->len;
|
||||
nskb->sk = skb->sk;
|
||||
nskb->destructor = skb->destructor;
|
||||
refcount_add(nskb->truesize, &nskb->sk->sk_wmem_alloc);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1659,7 +1739,7 @@ static int chcr_end_part_handler(struct chcr_ktls_info *tx_info,
|
|||
struct sk_buff *skb,
|
||||
struct tls_record_info *record,
|
||||
u32 tcp_seq, int mss, bool tcp_push_no_fin,
|
||||
struct sge_eth_txq *q,
|
||||
struct sge_eth_txq *q, u32 skb_offset,
|
||||
u32 tls_end_offset, bool last_wr)
|
||||
{
|
||||
struct sk_buff *nskb = NULL;
|
||||
|
@ -1668,30 +1748,37 @@ static int chcr_end_part_handler(struct chcr_ktls_info *tx_info,
|
|||
nskb = skb;
|
||||
atomic64_inc(&tx_info->adap->ch_ktls_stats.ktls_tx_complete_pkts);
|
||||
} else {
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
nskb = alloc_skb(0, GFP_KERNEL);
|
||||
if (!nskb)
|
||||
nskb = alloc_skb(0, GFP_ATOMIC);
|
||||
if (!nskb) {
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
/* copy complete record in skb */
|
||||
chcr_ktls_copy_record_in_skb(nskb, record);
|
||||
chcr_ktls_copy_record_in_skb(nskb, skb, record);
|
||||
/* packet is being sent from the beginning, update the tcp_seq
|
||||
* accordingly.
|
||||
*/
|
||||
tcp_seq = tls_record_start_seq(record);
|
||||
/* reset snd una, so the middle record won't send the already
|
||||
* sent part.
|
||||
*/
|
||||
if (chcr_ktls_update_snd_una(tx_info, q))
|
||||
goto out;
|
||||
/* reset skb offset */
|
||||
skb_offset = 0;
|
||||
|
||||
if (last_wr)
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
last_wr = true;
|
||||
|
||||
atomic64_inc(&tx_info->adap->ch_ktls_stats.ktls_tx_end_pkts);
|
||||
}
|
||||
|
||||
if (chcr_ktls_xmit_wr_complete(nskb, tx_info, q, tcp_seq,
|
||||
last_wr, record->len, skb_offset,
|
||||
record->num_frags,
|
||||
(last_wr && tcp_push_no_fin),
|
||||
mss)) {
|
||||
goto out;
|
||||
}
|
||||
tx_info->prev_seq = record->end_seq;
|
||||
return 0;
|
||||
out:
|
||||
dev_kfree_skb_any(nskb);
|
||||
|
@ -1723,41 +1810,47 @@ static int chcr_short_record_handler(struct chcr_ktls_info *tx_info,
|
|||
struct sk_buff *skb,
|
||||
struct tls_record_info *record,
|
||||
u32 tcp_seq, int mss, bool tcp_push_no_fin,
|
||||
u32 data_len, u32 skb_offset,
|
||||
struct sge_eth_txq *q, u32 tls_end_offset)
|
||||
{
|
||||
u32 tls_rec_offset = tcp_seq - tls_record_start_seq(record);
|
||||
u8 prior_data[16] = {0};
|
||||
u32 prior_data_len = 0;
|
||||
u32 data_len;
|
||||
|
||||
/* check if the skb is ending in middle of tag/HASH, its a big
|
||||
* trouble, send the packet before the HASH.
|
||||
*/
|
||||
int remaining_record = tls_end_offset - skb->data_len;
|
||||
int remaining_record = tls_end_offset - data_len;
|
||||
|
||||
if (remaining_record > 0 &&
|
||||
remaining_record < TLS_CIPHER_AES_GCM_128_TAG_SIZE) {
|
||||
int trimmed_len = skb->data_len -
|
||||
(TLS_CIPHER_AES_GCM_128_TAG_SIZE - remaining_record);
|
||||
struct sk_buff *tmp_skb = NULL;
|
||||
/* don't process the pkt if it is only a partial tag */
|
||||
if (skb->data_len < TLS_CIPHER_AES_GCM_128_TAG_SIZE)
|
||||
goto out;
|
||||
int trimmed_len = 0;
|
||||
|
||||
WARN_ON(trimmed_len > skb->data_len);
|
||||
if (tls_end_offset > TLS_CIPHER_AES_GCM_128_TAG_SIZE)
|
||||
trimmed_len = data_len -
|
||||
(TLS_CIPHER_AES_GCM_128_TAG_SIZE -
|
||||
remaining_record);
|
||||
if (!trimmed_len)
|
||||
return FALLBACK;
|
||||
|
||||
/* shift to those many bytes */
|
||||
tmp_skb = alloc_skb(0, GFP_KERNEL);
|
||||
if (unlikely(!tmp_skb))
|
||||
goto out;
|
||||
WARN_ON(trimmed_len > data_len);
|
||||
|
||||
chcr_ktls_skb_shift(tmp_skb, skb, trimmed_len);
|
||||
/* free the last trimmed portion */
|
||||
dev_kfree_skb_any(skb);
|
||||
skb = tmp_skb;
|
||||
data_len = trimmed_len;
|
||||
atomic64_inc(&tx_info->adap->ch_ktls_stats.ktls_tx_trimmed_pkts);
|
||||
}
|
||||
data_len = skb->data_len;
|
||||
|
||||
/* check if it is only the header part. */
|
||||
if (tls_rec_offset + data_len <= (TLS_HEADER_SIZE + tx_info->iv_size)) {
|
||||
if (chcr_ktls_tx_plaintxt(tx_info, skb, tcp_seq, mss,
|
||||
tcp_push_no_fin, q,
|
||||
tx_info->port_id, prior_data,
|
||||
data_len, skb_offset, prior_data_len))
|
||||
goto out;
|
||||
|
||||
tx_info->prev_seq = tcp_seq + data_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check if the middle record's start point is 16 byte aligned. CTR
|
||||
* needs 16 byte aligned start point to start encryption.
|
||||
*/
|
||||
|
@ -1818,9 +1911,6 @@ static int chcr_short_record_handler(struct chcr_ktls_info *tx_info,
|
|||
}
|
||||
/* reset tcp_seq as per the prior_data_required len */
|
||||
tcp_seq -= prior_data_len;
|
||||
/* include prio_data_len for further calculation.
|
||||
*/
|
||||
data_len += prior_data_len;
|
||||
}
|
||||
/* reset snd una, so the middle record won't send the already
|
||||
* sent part.
|
||||
|
@ -1829,37 +1919,54 @@ static int chcr_short_record_handler(struct chcr_ktls_info *tx_info,
|
|||
goto out;
|
||||
atomic64_inc(&tx_info->adap->ch_ktls_stats.ktls_tx_middle_pkts);
|
||||
} else {
|
||||
/* Else means, its a partial first part of the record. Check if
|
||||
* its only the header, don't need to send for encryption then.
|
||||
*/
|
||||
if (data_len <= TLS_HEADER_SIZE + tx_info->iv_size) {
|
||||
if (chcr_ktls_tx_plaintxt(tx_info, skb, tcp_seq, mss,
|
||||
tcp_push_no_fin, q,
|
||||
tx_info->port_id,
|
||||
prior_data,
|
||||
prior_data_len)) {
|
||||
goto out;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
atomic64_inc(&tx_info->adap->ch_ktls_stats.ktls_tx_start_pkts);
|
||||
}
|
||||
|
||||
if (chcr_ktls_xmit_wr_short(skb, tx_info, q, tcp_seq, tcp_push_no_fin,
|
||||
mss, tls_rec_offset, prior_data,
|
||||
prior_data_len)) {
|
||||
prior_data_len, data_len, skb_offset)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
tx_info->prev_seq = tcp_seq + data_len + prior_data_len;
|
||||
return 0;
|
||||
out:
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
static int chcr_ktls_sw_fallback(struct sk_buff *skb,
|
||||
struct chcr_ktls_info *tx_info,
|
||||
struct sge_eth_txq *q)
|
||||
{
|
||||
u32 data_len, skb_offset;
|
||||
struct sk_buff *nskb;
|
||||
struct tcphdr *th;
|
||||
|
||||
nskb = tls_encrypt_skb(skb);
|
||||
|
||||
if (!nskb)
|
||||
return 0;
|
||||
|
||||
th = tcp_hdr(nskb);
|
||||
skb_offset = skb_transport_offset(nskb) + tcp_hdrlen(nskb);
|
||||
data_len = nskb->len - skb_offset;
|
||||
skb_tx_timestamp(nskb);
|
||||
|
||||
if (chcr_ktls_tunnel_pkt(tx_info, nskb, q))
|
||||
goto out;
|
||||
|
||||
tx_info->prev_seq = ntohl(th->seq) + data_len;
|
||||
atomic64_inc(&tx_info->adap->ch_ktls_stats.ktls_tx_fallback);
|
||||
return 0;
|
||||
out:
|
||||
dev_kfree_skb_any(nskb);
|
||||
return 0;
|
||||
}
|
||||
/* nic tls TX handler */
|
||||
static int chcr_ktls_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
u32 tls_end_offset, tcp_seq, skb_data_len, skb_offset;
|
||||
struct ch_ktls_port_stats_debug *port_stats;
|
||||
struct chcr_ktls_ofld_ctx_tx *tx_ctx;
|
||||
struct ch_ktls_stats_debug *stats;
|
||||
|
@ -1867,20 +1974,17 @@ static int chcr_ktls_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
int data_len, qidx, ret = 0, mss;
|
||||
struct tls_record_info *record;
|
||||
struct chcr_ktls_info *tx_info;
|
||||
u32 tls_end_offset, tcp_seq;
|
||||
struct tls_context *tls_ctx;
|
||||
struct sk_buff *local_skb;
|
||||
struct sge_eth_txq *q;
|
||||
struct adapter *adap;
|
||||
unsigned long flags;
|
||||
|
||||
tcp_seq = ntohl(th->seq);
|
||||
skb_offset = skb_transport_offset(skb) + tcp_hdrlen(skb);
|
||||
skb_data_len = skb->len - skb_offset;
|
||||
data_len = skb_data_len;
|
||||
|
||||
mss = skb_is_gso(skb) ? skb_shinfo(skb)->gso_size : skb->data_len;
|
||||
|
||||
/* check if we haven't set it for ktls offload */
|
||||
if (!skb->sk || !tls_is_sk_tx_device_offloaded(skb->sk))
|
||||
goto out;
|
||||
mss = skb_is_gso(skb) ? skb_shinfo(skb)->gso_size : data_len;
|
||||
|
||||
tls_ctx = tls_get_ctx(skb->sk);
|
||||
if (unlikely(tls_ctx->netdev != dev))
|
||||
|
@ -1892,14 +1996,6 @@ static int chcr_ktls_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
if (unlikely(!tx_info))
|
||||
goto out;
|
||||
|
||||
/* don't touch the original skb, make a new skb to extract each records
|
||||
* and send them separately.
|
||||
*/
|
||||
local_skb = alloc_skb(0, GFP_KERNEL);
|
||||
|
||||
if (unlikely(!local_skb))
|
||||
return NETDEV_TX_BUSY;
|
||||
|
||||
adap = tx_info->adap;
|
||||
stats = &adap->ch_ktls_stats;
|
||||
port_stats = &stats->ktls_port[tx_info->port_id];
|
||||
|
@ -1914,20 +2010,7 @@ static int chcr_ktls_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
if (ret)
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
/* update tcb */
|
||||
ret = chcr_ktls_xmit_tcb_cpls(tx_info, q, ntohl(th->seq),
|
||||
ntohl(th->ack_seq),
|
||||
ntohs(th->window));
|
||||
if (ret) {
|
||||
dev_kfree_skb_any(local_skb);
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
/* copy skb contents into local skb */
|
||||
chcr_ktls_skb_copy(skb, local_skb);
|
||||
|
||||
/* go through the skb and send only one record at a time. */
|
||||
data_len = skb->data_len;
|
||||
/* TCP segments can be in received either complete or partial.
|
||||
* chcr_end_part_handler will handle cases if complete record or end
|
||||
* part of the record is received. Incase of partial end part of record,
|
||||
|
@ -1952,10 +2035,64 @@ static int chcr_ktls_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
goto out;
|
||||
}
|
||||
|
||||
tls_end_offset = record->end_seq - tcp_seq;
|
||||
|
||||
pr_debug("seq 0x%x, end_seq 0x%x prev_seq 0x%x, datalen 0x%x\n",
|
||||
tcp_seq, record->end_seq, tx_info->prev_seq, data_len);
|
||||
/* update tcb for the skb */
|
||||
if (skb_data_len == data_len) {
|
||||
u32 tx_max = tcp_seq;
|
||||
|
||||
if (!tls_record_is_start_marker(record) &&
|
||||
tls_end_offset < TLS_CIPHER_AES_GCM_128_TAG_SIZE)
|
||||
tx_max = record->end_seq -
|
||||
TLS_CIPHER_AES_GCM_128_TAG_SIZE;
|
||||
|
||||
ret = chcr_ktls_xmit_tcb_cpls(tx_info, q, tx_max,
|
||||
ntohl(th->ack_seq),
|
||||
ntohs(th->window),
|
||||
tls_end_offset !=
|
||||
record->len);
|
||||
if (ret) {
|
||||
spin_unlock_irqrestore(&tx_ctx->base.lock,
|
||||
flags);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (th->fin)
|
||||
skb_get(skb);
|
||||
}
|
||||
|
||||
if (unlikely(tls_record_is_start_marker(record))) {
|
||||
spin_unlock_irqrestore(&tx_ctx->base.lock, flags);
|
||||
atomic64_inc(&port_stats->ktls_tx_skip_no_sync_data);
|
||||
goto out;
|
||||
/* If tls_end_offset < data_len, means there is some
|
||||
* data after start marker, which needs encryption, send
|
||||
* plaintext first and take skb refcount. else send out
|
||||
* complete pkt as plaintext.
|
||||
*/
|
||||
if (tls_end_offset < data_len)
|
||||
skb_get(skb);
|
||||
else
|
||||
tls_end_offset = data_len;
|
||||
|
||||
ret = chcr_ktls_tx_plaintxt(tx_info, skb, tcp_seq, mss,
|
||||
(!th->fin && th->psh), q,
|
||||
tx_info->port_id, NULL,
|
||||
tls_end_offset, skb_offset,
|
||||
0);
|
||||
|
||||
spin_unlock_irqrestore(&tx_ctx->base.lock, flags);
|
||||
if (ret) {
|
||||
/* free the refcount taken earlier */
|
||||
if (tls_end_offset < data_len)
|
||||
dev_kfree_skb_any(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
data_len -= tls_end_offset;
|
||||
tcp_seq = record->end_seq;
|
||||
skb_offset += tls_end_offset;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* increase page reference count of the record, so that there
|
||||
|
@ -1967,73 +2104,64 @@ static int chcr_ktls_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
/* lock cleared */
|
||||
spin_unlock_irqrestore(&tx_ctx->base.lock, flags);
|
||||
|
||||
tls_end_offset = record->end_seq - tcp_seq;
|
||||
|
||||
pr_debug("seq 0x%x, end_seq 0x%x prev_seq 0x%x, datalen 0x%x\n",
|
||||
tcp_seq, record->end_seq, tx_info->prev_seq, data_len);
|
||||
/* if a tls record is finishing in this SKB */
|
||||
if (tls_end_offset <= data_len) {
|
||||
struct sk_buff *nskb = NULL;
|
||||
|
||||
if (tls_end_offset < data_len) {
|
||||
nskb = alloc_skb(0, GFP_KERNEL);
|
||||
if (unlikely(!nskb)) {
|
||||
ret = -ENOMEM;
|
||||
goto clear_ref;
|
||||
}
|
||||
|
||||
chcr_ktls_skb_shift(nskb, local_skb,
|
||||
tls_end_offset);
|
||||
} else {
|
||||
/* its the only record in this skb, directly
|
||||
* point it.
|
||||
*/
|
||||
nskb = local_skb;
|
||||
}
|
||||
ret = chcr_end_part_handler(tx_info, nskb, record,
|
||||
ret = chcr_end_part_handler(tx_info, skb, record,
|
||||
tcp_seq, mss,
|
||||
(!th->fin && th->psh), q,
|
||||
skb_offset,
|
||||
tls_end_offset,
|
||||
(nskb == local_skb));
|
||||
|
||||
if (ret && nskb != local_skb)
|
||||
dev_kfree_skb_any(local_skb);
|
||||
skb_offset +
|
||||
tls_end_offset == skb->len);
|
||||
|
||||
data_len -= tls_end_offset;
|
||||
/* tcp_seq increment is required to handle next record.
|
||||
*/
|
||||
tcp_seq += tls_end_offset;
|
||||
skb_offset += tls_end_offset;
|
||||
} else {
|
||||
ret = chcr_short_record_handler(tx_info, local_skb,
|
||||
ret = chcr_short_record_handler(tx_info, skb,
|
||||
record, tcp_seq, mss,
|
||||
(!th->fin && th->psh),
|
||||
data_len, skb_offset,
|
||||
q, tls_end_offset);
|
||||
data_len = 0;
|
||||
}
|
||||
clear_ref:
|
||||
|
||||
/* clear the frag ref count which increased locally before */
|
||||
for (i = 0; i < record->num_frags; i++) {
|
||||
/* clear the frag ref count */
|
||||
__skb_frag_unref(&record->frags[i]);
|
||||
}
|
||||
/* if any failure, come out from the loop. */
|
||||
if (ret)
|
||||
goto out;
|
||||
if (ret) {
|
||||
if (th->fin)
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
if (ret == FALLBACK)
|
||||
return chcr_ktls_sw_fallback(skb, tx_info, q);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
/* length should never be less than 0 */
|
||||
WARN_ON(data_len < 0);
|
||||
|
||||
} while (data_len > 0);
|
||||
|
||||
tx_info->prev_seq = ntohl(th->seq) + skb->data_len;
|
||||
atomic64_inc(&port_stats->ktls_tx_encrypted_packets);
|
||||
atomic64_add(skb->data_len, &port_stats->ktls_tx_encrypted_bytes);
|
||||
atomic64_add(skb_data_len, &port_stats->ktls_tx_encrypted_bytes);
|
||||
|
||||
/* tcp finish is set, send a separate tcp msg including all the options
|
||||
* as well.
|
||||
*/
|
||||
if (th->fin)
|
||||
if (th->fin) {
|
||||
chcr_ktls_write_tcp_options(tx_info, skb, q, tx_info->tx_chan);
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
out:
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#define CHCR_KTLS_WR_SIZE (CHCR_PLAIN_TX_DATA_LEN +\
|
||||
sizeof(struct cpl_tx_sec_pdu))
|
||||
#define FALLBACK 35
|
||||
|
||||
enum ch_ktls_open_state {
|
||||
CH_KTLS_OPEN_SUCCESS = 0,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue