* Re: [PATCH v8 3/5] mtd: Add support for HyperBus memory devices
From: Vignesh Raghavendra @ 2019-07-12 4:52 UTC (permalink / raw)
To: Sergei Shtylyov, Boris Brezillon, Marek Vasut, Richard Weinberger,
Rob Herring
Cc: devicetree, Tokunori Ikegami, linux-kernel, linux-mtd,
Miquel Raynal, Mason Yang, linux-arm-kernel
In-Reply-To: <e5a7866d-bc34-887d-31d3-de4f745c8d65@cogentembedded.com>
On 12/07/19 12:56 AM, Sergei Shtylyov wrote:
> Hello!
>
> On 06/25/2019 10:57 AM, Vignesh Raghavendra wrote:
>
>> Cypress' HyperBus is Low Signal Count, High Performance Double Data Rate
>> Bus interface between a host system master and one or more slave
>> interfaces. HyperBus is used to connect microprocessor, microcontroller,
>> or ASIC devices with random access NOR flash memory (called HyperFlash)
>> or self refresh DRAM (called HyperRAM).
>>
>> Its a 8-bit data bus (DQ[7:0]) with Read-Write Data Strobe (RWDS)
>> signal and either Single-ended clock(3.0V parts) or Differential clock
>> (1.8V parts). It uses ChipSelect lines to select b/w multiple slaves.
>> At bus level, it follows a separate protocol described in HyperBus
>> specification[1].
>>
>> HyperFlash follows CFI AMD/Fujitsu Extended Command Set (0x0002) similar
>> to that of existing parallel NORs. Since HyperBus is x8 DDR bus,
>> its equivalent to x16 parallel NOR flash with respect to bits per clock
>> cycle. But HyperBus operates at >166MHz frequencies.
>> HyperRAM provides direct random read/write access to flash memory
>> array.
>>
>> But, HyperBus memory controllers seem to abstract implementation details
>> and expose a simple MMIO interface to access connected flash.
>>
>> Add support for registering HyperFlash devices with MTD framework. MTD
>> maps framework along with CFI chip support framework are used to support
>> communicating with flash.
>>
>> Framework is modelled along the lines of spi-nor framework. HyperBus
>> memory controller (HBMC) drivers calls hyperbus_register_device() to
>> register a single HyperFlash device. HyperFlash core parses MMIO access
>> information from DT, sets up the map_info struct, probes CFI flash and
>> registers it with MTD framework.
>>
>> Some HBMC masters need calibration/training sequence[3] to be carried
>> out, in order for DLL inside the controller to lock, by reading a known
>> string/pattern. This is done by repeatedly reading CFI Query
>> Identification String. Calibration needs to be done before trying to detect
>> flash as part of CFI flash probe.
>>
>> HyperRAM is not supported at the moment.
>>
>> HyperBus specification can be found at[1]
>> HyperFlash datasheet can be found at[2]
>>
>> [1] https://www.cypress.com/file/213356/download
>> [2] https://www.cypress.com/file/213346/download
>> [3] http://www.ti.com/lit/ug/spruid7b/spruid7b.pdf
>> Table 12-5741. HyperFlash Access Sequence
>>
>> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
> [...]
>
>> diff --git a/drivers/mtd/hyperbus/hyperbus-core.c b/drivers/mtd/hyperbus/hyperbus-core.c
>> new file mode 100644
>> index 000000000000..63a9e64895bc
>> --- /dev/null
>> +++ b/drivers/mtd/hyperbus/hyperbus-core.c
>> @@ -0,0 +1,154 @@
> [...]
>> +int hyperbus_register_device(struct hyperbus_device *hbdev)
>> +{
> [...]
>> + map->name = dev_name(dev);
>> + map->bankwidth = 2;
>
> I think this should really be 1, judging on the comment to that field (and on
> Cogent's own RPC-IF HF driver).
>
I agree this setting is a bit confusing because DDR nature. What we have
with HyperFlash in DDR mode is equivalent to 16bit flash on a 8bit bus
and kind of equal to 2 bus cycles (in this case clock edges), therefore
bandwidth would turn out to be 2. Otherwise cfi_build_cmd() would
generate wrong addresses and simple map implmention of read/writes would
use wrong accessors.
Only way I see map->bankwidth = 1 working is if HF is used in SDR mode.
So is Cogent's HF in SDR mode? I thought HyperFlash is DDR only but I
may be wrong.
>> + map->device_node = np;
>
> [...]
>
> MBR, Sergei
>
--
Regards
Vignesh
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply
* Re: [PATCH 00/12] remoteproc: qcom: q6v5-wcss: Add support for secure pil
From: gokulsri @ 2019-07-12 5:43 UTC (permalink / raw)
To: agross, david.brown, robh+dt, mark.rutland, mturquette, sboyd,
jassisinghbrar, ohad, bjorn.andersson, linux-arm-msm, devicetree,
linux-kernel, linux-clk, linux-remoteproc, sricharan, gokulsri,
sjaganat, nprakash
In-Reply-To: <1562859668-14209-1-git-send-email-gokulsri@codeaurora.org>
Hi,
On 2019-07-11 21:10, Gokul Sriram Palanisamy wrote:
> IPQ8074 needs support for secure pil as well.
> Also, currently only unified firmware is supported.
> IPQ8074 supports split firmware for q6 and m3, so
> adding support for that.
>
> Gokul Sriram Palanisamy (12):
> remoteproc: qcom: Add PRNG proxy clock
> remoteproc: qcom: Add secure PIL support
> remoteproc: qcom: Add support for split q6 + m3 wlan firmware
> remoteproc: qcom: Add ssr subdevice identifier
> remoteproc: qcom: Update regmap offsets for halt register
> dt-bindings: clock: qcom: Add reset for WCSSAON
> clk: qcom: Add WCSSAON reset
> dt-bindings: mailbox: qom: Add ipq8074 APPS compatible
> mailbox: qcom: Add support for IPQ8074 APCS
> dt-bindings: firmware: qcom: Add compatible for IPQ8074 SoC
> arm64: dts: Add support for scm on IPQ8074 SoCs
> arm64: dts: qcom: Enable Q6v5 WCSS for ipq8074 SoC
>
Also, this series is based on Govind’s,
“[v4] Add non PAS wcss Q6 support for QCS404”
https://www.spinics.net/lists/linux-remoteproc/msg03612.html
Regards,
Gokul
> .../devicetree/bindings/firmware/qcom,scm.txt | 1 +
> .../bindings/mailbox/qcom,apcs-kpss-global.txt | 1 +
> arch/arm64/boot/dts/qcom/ipq8074.dtsi | 131
> +++++++++++++++++
> drivers/clk/qcom/gcc-ipq8074.c | 1 +
> drivers/mailbox/qcom-apcs-ipc-mailbox.c | 1 +
> drivers/remoteproc/qcom_q6v5_wcss.c | 158
> +++++++++++++++++----
> include/dt-bindings/clock/qcom,gcc-ipq8074.h | 1 +
> 7 files changed, 264 insertions(+), 30 deletions(-)
^ permalink raw reply
* [PATCH] dt-bindings: pinctrl: aspeed: Strip unnecessary quotes
From: Andrew Jeffery @ 2019-07-12 6:17 UTC (permalink / raw)
To: linux-gpio
Cc: mark.rutland, devicetree, linux-aspeed, Andrew Jeffery,
linus.walleij, linux-kernel, robh+dt, joel, linux-arm-kernel
Rob pointed out that we didn't need the noise of the quotes in a
separate review[1], so strip them out for consistency and avoid setting
a bad example.
[1] https://lists.ozlabs.org/pipermail/linux-aspeed/2019-July/002009.html
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
---
This patch applies to the tip of pinctrl/devel where the aspeed pinctrl binding
conversion patches have already landed.
.../pinctrl/aspeed,ast2400-pinctrl.yaml | 40 ++++++++---------
.../pinctrl/aspeed,ast2500-pinctrl.yaml | 45 +++++++++----------
2 files changed, 38 insertions(+), 47 deletions(-)
diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml
index 61a110a7db8a..faedfed0769c 100644
--- a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml
@@ -33,28 +33,24 @@ patternProperties:
"^function|groups$":
allOf:
- $ref: "/schemas/types.yaml#/definitions/string"
- - enum: [ "ACPI", "ADC0", "ADC1", "ADC10", "ADC11", "ADC12", "ADC13",
- "ADC14", "ADC15", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC7",
- "ADC8", "ADC9", "BMCINT", "DDCCLK", "DDCDAT", "EXTRST", "FLACK",
- "FLBUSY", "FLWP", "GPID", "GPID0", "GPID2", "GPID4", "GPID6",
- "GPIE0", "GPIE2", "GPIE4", "GPIE6", "I2C10", "I2C11", "I2C12",
- "I2C13", "I2C14", "I2C3", "I2C4", "I2C5", "I2C6", "I2C7", "I2C8",
- "I2C9", "LPCPD", "LPCPME", "LPCRST", "LPCSMI", "MAC1LINK",
- "MAC2LINK", "MDIO1", "MDIO2", "NCTS1", "NCTS2", "NCTS3", "NCTS4",
- "NDCD1", "NDCD2", "NDCD3", "NDCD4", "NDSR1", "NDSR2", "NDSR3",
- "NDSR4", "NDTR1", "NDTR2", "NDTR3", "NDTR4", "NDTS4", "NRI1",
- "NRI2", "NRI3", "NRI4", "NRTS1", "NRTS2", "NRTS3", "OSCCLK",
- "PWM0", "PWM1", "PWM2", "PWM3", "PWM4", "PWM5", "PWM6", "PWM7",
- "RGMII1", "RGMII2", "RMII1", "RMII2", "ROM16", "ROM8", "ROMCS1",
- "ROMCS2", "ROMCS3", "ROMCS4", "RXD1", "RXD2", "RXD3", "RXD4",
- "SALT1", "SALT2", "SALT3", "SALT4", "SD1", "SD2", "SGPMCK",
- "SGPMI", "SGPMLD", "SGPMO", "SGPSCK", "SGPSI0", "SGPSI1", "SGPSLD",
- "SIOONCTRL", "SIOPBI", "SIOPBO", "SIOPWREQ", "SIOPWRGD", "SIOS3",
- "SIOS5", "SIOSCI", "SPI1", "SPI1DEBUG", "SPI1PASSTHRU", "SPICS1",
- "TIMER3", "TIMER4", "TIMER5", "TIMER6", "TIMER7", "TIMER8", "TXD1",
- "TXD2", "TXD3", "TXD4", "UART6", "USB11D1", "USB11H2", "USB2D1",
- "USB2H1", "USBCKI", "VGABIOS_ROM", "VGAHS", "VGAVS", "VPI18",
- "VPI24", "VPI30", "VPO12", "VPO24", "WDTRST1", "WDTRST2" ]
+ - enum: [ ACPI, ADC0, ADC1, ADC10, ADC11, ADC12, ADC13, ADC14,
+ ADC15, ADC2, ADC3, ADC4, ADC5, ADC6, ADC7, ADC8, ADC9, BMCINT,
+ DDCCLK, DDCDAT, EXTRST, FLACK, FLBUSY, FLWP, GPID, GPID0, GPID2,
+ GPID4, GPID6, GPIE0, GPIE2, GPIE4, GPIE6, I2C10, I2C11, I2C12,
+ I2C13, I2C14, I2C3, I2C4, I2C5, I2C6, I2C7, I2C8, I2C9, LPCPD,
+ LPCPME, LPCRST, LPCSMI, MAC1LINK, MAC2LINK, MDIO1, MDIO2, NCTS1,
+ NCTS2, NCTS3, NCTS4, NDCD1, NDCD2, NDCD3, NDCD4, NDSR1, NDSR2,
+ NDSR3, NDSR4, NDTR1, NDTR2, NDTR3, NDTR4, NDTS4, NRI1, NRI2,
+ NRI3, NRI4, NRTS1, NRTS2, NRTS3, OSCCLK, PWM0, PWM1, PWM2, PWM3,
+ PWM4, PWM5, PWM6, PWM7, RGMII1, RGMII2, RMII1, RMII2, ROM16,
+ ROM8, ROMCS1, ROMCS2, ROMCS3, ROMCS4, RXD1, RXD2, RXD3, RXD4,
+ SALT1, SALT2, SALT3, SALT4, SD1, SD2, SGPMCK, SGPMI, SGPMLD,
+ SGPMO, SGPSCK, SGPSI0, SGPSI1, SGPSLD, SIOONCTRL, SIOPBI, SIOPBO,
+ SIOPWREQ, SIOPWRGD, SIOS3, SIOS5, SIOSCI, SPI1, SPI1DEBUG,
+ SPI1PASSTHRU, SPICS1, TIMER3, TIMER4, TIMER5, TIMER6, TIMER7,
+ TIMER8, TXD1, TXD2, TXD3, TXD4, UART6, USB11D1, USB11H2, USB2D1,
+ USB2H1, USBCKI, VGABIOS_ROM, VGAHS, VGAVS, VPI18, VPI24, VPI30,
+ VPO12, VPO24, WDTRST1, WDTRST2 ]
required:
- compatible
diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml
index cf561bd55128..d1984f619b74 100644
--- a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml
@@ -42,31 +42,26 @@ patternProperties:
"^function|groups$":
allOf:
- $ref: "/schemas/types.yaml#/definitions/string"
- - enum: [ "ACPI", "ADC0", "ADC1", "ADC10", "ADC11", "ADC12", "ADC13",
- "ADC14", "ADC15", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC7",
- "ADC8", "ADC9", "BMCINT", "DDCCLK", "DDCDAT", "ESPI", "FWSPICS1",
- "FWSPICS2", "GPID0", "GPID2", "GPID4", "GPID6", "GPIE0", "GPIE2",
- "GPIE4", "GPIE6", "I2C10", "I2C11", "I2C12", "I2C13", "I2C14",
- "I2C3", "I2C4", "I2C5", "I2C6", "I2C7", "I2C8", "I2C9", "LAD0",
- "LAD1", "LAD2", "LAD3", "LCLK", "LFRAME", "LPCHC", "LPCPD",
- "LPCPLUS", "LPCPME", "LPCRST", "LPCSMI", "LSIRQ", "MAC1LINK",
- "MAC2LINK", "MDIO1", "MDIO2", "NCTS1", "NCTS2", "NCTS3", "NCTS4",
- "NDCD1", "NDCD2", "NDCD3", "NDCD4", "NDSR1", "NDSR2", "NDSR3",
- "NDSR4", "NDTR1", "NDTR2", "NDTR3", "NDTR4", "NRI1", "NRI2",
- "NRI3", "NRI4", "NRTS1", "NRTS2", "NRTS3", "NRTS4", "OSCCLK",
- "PEWAKE", "PNOR", "PWM0", "PWM1", "PWM2", "PWM3", "PWM4", "PWM5",
- "PWM6", "PWM7", "RGMII1", "RGMII2", "RMII1", "RMII2", "RXD1",
- "RXD2", "RXD3", "RXD4", "SALT1", "SALT10", "SALT11", "SALT12",
- "SALT13", "SALT14", "SALT2", "SALT3", "SALT4", "SALT5", "SALT6",
- "SALT7", "SALT8", "SALT9", "SCL1", "SCL2", "SD1", "SD2", "SDA1",
- "SDA2", "SGPS1", "SGPS2", "SIOONCTRL", "SIOPBI", "SIOPBO",
- "SIOPWREQ", "SIOPWRGD", "SIOS3", "SIOS5", "SIOSCI", "SPI1",
- "SPI1CS1", "SPI1DEBUG", "SPI1PASSTHRU", "SPI2CK", "SPI2CS0",
- "SPI2CS1", "SPI2MISO", "SPI2MOSI", "TIMER3", "TIMER4", "TIMER5",
- "TIMER6", "TIMER7", "TIMER8", "TXD1", "TXD2", "TXD3", "TXD4",
- "UART6", "USB11BHID", "USB2AD", "USB2AH", "USB2BD", "USB2BH",
- "USBCKI", "VGABIOSROM", "VGAHS", "VGAVS", "VPI24", "VPO",
- "WDTRST1", "WDTRST2", ]
+ - enum: [ ACPI, ADC0, ADC1, ADC10, ADC11, ADC12, ADC13, ADC14,
+ ADC15, ADC2, ADC3, ADC4, ADC5, ADC6, ADC7, ADC8, ADC9, BMCINT,
+ DDCCLK, DDCDAT, ESPI, FWSPICS1, FWSPICS2, GPID0, GPID2, GPID4,
+ GPID6, GPIE0, GPIE2, GPIE4, GPIE6, I2C10, I2C11, I2C12, I2C13,
+ I2C14, I2C3, I2C4, I2C5, I2C6, I2C7, I2C8, I2C9, LAD0, LAD1,
+ LAD2, LAD3, LCLK, LFRAME, LPCHC, LPCPD, LPCPLUS, LPCPME, LPCRST,
+ LPCSMI, LSIRQ, MAC1LINK, MAC2LINK, MDIO1, MDIO2, NCTS1, NCTS2,
+ NCTS3, NCTS4, NDCD1, NDCD2, NDCD3, NDCD4, NDSR1, NDSR2, NDSR3,
+ NDSR4, NDTR1, NDTR2, NDTR3, NDTR4, NRI1, NRI2, NRI3, NRI4, NRTS1,
+ NRTS2, NRTS3, NRTS4, OSCCLK, PEWAKE, PNOR, PWM0, PWM1, PWM2,
+ PWM3, PWM4, PWM5, PWM6, PWM7, RGMII1, RGMII2, RMII1, RMII2, RXD1,
+ RXD2, RXD3, RXD4, SALT1, SALT10, SALT11, SALT12, SALT13, SALT14,
+ SALT2, SALT3, SALT4, SALT5, SALT6, SALT7, SALT8, SALT9, SCL1,
+ SCL2, SD1, SD2, SDA1, SDA2, SGPS1, SGPS2, SIOONCTRL, SIOPBI,
+ SIOPBO, SIOPWREQ, SIOPWRGD, SIOS3, SIOS5, SIOSCI, SPI1, SPI1CS1,
+ SPI1DEBUG, SPI1PASSTHRU, SPI2CK, SPI2CS0, SPI2CS1, SPI2MISO,
+ SPI2MOSI, TIMER3, TIMER4, TIMER5, TIMER6, TIMER7, TIMER8, TXD1,
+ TXD2, TXD3, TXD4, UART6, USB11BHID, USB2AD, USB2AH, USB2BD,
+ USB2BH, USBCKI, VGABIOSROM, VGAHS, VGAVS, VPI24, VPO, WDTRST1,
+ WDTRST2, ]
required:
- compatible
--
2.20.1
^ permalink raw reply related
* [PATCH V2 1/2] usb: dwc3: Add node to update cache type setting
From: Ran Wang @ 2019-07-12 6:42 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Mark Rutland, Felipe Balbi
Cc: linux-usb, devicetree, linux-kernel, Ran Wang
Some Layerscape paltforms (such as LS1088A, LS2088A, etc) encounter USB
detect failues when adding dma-coherent to DWC3 node. This is because the
HW default cache type configuration of those SoC are not right, need to
be updated in DTS.
Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
---
Change in v2:
- New file.
Documentation/devicetree/bindings/usb/dwc3.txt | 43 ++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index 8e5265e..7bc1cef 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -110,6 +110,43 @@ Optional properties:
- in addition all properties from usb-xhci.txt from the current directory are
supported as well
+* Cache type nodes (optional)
+
+The Cache type node is used to tell how to configure cache type on 4 different
+transfer types: Data Read, Desc Read, Data Write and Desc write. For each
+treasfer type, controller has a 4-bit register field to enable different cache
+type. Quoted from DWC3 data book Table 6-5 Cache Type Bit Assignments:
+----------------------------------------------------------------
+MBUS_TYPE| bit[3] |bit[2] |bit[1] |bit[0]
+----------------------------------------------------------------
+AHB |Cacheable |Bufferable |Privilegge |Data
+AXI3 |Write Allocate|Read Allocate|Cacheable |Bufferable
+AXI4 |Allocate Other|Allocate |Modifiable |Bufferable
+AXI4 |Other Allocate|Allocate |Modifiable |Bufferable
+Native |Same as AXI |Same as AXI |Same as AXI|Same as AXI
+----------------------------------------------------------------
+Note: The AHB, AXI3, AXI4, and PCIe busses use different names for certain
+signals, which have the same meaning:
+ Bufferable = Posted
+ Cacheable = Modifiable = Snoop (negation of No Snoop)
+
+In most cases, this node is not required unless the default values of related
+registers are not correct *and* DWC3 node has enabled dma-coherent. So far we
+have observed USB device detect failure on some Layerscape platforms if this
+programming is not conducted properly.
+
+Required properties:
+- transfer_type_datard: A value for 4-bit register which decide cache type of
+ Data Read transfer. According to above table, we can know that different
+ master bus type will cause different definition of cache type control bit. So
+ developer need to know which master bus type his platforms are using in
+ advance, then decide the value for this transfer type.
+- transfer_type_descrd: A value for 4-bit register which decide cache type of
+ Desc Read transfer.
+- transfer_type_datawr: A value for 4-bit register which decide cache type of
+ Data Write transfer.
+- transfer_type_descwr: A value for 4-bit register which decide cache type of
+ Desc Write transfer.
This is usually a subnode to DWC3 glue to which it is connected.
@@ -119,4 +156,10 @@ dwc3@4a030000 {
interrupts = <0 92 4>
usb-phy = <&usb2_phy>, <&usb3,phy>;
snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+ cache_type: cache_type {
+ transfer_type_datard = <0x2>;
+ transfer_type_descrd = <0x2>;
+ transfer_type_datawr = <0x2>;
+ transfer_type_descwr = <0x2>;
+ };
};
--
2.7.4
^ permalink raw reply related
* [PATCH V2 2/2] usb: dwc3: Add cache type configuration support
From: Ran Wang @ 2019-07-12 6:42 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Mark Rutland, Felipe Balbi
Cc: linux-usb, devicetree, linux-kernel, Ran Wang
In-Reply-To: <20190712064206.48249-1-ran.wang_1@nxp.com>
Add support to configure cache type for 4 different transfer types: Data Read,
Desc Read, Data Write and Desc write. For each treasfer type, controller has a
4-bit register field to enable different cache type.
Some Layerscape platforms might need this to resolve USB detect problem
when DWC3 node apply dma-coherent.
Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
---
Change in v2:
- Change most program logic to meet new DTS property define.
- Rename related register address macros.
- Rename function dwc3_enable_snooping() to dwc3_set_cache_type().
drivers/usb/dwc3/core.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++
drivers/usb/dwc3/core.h | 12 ++++++++++
2 files changed, 76 insertions(+)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 4aff1d8..43bdd73 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -284,6 +284,69 @@ static const struct clk_bulk_data dwc3_core_clks[] = {
};
/*
+ * dwc3_set_cache_type - Configure cache type
+ * @dwc3: Pointer to our controller context structure
+ */
+static void dwc3_set_cache_type(struct dwc3 *dwc)
+{
+ int ret;
+ u32 tmp, reg, cache_type;
+ struct fwnode_handle *fwnode;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0);
+ tmp = reg;
+
+ fwnode = device_get_named_child_node(dwc->dev, "cache_type");
+ if (!fwnode) {
+ dev_info(dwc->dev, "Cache_type node no found, skip.\n");
+ return;
+ }
+
+ ret = fwnode_property_read_u32(fwnode,
+ "transfer_type_datard", &cache_type);
+ if (ret) {
+ dev_err(dwc->dev,
+ "Can't find property transfer_type_datard.\n");
+ return;
+ }
+ reg &= ~DWC3_GSBUSCFG0_DATARD(~0);
+ reg |= DWC3_GSBUSCFG0_DATARD(cache_type);
+
+ ret = fwnode_property_read_u32(fwnode,
+ "transfer_type_descrd", &cache_type);
+ if (ret) {
+ dev_err(dwc->dev,
+ "Can't find property transfer_type_descrd.\n");
+ return;
+ }
+ reg &= ~DWC3_GSBUSCFG0_DESCRD(~0);
+ reg |= DWC3_GSBUSCFG0_DESCRD(cache_type);
+
+ ret = fwnode_property_read_u32(fwnode,
+ "transfer_type_datawr", &cache_type);
+ if (ret) {
+ dev_err(dwc->dev,
+ "Can't find property transfer_type_datawr.\n");
+ return;
+ }
+ reg &= ~DWC3_GSBUSCFG0_DATAWR(~0);
+ reg |= DWC3_GSBUSCFG0_DATAWR(cache_type);
+
+ ret = fwnode_property_read_u32(fwnode,
+ "transfer_type_descwr", &cache_type);
+ if (ret) {
+ dev_err(dwc->dev,
+ "Can't find property transfer_type_descwr.\n");
+ return;
+ }
+ reg &= ~DWC3_GSBUSCFG0_DESCWR(~0);
+ reg |= DWC3_GSBUSCFG0_DESCWR(cache_type);
+
+ if (tmp != reg)
+ dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, reg);
+}
+
+/*
* dwc3_frame_length_adjustment - Adjusts frame length if required
* @dwc3: Pointer to our controller context structure
*/
@@ -942,6 +1005,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_frame_length_adjustment(dwc);
dwc3_set_incr_burst_type(dwc);
+ dwc3_set_cache_type(dwc);
usb_phy_set_suspend(dwc->usb2_phy, 0);
usb_phy_set_suspend(dwc->usb3_phy, 0);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index f19cbeb..24a613f 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -165,6 +165,18 @@
/* Bit fields */
/* Global SoC Bus Configuration INCRx Register 0 */
+#define DWC3_GSBUSCFG0_DATARD_SHIFT 28
+#define DWC3_GSBUSCFG0_DATARD(n) (((n) & 0xf) \
+ << DWC3_GSBUSCFG0_DATARD_SHIFT)
+#define DWC3_GSBUSCFG0_DESCRD_SHIFT 24
+#define DWC3_GSBUSCFG0_DESCRD(n) (((n) & 0xf) \
+ << DWC3_GSBUSCFG0_DESCRD_SHIFT)
+#define DWC3_GSBUSCFG0_DATAWR_SHIFT 20
+#define DWC3_GSBUSCFG0_DATAWR(n) (((n) & 0xf) \
+ << DWC3_GSBUSCFG0_DATAWR_SHIFT)
+#define DWC3_GSBUSCFG0_DESCWR_SHIFT 16
+#define DWC3_GSBUSCFG0_DESCWR(n) (((n) & 0xf) \
+ << DWC3_GSBUSCFG0_DESCWR_SHIFT)
#define DWC3_GSBUSCFG0_INCR256BRSTENA (1 << 7) /* INCR256 burst */
#define DWC3_GSBUSCFG0_INCR128BRSTENA (1 << 6) /* INCR128 burst */
#define DWC3_GSBUSCFG0_INCR64BRSTENA (1 << 5) /* INCR64 burst */
--
2.7.4
^ permalink raw reply related
* [PATCHv3] clk: add imx8 clk defines
From: Oliver Graute @ 2019-07-12 7:16 UTC (permalink / raw)
To: sboyd@kernel.org
Cc: Mark Rutland, Aisheng Dong, Ulf Hansson, Anson.Huang@nxp.com,
devicetree@vger.kernel.org, Fabio Estevam, Oliver Graute,
linux-kernel@vger.kernel.org, Rob Herring, NXP Linux Team,
Pengutronix Kernel Team, Shawn Guo, Sascha Hauer,
linux-arm-kernel@lists.infradead.org
From: Anson Huang <Anson.Huang@nxp.com>
added header defines for imx8qm clock
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Signed-off-by: Oliver Graute <oliver.graute@kococonnector.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
- fixed authorship
include/dt-bindings/clock/imx8qm-clock.h | 851 +++++++++++++++++++++++
1 file changed, 851 insertions(+)
create mode 100644 include/dt-bindings/clock/imx8qm-clock.h
diff --git a/include/dt-bindings/clock/imx8qm-clock.h b/include/dt-bindings/clock/imx8qm-clock.h
new file mode 100644
index 000000000000..47217e4eaa6b
--- /dev/null
+++ b/include/dt-bindings/clock/imx8qm-clock.h
@@ -0,0 +1,851 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+*/
+
+#ifndef __DT_BINDINGS_CLOCK_IMX8QM_H
+#define __DT_BINDINGS_CLOCK_IMX8QM_H
+
+#define IMX8QM_CLK_DUMMY 0
+
+#define IMX8QM_A53_DIV 1
+#define IMX8QM_A53_CLK 2
+#define IMX8QM_A72_DIV 3
+#define IMX8QM_A72_CLK 4
+
+/* SC Clocks. */
+#define IMX8QM_SC_I2C_DIV 5
+#define IMX8QM_SC_I2C_CLK 6
+#define IMX8QM_SC_PID0_DIV 7
+#define IMX8QM_SC_PID0_CLK 8
+#define IMX8QM_SC_PIT_DIV 9
+#define IMX8QM_SC_PIT_CLK 10
+#define IMX8QM_SC_TPM_DIV 11
+#define IMX8QM_SC_TPM_CLK 12
+#define IMX8QM_SC_UART_DIV 13
+#define IMX8QM_SC_UART_CLK 14
+
+/* LSIO */
+#define IMX8QM_PWM0_DIV 15
+#define IMX8QM_PWM0_CLK 16
+#define IMX8QM_PWM1_DIV 17
+#define IMX8QM_PWM1_CLK 18
+#define IMX8QM_PWM2_DIV 19
+#define IMX8QM_PWM2_CLK 20
+#define IMX8QM_PWM3_DIV 21
+#define IMX8QM_PWM3_CLK 22
+#define IMX8QM_PWM4_DIV 23
+#define IMX8QM_PWM4_CLK 24
+#define IMX8QM_PWM5_DIV 26
+#define IMX8QM_PWM5_CLK 27
+#define IMX8QM_PWM6_DIV 28
+#define IMX8QM_PWM6_CLK 29
+#define IMX8QM_PWM7_DIV 30
+#define IMX8QM_PWM7_CLK 31
+#define IMX8QM_FSPI0_DIV 32
+#define IMX8QM_FSPI0_CLK 33
+#define IMX8QM_FSPI1_DIV 34
+#define IMX8QM_FSPI1_CLK 35
+#define IMX8QM_GPT0_DIV 36
+//#define IMX8QM_GPT0_CLK 37
+#define IMX8QM_GPT1_DIV 38
+//#define IMX8QM_GPT1_CLK 39
+#define IMX8QM_GPT2_DIV 40
+#define IMX8QM_GPT2_CLK 41
+#define IMX8QM_GPT3_DIV 42
+#define IMX8QM_GPT3_CLK 43
+#define IMX8QM_GPT4_DIV 44
+#define IMX8QM_GPT4_CLK 45
+
+/* Connectivity */
+#define IMX8QM_APBHDMA_CLK 46
+#define IMX8QM_GPMI_APB_CLK 47
+#define IMX8QM_GPMI_APB_BCH_CLK 48
+#define IMX8QM_GPMI_BCH_IO_DIV 49
+#define IMX8QM_GPMI_BCH_IO_CLK 50
+#define IMX8QM_GPMI_BCH_DIV 51
+#define IMX8QM_GPMI_BCH_CLK 52
+#define IMX8QM_SDHC0_IPG_CLK 53
+#define IMX8QM_SDHC0_DIV 54
+#define IMX8QM_SDHC0_CLK 55
+#define IMX8QM_SDHC1_IPG_CLK 56
+#define IMX8QM_SDHC1_DIV 57
+#define IMX8QM_SDHC1_CLK 58
+#define IMX8QM_SDHC2_IPG_CLK 59
+#define IMX8QM_SDHC2_DIV 60
+#define IMX8QM_SDHC2_CLK 61
+#define IMX8QM_USB2_OH_AHB_CLK 62
+#define IMX8QM_USB2_OH_IPG_S_CL 63
+#define IMX8QM_USB2_OH_IPG_S_PL301_CLK 64
+#define IMX8QM_USB2_PHY_IPG_CLK 65
+#define IMX8QM_USB3_IPG_CLK 66
+#define IMX8QM_USB3_CORE_PCLK 67
+#define IMX8QM_USB3_PHY_CLK 68
+#define IMX8QM_USB3_ACLK_DIV 69
+#define IMX8QM_USB3_ACLK 70
+#define IMX8QM_USB3_BUS_DIV 71
+#define IMX8QM_USB3_BUS_CLK 72
+#define IMX8QM_USB3_LPM_DIV 73
+#define IMX8QM_USB3_LPM_CLK 74
+#define IMX8QM_ENET0_AHB_CLK 75
+#define IMX8QM_ENET0_IPG_S_CLK 76
+#define IMX8QM_ENET0_IPG_CLK 77
+#define IMX8QM_ENET0_RGMII_DIV 78
+#define IMX8QM_ENET0_RGMII_TX_CLK 79
+#define IMX8QM_ENET0_ROOT_DIV 80
+#define IMX8QM_ENET0_TX_CLK 81
+#define IMX8QM_ENET0_ROOT_CLK 82
+#define IMX8QM_ENET0_PTP_CLK 83
+#define IMX8QM_ENET0_BYPASS_DIV 84
+#define IMX8QM_ENET1_AHB_CLK 85
+#define IMX8QM_ENET1_IPG_S_CLK 86
+#define IMX8QM_ENET1_IPG_CLK 87
+#define IMX8QM_ENET1_RGMII_DIV 88
+#define IMX8QM_ENET1_RGMII_TX_CLK 89
+#define IMX8QM_ENET1_ROOT_DIV 90
+#define IMX8QM_ENET1_TX_CLK 91
+#define IMX8QM_ENET1_ROOT_CLK 92
+#define IMX8QM_ENET1_PTP_CLK 93
+#define IMX8QM_ENET1_BYPASS_DIV 94
+//#define IMX8QM_MLB_CLK 95
+#define IMX8QM_MLB_HCLK 96
+#define IMX8QM_MLB_IPG_CLK 97
+#define IMX8QM_EDMA_CLK 98
+#define IMX8QM_EDMA_IPG_CLK 99
+
+/* DMA */
+#define IMX8QM_SPI0_IPG_CLK 100
+#define IMX8QM_SPI0_DIV 101
+#define IMX8QM_SPI0_CLK 102
+#define IMX8QM_SPI1_IPG_CLK 103
+#define IMX8QM_SPI1_DIV 104
+#define IMX8QM_SPI1_CLK 105
+#define IMX8QM_SPI2_IPG_CLK 106
+#define IMX8QM_SPI2_DIV 107
+#define IMX8QM_SPI2_CLK 108
+#define IMX8QM_SPI3_IPG_CLK 109
+#define IMX8QM_SPI3_DIV 110
+#define IMX8QM_SPI3_CLK 111
+#define IMX8QM_UART0_IPG_CLK 112
+#define IMX8QM_UART0_DIV 113
+#define IMX8QM_UART0_CLK 114
+#define IMX8QM_UART1_IPG_CLK 115
+#define IMX8QM_UART1_DIV 116
+#define IMX8QM_UART1_CLK 117
+#define IMX8QM_UART2_IPG_CLK 118
+#define IMX8QM_UART2_DIV 119
+#define IMX8QM_UART2_CLK 120
+#define IMX8QM_UART3_IPG_CLK 121
+#define IMX8QM_UART3_DIV 122
+#define IMX8QM_UART3_CLK 123
+#define IMX8QM_UART4_IPG_CLK 124
+#define IMX8QM_UART4_DIV 125
+#define IMX8QM_EMVSIM0_IPG_CLK 126
+#define IMX8QM_UART4_CLK 127
+#define IMX8QM_EMVSIM0_DIV 128
+#define IMX8QM_EMVSIM0_CLK 129
+#define IMX8QM_EMVSIM1_IPG_CLK 130
+#define IMX8QM_EMVSIM1_DIV 131
+#define IMX8QM_EMVSIM1_CLK 132
+#define IMX8QM_CAN0_IPG_CHI_CLK 133
+#define IMX8QM_CAN0_IPG_CLK 134
+#define IMX8QM_CAN0_DIV 135
+#define IMX8QM_CAN0_CLK 136
+#define IMX8QM_CAN1_IPG_CHI_CLK 137
+#define IMX8QM_CAN1_IPG_CLK 138
+#define IMX8QM_CAN1_DIV 139
+#define IMX8QM_CAN1_CLK 140
+#define IMX8QM_CAN2_IPG_CHI_CLK 141
+#define IMX8QM_CAN2_IPG_CLK 142
+#define IMX8QM_CAN2_DIV 143
+#define IMX8QM_CAN2_CLK 144
+#define IMX8QM_I2C0_IPG_CLK 145
+#define IMX8QM_I2C0_DIV 146
+#define IMX8QM_I2C0_CLK 147
+#define IMX8QM_I2C1_IPG_CLK 148
+#define IMX8QM_I2C1_DIV 149
+#define IMX8QM_I2C1_CLK 150
+#define IMX8QM_I2C2_IPG_CLK 151
+#define IMX8QM_I2C2_DIV 152
+#define IMX8QM_I2C2_CLK 153
+#define IMX8QM_I2C3_IPG_CLK 154
+#define IMX8QM_I2C3_DIV 155
+#define IMX8QM_I2C3_CLK 156
+#define IMX8QM_I2C4_IPG_CLK 157
+#define IMX8QM_I2C4_DIV 158
+#define IMX8QM_I2C4_CLK 159
+#define IMX8QM_FTM0_IPG_CLK 160
+#define IMX8QM_FTM0_DIV 161
+#define IMX8QM_FTM0_CLK 162
+#define IMX8QM_FTM1_IPG_CLK 163
+#define IMX8QM_FTM1_DIV 164
+#define IMX8QM_FTM1_CLK 165
+#define IMX8QM_ADC0_IPG_CLK 166
+#define IMX8QM_ADC0_DIV 167
+#define IMX8QM_ADC0_CLK 168
+#define IMX8QM_ADC1_IPG_CLK 169
+#define IMX8QM_ADC1_DIV 170
+#define IMX8QM_ADC1_CLK 171
+
+/* Audio */
+#define IMX8QM_AUD_PLL0_DIV 172
+#define IMX8QM_AUD_PLL0 173
+#define IMX8QM_AUD_PLL1_DIV 174
+#define IMX8QM_AUD_PLL1 175
+#define IMX8QM_AUD_AMIX_IPG 182
+#define IMX8QM_AUD_ESAI_0_IPG 183
+#define IMX8QM_AUD_ESAI_1_IPG 184
+#define IMX8QM_AUD_ESAI_0_EXTAL_IPG 185
+#define IMX8QM_AUD_ESAI_1_EXTAL_IPG 186
+#define IMX8QM_AUD_SAI_0_IPG 187
+#define IMX8QM_AUD_SAI_0_IPG_S 188
+#define IMX8QM_AUD_SAI_0_MCLK 189
+#define IMX8QM_AUD_SAI_1_IPG 190
+#define IMX8QM_AUD_SAI_1_IPG_S 191
+#define IMX8QM_AUD_SAI_1_MCLK 192
+#define IMX8QM_AUD_SAI_2_IPG 193
+#define IMX8QM_AUD_SAI_2_IPG_S 194
+#define IMX8QM_AUD_SAI_2_MCLK 195
+#define IMX8QM_AUD_SAI_3_IPG 196
+#define IMX8QM_AUD_SAI_3_IPG_S 197
+#define IMX8QM_AUD_SAI_3_MCLK 198
+#define IMX8QM_AUD_SAI_6_IPG 199
+#define IMX8QM_AUD_SAI_6_IPG_S 200
+#define IMX8QM_AUD_SAI_6_MCLK 201
+#define IMX8QM_AUD_SAI_7_IPG 202
+#define IMX8QM_AUD_SAI_7_IPG_S 203
+#define IMX8QM_AUD_SAI_7_MCLK 204
+#define IMX8QM_AUD_SAI_HDMIRX0_IPG 205
+#define IMX8QM_AUD_SAI_HDMIRX0_IPG_S 206
+#define IMX8QM_AUD_SAI_HDMIRX0_MCLK 207
+#define IMX8QM_AUD_SAI_HDMITX0_IPG 208
+#define IMX8QM_AUD_SAI_HDMITX0_IPG_S 209
+#define IMX8QM_AUD_SAI_HDMITX0_MCLK 210
+#define IMX8QM_AUD_MQS_IPG 211
+#define IMX8QM_AUD_MQS_HMCLK 212
+#define IMX8QM_AUD_GPT5_IPG_S 213
+#define IMX8QM_AUD_GPT5_CLKIN 214
+#define IMX8QM_AUD_GPT5_24M_CLK 215
+#define IMX8QM_AUD_GPT6_IPG_S 216
+#define IMX8QM_AUD_GPT6_CLKIN 217
+#define IMX8QM_AUD_GPT6_24M_CLK 218
+#define IMX8QM_AUD_GPT7_IPG_S 219
+#define IMX8QM_AUD_GPT7_CLKIN 220
+#define IMX8QM_AUD_GPT7_24M_CLK 221
+#define IMX8QM_AUD_GPT8_IPG_S 222
+#define IMX8QM_AUD_GPT8_CLKIN 223
+#define IMX8QM_AUD_GPT8_24M_CLK 224
+#define IMX8QM_AUD_GPT9_IPG_S 225
+#define IMX8QM_AUD_GPT9_CLKIN 226
+#define IMX8QM_AUD_GPT9_24M_CLK 227
+#define IMX8QM_AUD_GPT10_IPG_S 228
+#define IMX8QM_AUD_GPT10_CLKIN 229
+#define IMX8QM_AUD_GPT10_24M_CLK 230
+#define IMX8QM_AUD_ACM_AUD_PLL_CLK0_DIV 232
+#define IMX8QM_AUD_ACM_AUD_PLL_CLK0_CLK 233
+#define IMX8QM_AUD_ACM_AUD_PLL_CLK1_DIV 234
+#define IMX8QM_AUD_ACM_AUD_PLL_CLK1_CLK 235
+#define IMX8QM_AUD_ACM_AUD_REC_CLK0_DIV 236
+#define IMX8QM_AUD_ACM_AUD_REC_CLK0_CLK 237
+#define IMX8QM_AUD_ACM_AUD_REC_CLK1_DIV 238
+#define IMX8QM_AUD_ACM_AUD_REC_CLK1_CLK 239
+#define IMX8QM_AUD_MCLKOUT0 240
+#define IMX8QM_AUD_MCLKOUT1 241
+#define IMX8QM_AUD_SPDIF_0_TX_CLK 242
+#define IMX8QM_AUD_SPDIF_0_GCLKW 243
+#define IMX8QM_AUD_SPDIF_0_IPG_S 244
+#define IMX8QM_AUD_SPDIF_1_TX_CLK 245
+#define IMX8QM_AUD_SPDIF_1_GCLKW 246
+#define IMX8QM_AUD_SPDIF_1_IPG_S 247
+#define IMX8QM_AUD_ASRC_0_IPG 248
+#define IMX8QM_AUD_ASRC_0_MEM 249
+#define IMX8QM_AUD_ASRC_1_IPG 250
+#define IMX8QM_AUD_ASRC_1_MEM 251
+
+
+/* VPU */
+#define IMX8QM_VPU_CORE_DIV 252
+#define IMX8QM_VPU_CORE_CLK 253
+#define IMX8QM_VPU_UART_DIV 254
+#define IMX8QM_VPU_UART_CLK 255
+#define IMX8QM_VPU_DDR_DIV 256
+#define IMX8QM_VPU_DDR_CLK 257
+#define IMX8QM_VPU_SYS_DIV 258
+#define IMX8QM_VPU_SYS_CLK 259
+#define IMX8QM_VPU_XUVI_DIV 260
+#define IMX8QM_VPU_XUVI_CLK 261
+
+/* GPU Clocks. */
+#define IMX8QM_GPU0_CORE_DIV 262
+#define IMX8QM_GPU0_CORE_CLK 263
+#define IMX8QM_GPU0_SHADER_DIV 264
+#define IMX8QM_GPU0_SHADER_CLK 265
+#define IMX8QM_GPU1_CORE_DIV 266
+#define IMX8QM_GPU1_CORE_CLK 267
+#define IMX8QM_GPU1_SHADER_DIV 268
+#define IMX8QM_GPU1_SHADER_CLK 269
+
+
+/* MIPI CSI */
+#define IMX8QM_CSI0_IPG_CLK_S 270
+#define IMX8QM_CSI0_LIS_IPG_CLK 271
+#define IMX8QM_CSI0_APB_CLK 272
+#define IMX8QM_CSI0_I2C0_DIV 273
+#define IMX8QM_CSI0_I2C0_CLK 274
+#define IMX8QM_CSI0_PWM0_DIV 275
+#define IMX8QM_CSI0_PWM0_CLK 276
+#define IMX8QM_CSI0_CORE_DIV 277
+#define IMX8QM_CSI0_CORE_CLK 278
+#define IMX8QM_CSI0_ESC_DIV 279
+#define IMX8QM_CSI0_ESC_CLK 280
+#define IMX8QM_CSI1_IPG_CLK_S 281
+#define IMX8QM_CSI1_LIS_IPG_CLK 282
+#define IMX8QM_CSI1_APB_CLK 283
+#define IMX8QM_CSI1_I2C0_DIV 284
+#define IMX8QM_CSI1_I2C0_CLK 285
+#define IMX8QM_CSI1_PWM0_DIV 286
+#define IMX8QM_CSI1_PWM0_CLK 287
+#define IMX8QM_CSI1_CORE_DIV 288
+#define IMX8QM_CSI1_CORE_CLK 289
+#define IMX8QM_CSI1_ESC_DIV 290
+#define IMX8QM_CSI1_ESC_CLK 291
+
+
+/* Display */
+#define IMX8QM_DC0_PLL0_DIV 292
+#define IMX8QM_DC0_PLL0_CLK 293
+#define IMX8QM_DC0_PLL1_DIV 294
+#define IMX8QM_DC0_PLL1_CLK 295
+#define IMX8QM_DC0_DISP0_DIV 296
+#define IMX8QM_DC0_DISP0_CLK 297
+#define IMX8QM_DC0_DISP1_DIV 298
+#define IMX8QM_DC0_DISP1_CLK 299
+#define IMX8QM_DC0_BYPASS_0_DIV 300
+#define IMX8QM_DC0_BYPASS_1_DIV 301
+#define IMX8QM_DC0_IRIS_AXI_CLK 302
+#define IMX8AM_DC0_IRIS_MVPL_CLK 303
+#define IMX8QM_DC0_DISP0_MSI_CLK 304
+#define IMX8QM_DC0_LIS_IPG_CLK 305
+#define IMX8QM_DC0_PXL_CMB_APB_CLK 306
+#define IMX8QM_DC0_PRG0_RTRAM_CLK 307
+#define IMX8QM_DC0_PRG1_RTRAM_CLK 308
+#define IMX8QM_DC0_PRG2_RTRAM_CLK 309
+#define IMX8QM_DC0_PRG3_RTRAM_CLK 310
+#define IMX8QM_DC0_PRG4_RTRAM_CLK 311
+#define IMX8QM_DC0_PRG5_RTRAM_CLK 312
+#define IMX8QM_DC0_PRG6_RTRAM_CLK 313
+#define IMX8QM_DC0_PRG7_RTRAM_CLK 314
+#define IMX8QM_DC0_PRG8_RTRAM_CLK 315
+#define IMX8QM_DC0_PRG0_APB_CLK 316
+#define IMX8QM_DC0_PRG1_APB_CLK 317
+#define IMX8QM_DC0_PRG2_APB_CLK 318
+#define IMX8QM_DC0_PRG3_APB_CLK 319
+#define IMX8QM_DC0_PRG4_APB_CLK 320
+#define IMX8QM_DC0_PRG5_APB_CLK 321
+#define IMX8QM_DC0_PRG6_APB_CLK 322
+#define IMX8QM_DC0_PRG7_APB_CLK 323
+#define IMX8QM_DC0_PRG8_APB_CLK 324
+#define IMX8QM_DC0_DPR0_APB_CLK 325
+#define IMX8QM_DC0_DPR1_APB_CLK 326
+#define IMX8QM_DC0_RTRAM0_CLK 327
+#define IMX8QM_DC0_RTRAM1_CLK 328
+#define IMX8QM_DC1_PLL0_DIV 329
+#define IMX8QM_DC1_PLL0_CLK 330
+#define IMX8QM_DC1_PLL1_DIV 331
+#define IMX8QM_DC1_PLL1_CLK 332
+#define IMX8QM_DC1_DISP0_DIV 333
+#define IMX8QM_DC1_DISP0_CLK 334
+#define IMX8QM_DC1_BYPASS_0_DIV 335
+#define IMX8QM_DC1_BYPASS_1_DIV 336
+#define IMX8QM_DC1_DISP1_DIV 337
+#define IMX8QM_DC1_DISP1_CLK 338
+#define IMX8QM_DC1_IRIS_AXI_CLK 339
+#define IMX8AM_DC1_IRIS_MVPL_CLK 340
+#define IMX8QM_DC1_DISP0_MSI_CLK 341
+#define IMX8QM_DC1_LIS_IPG_CLK 342
+#define IMX8QM_DC1_PXL_CMB_APB_CLK 343
+#define IMX8QM_DC1_PRG0_RTRAM_CLK 344
+#define IMX8QM_DC1_PRG1_RTRAM_CLK 345
+#define IMX8QM_DC1_PRG2_RTRAM_CLK 346
+#define IMX8QM_DC1_PRG3_RTRAM_CLK 347
+#define IMX8QM_DC1_PRG4_RTRAM_CLK 348
+#define IMX8QM_DC1_PRG5_RTRAM_CLK 349
+#define IMX8QM_DC1_PRG6_RTRAM_CLK 350
+#define IMX8QM_DC1_PRG7_RTRAM_CLK 351
+#define IMX8QM_DC1_PRG8_RTRAM_CLK 352
+#define IMX8QM_DC1_PRG0_APB_CLK 353
+#define IMX8QM_DC1_PRG1_APB_CLK 354
+#define IMX8QM_DC1_PRG2_APB_CLK 355
+#define IMX8QM_DC1_PRG3_APB_CLK 356
+#define IMX8QM_DC1_PRG4_APB_CLK 357
+#define IMX8QM_DC1_PRG5_APB_CLK 358
+#define IMX8QM_DC1_PRG6_APB_CLK 359
+#define IMX8QM_DC1_PRG7_APB_CLK 360
+#define IMX8QM_DC1_PRG8_APB_CLK 361
+#define IMX8QM_DC1_DPR0_APB_CLK 362
+#define IMX8QM_DC1_DPR1_APB_CLK 363
+#define IMX8QM_DC1_RTRAM0_CLK 364
+#define IMX8QM_DC1_RTRAM1_CLK 365
+
+/* DRC */
+#define IMX8QM_DRC0_PLL0_DIV 366
+#define IMX8QM_DRC0_PLL0_CLK 367
+#define IMX8QM_DRC0_DIV 368
+#define IMX8QM_DRC0_CLK 369
+#define IMX8QM_DRC1_PLL0_DIV 370
+#define IMX8QM_DRC1_PLL0_CLK 371
+#define IMX8QM_DRC1_DIV 372
+#define IMX8QM_DRC1_CLK 373
+
+/* HDMI */
+#define IMX8QM_HDMI_AV_PLL_DIV 374
+#define IMX8QM_HDMI_AV_PLL_CLK 375
+#define IMX8QM_HDMI_I2S_BYPASS_CLK 376
+#define IMX8QM_HDMI_I2C0_DIV 377
+#define IMX8QM_HDMI_I2C0_CLK 378
+#define IMX8QM_HDMI_PXL_DIV 379
+#define IMX8QM_HDMI_PXL_CLK 380
+#define IMX8QM_HDMI_PXL_LINK_DIV 381
+#define IMX8QM_HDMI_PXL_LINK_CLK 382
+#define IMX8QM_HDMI_PXL_MUX_DIV 383
+#define IMX8QM_HDMI_PXL_MUX_CLK 384
+#define IMX8QM_HDMI_I2S_DIV 385
+#define IMX8QM_HDMI_I2S_CLK 386
+#define IMX8QM_HDMI_HDP_CORE_DIV 387
+#define IMX8QM_HDMI_HDP_CORE_CLK 388
+#define IMX8QM_HDMI_I2C_IPG_S_CLK 389
+#define IMX8QM_HDMI_I2C_IPG_CLK 390
+#define IMX8QM_HDMI_PWM_IPG_S_CLK 391
+#define IMX8QM_HDMI_PWM_IPG_CLK 392
+#define IMX8QM_HDMI_PWM_32K_CLK 393
+#define IMX8QM_HDMI_GPIO_IPG_CLK 394
+#define IMX8QM_HDMI_PXL_LINK_SLV_ODD_CLK 395
+#define IMX8QM_HDMI_PXL_LINK_SLV_EVEN_CLK 396
+#define IMX8QM_HDMI_LIS_IPG_CLK 397
+#define IMX8QM_HDMI_MSI_HCLK 398
+#define IMX8QM_HDMI_PXL_EVEN_CLK 399
+#define IMX8QM_HDMI_HDP_CLK 400
+#define IMX8QM_HDMI_PXL_DBL_CLK 401
+#define IMX8QM_HDMI_APB_CLK 402
+#define IMX8QM_HDMI_PXL_LPCG_CLK 403
+#define IMX8QM_HDMI_HDP_PHY_CLK 404
+#define IMX8QM_HDMI_IPG_DIV 405
+#define IMX8QM_HDMI_VIF_CLK 406
+#define IMX8QM_HDMI_DIG_PLL_DIV 407
+#define IMX8QM_HDMI_DIG_PLL_CLK 408
+#define IMX8QM_HDMI_APB_MUX_CSR_CLK 409
+#define IMX8QM_HDMI_APB_MUX_CTRL_CLK 410
+
+/* RX-HDMI */
+#define IMX8QM_HDMI_RX_I2S_BYPASS_CLK 411
+#define IMX8QM_HDMI_RX_BYPASS_CLK 412
+#define IMX8QM_HDMI_RX_SPDIF_BYPASS_CLK 413
+#define IMX8QM_HDMI_RX_I2C0_DIV 414
+#define IMX8QM_HDMI_RX_I2C0_CLK 415
+#define IMX8QM_HDMI_RX_SPDIF_DIV 416
+#define IMX8QM_HDMI_RX_SPDIF_CLK 417
+#define IMX8QM_HDMI_RX_HD_REF_DIV 418
+#define IMX8QM_HDMI_RX_HD_REF_CLK 419
+#define IMX8QM_HDMI_RX_HD_CORE_DIV 420
+#define IMX8QM_HDMI_RX_HD_CORE_CLK 421
+#define IMX8QM_HDMI_RX_PXL_DIV 422
+#define IMX8QM_HDMI_RX_PXL_CLK 423
+#define IMX8QM_HDMI_RX_I2S_DIV 424
+#define IMX8QM_HDMI_RX_I2S_CLK 425
+#define IMX8QM_HDMI_RX_PWM_DIV 426
+#define IMX8QM_HDMI_RX_PWM_CLK 427
+
+/* LVDS */
+#define IMX8QM_LVDS0_BYPASS_CLK 428
+#define IMX8QM_LVDS0_PIXEL_DIV 429
+#define IMX8QM_LVDS0_PIXEL_CLK 430
+#define IMX8QM_LVDS0_PHY_DIV 431
+#define IMX8QM_LVDS0_PHY_CLK 432
+#define IMX8QM_LVDS0_I2C0_IPG_CLK 433
+#define IMX8QM_LVDS0_I2C0_DIV 434
+#define IMX8QM_LVDS0_I2C0_CLK 435
+#define IMX8QM_LVDS0_I2C1_IPG_CLK 436
+#define IMX8QM_LVDS0_I2C1_DIV 437
+#define IMX8QM_LVDS0_I2C1_CLK 438
+#define IMX8QM_LVDS0_PWM0_IPG_CLK 439
+#define IMX8QM_LVDS0_PWM0_DIV 440
+#define IMX8QM_LVDS0_PWM0_CLK 441
+#define IMX8QM_LVDS0_GPIO_IPG_CLK 444
+#define IMX8QM_LVDS1_BYPASS_DIV 445
+#define IMX8QM_LVDS1_BYPASS_CLK 446
+#define IMX8QM_LVDS1_PIXEL_DIV 447
+#define IMX8QM_LVDS1_PIXEL_CLK 448
+#define IMX8QM_LVDS1_PHY_DIV 449
+#define IMX8QM_LVDS1_PHY_CLK 450
+#define IMX8QM_LVDS1_I2C0_IPG_CLK 451
+#define IMX8QM_LVDS1_I2C0_DIV 452
+#define IMX8QM_LVDS1_I2C0_CLK 453
+#define IMX8QM_LVDS1_I2C1_IPG_CLK 454
+#define IMX8QM_LVDS1_I2C1_DIV 455
+#define IMX8QM_LVDS1_I2C1_CLK 456
+#define IMX8QM_LVDS1_PWM0_IPG_CLK 457
+#define IMX8QM_LVDS1_PWM0_DIV 458
+#define IMX8QM_LVDS1_PWM0_CLK 459
+#define IMX8QM_LVDS1_GPIO_IPG_CLK 462
+
+/* MIPI */
+#define IMX8QM_MIPI0_BYPASS_CLK 465
+#define IMX8QM_MIPI0_I2C0_DIV 466
+#define IMX8QM_MIPI0_I2C0_CLK 467
+#define IMX8QM_MIPI0_I2C1_DIV 468
+#define IMX8QM_MIPI0_I2C1_CLK 469
+#define IMX8QM_MIPI0_PWM0_DIV 470
+#define IMX8QM_MIPI0_PWM0_CLK 471
+#define IMX8QM_MIPI0_DSI_TX_ESC_DIV 472
+#define IMX8QM_MIPI0_DSI_TX_ESC_CLK 473
+#define IMX8QM_MIPI0_DSI_RX_ESC_DIV 474
+#define IMX8QM_MIPI0_DSI_RX_ESC_CLK 475
+#define IMX8QM_MIPI0_PXL_DIV 476
+#define IMX8QM_MIPI0_PXL_CLK 477
+#define IMX8QM_MIPI1_BYPASS_CLK 479
+#define IMX8QM_MIPI1_I2C0_DIV 480
+#define IMX8QM_MIPI1_I2C0_CLK 481
+#define IMX8QM_MIPI1_I2C1_DIV 482
+#define IMX8QM_MIPI1_I2C1_CLK 483
+#define IMX8QM_MIPI1_PWM0_DIV 484
+#define IMX8QM_MIPI1_PWM0_CLK 485
+#define IMX8QM_MIPI1_DSI_TX_ESC_DIV 486
+#define IMX8QM_MIPI1_DSI_TX_ESC_CLK 487
+#define IMX8QM_MIPI1_DSI_RX_ESC_DIV 488
+#define IMX8QM_MIPI1_DSI_RX_ESC_CLK 489
+#define IMX8QM_MIPI1_PXL_DIV 490
+#define IMX8QM_MIPI1_PXL_CLK 491
+
+/* Imaging */
+#define IMX8QM_IMG_JPEG_ENC_IPG_CLK 492
+#define IMX8QM_IMG_JPEG_ENC_CLK 493
+#define IMX8QM_IMG_JPEG_DEC_IPG_CLK 494
+#define IMX8QM_IMG_JPEG_DEC_CLK 495
+#define IMX8QM_IMG_PXL_LINK_DC0_CLK 496
+#define IMX8QM_IMG_PXL_LINK_DC1_CLK 497
+#define IMX8QM_IMG_PXL_LINK_CSI0_CLK 498
+#define IMX8QM_IMG_PXL_LINK_CSI1_CLK 499
+#define IMX8QM_IMG_PXL_LINK_HDMI_IN_CLK 500
+#define IMX8QM_IMG_PDMA_0_CLK 501
+#define IMX8QM_IMG_PDMA_1_CLK 502
+#define IMX8QM_IMG_PDMA_2_CLK 503
+#define IMX8QM_IMG_PDMA_3_CLK 504
+#define IMX8QM_IMG_PDMA_4_CLK 505
+#define IMX8QM_IMG_PDMA_5_CLK 506
+#define IMX8QM_IMG_PDMA_6_CLK 507
+#define IMX8QM_IMG_PDMA_7_CLK 508
+
+/* HSIO */
+#define IMX8QM_HSIO_PCIE_A_MSTR_AXI_CLK 509
+#define IMX8QM_HSIO_PCIE_A_SLV_AXI_CLK 510
+#define IMX8QM_HSIO_PCIE_A_DBI_AXI_CLK 511
+#define IMX8QM_HSIO_PCIE_B_MSTR_AXI_CLK 512
+#define IMX8QM_HSIO_PCIE_B_SLV_AXI_CLK 513
+#define IMX8QM_HSIO_PCIE_B_DBI_AXI_CLK 514
+#define IMX8QM_HSIO_PCIE_X1_PER_CLK 515
+#define IMX8QM_HSIO_PCIE_X2_PER_CLK 516
+#define IMX8QM_HSIO_SATA_PER_CLK 517
+#define IMX8QM_HSIO_PHY_X1_PER_CLK 518
+#define IMX8QM_HSIO_PHY_X2_PER_CLK 519
+#define IMX8QM_HSIO_MISC_PER_CLK 520
+#define IMX8QM_HSIO_PHY_X1_APB_CLK 521
+#define IMX8QM_HSIO_PHY_X2_APB_0_CLK 522
+#define IMX8QM_HSIO_PHY_X2_APB_1_CLK 523
+#define IMX8QM_HSIO_SATA_CLK 524
+#define IMX8QM_HSIO_GPIO_CLK 525
+#define IMX8QM_HSIO_PHY_X1_PCLK 526
+#define IMX8QM_HSIO_PHY_X2_PCLK_0 527
+#define IMX8QM_HSIO_PHY_X2_PCLK_1 528
+#define IMX8QM_HSIO_SATA_EPCS_RX_CLK 529
+#define IMX8QM_HSIO_SATA_EPCS_TX_CLK 530
+
+
+/* M4 */
+#define IMX8QM_M4_0_CORE_DIV 531
+#define IMX8QM_M4_0_CORE_CLK 532
+#define IMX8QM_M4_0_I2C_DIV 533
+#define IMX8QM_M4_0_I2C_CLK 534
+#define IMX8QM_M4_0_PIT_DIV 535
+#define IMX8QM_M4_0_PIT_CLK 536
+#define IMX8QM_M4_0_TPM_DIV 537
+#define IMX8QM_M4_0_TPM_CLK 538
+#define IMX8QM_M4_0_UART_DIV 539
+#define IMX8QM_M4_0_UART_CLK 540
+#define IMX8QM_M4_0_WDOG_DIV 541
+#define IMX8QM_M4_0_WDOG_CLK 542
+#define IMX8QM_M4_1_CORE_DIV 543
+#define IMX8QM_M4_1_CORE_CLK 544
+#define IMX8QM_M4_1_I2C_DIV 545
+#define IMX8QM_M4_1_I2C_CLK 546
+#define IMX8QM_M4_1_PIT_DIV 547
+#define IMX8QM_M4_1_PIT_CLK 548
+#define IMX8QM_M4_1_TPM_DIV 549
+#define IMX8QM_M4_1_TPM_CLK 550
+#define IMX8QM_M4_1_UART_DIV 551
+#define IMX8QM_M4_1_UART_CLK 552
+#define IMX8QM_M4_1_WDOG_DIV 553
+#define IMX8QM_M4_1_WDOG_CLK 554
+
+/* IPG clocks */
+#define IMX8QM_24MHZ 555
+#define IMX8QM_GPT_3M 556
+#define IMX8QM_IPG_DMA_CLK_ROOT 557
+#define IMX8QM_IPG_AUD_CLK_ROOT 558
+#define IMX8QM_IPG_CONN_CLK_ROOT 559
+#define IMX8QM_AHB_CONN_CLK_ROOT 560
+#define IMX8QM_AXI_CONN_CLK_ROOT 561
+#define IMX8QM_IPG_MIPI_CSI_CLK_ROOT 562
+#define IMX8QM_DC_AXI_EXT_CLK 563
+#define IMX8QM_DC_AXI_INT_CLK 564
+#define IMX8QM_DC_CFG_CLK 565
+#define IMX8QM_HDMI_IPG_CLK 566
+#define IMX8QM_LVDS_IPG_CLK 567
+#define IMX8QM_IMG_AXI_CLK 568
+#define IMX8QM_IMG_IPG_CLK 569
+#define IMX8QM_IMG_PXL_CLK 570
+#define IMX8QM_CSI0_I2C0_IPG_CLK 571
+#define IMX8QM_CSI0_PWM0_IPG_CLK 572
+#define IMX8QM_CSI1_I2C0_IPG_CLK 573
+#define IMX8QM_CSI1_PWM0_IPG_CLK 574
+#define IMX8QM_DC0_DPR0_B_CLK 575
+#define IMX8QM_DC0_DPR1_B_CLK 576
+#define IMX8QM_DC1_DPR0_B_CLK 577
+#define IMX8QM_DC1_DPR1_B_CLK 578
+#define IMX8QM_32KHZ 579
+#define IMX8QM_HSIO_AXI_CLK 580
+#define IMX8QM_HSIO_PER_CLK 581
+#define IMX8QM_HDMI_RX_GPIO_IPG_S_CLK 582
+#define IMX8QM_HDMI_RX_PWM_IPG_S_CLK 583
+#define IMX8QM_HDMI_RX_PWM_IPG_CLK 584
+#define IMX8QM_HDMI_RX_I2C_DIV_CLK 585
+#define IMX8QM_HDMI_RX_I2C_IPG_S_CLK 586
+#define IMX8QM_HDMI_RX_I2C_IPG_CLK 587
+#define IMX8QM_HDMI_RX_SINK_PCLK 588
+#define IMX8QM_HDMI_RX_SINK_SCLK 589
+#define IMX8QM_HDMI_RX_PXL_ENC_CLK 590
+#define IMX8QM_HDMI_RX_IPG_CLK 591
+
+/* ACM */
+#define IMX8QM_HDMI_RX_MCLK 592
+#define IMX8QM_EXT_AUD_MCLK0 593
+#define IMX8QM_EXT_AUD_MCLK1 594
+#define IMX8QM_ESAI0_RX_CLK 595
+#define IMX8QM_ESAI0_RX_HF_CLK 596
+#define IMX8QM_ESAI0_TX_CLK 597
+#define IMX8QM_ESAI0_TX_HF_CLK 598
+#define IMX8QM_ESAI1_RX_CLK 599
+#define IMX8QM_ESAI1_RX_HF_CLK 600
+#define IMX8QM_ESAI1_TX_CLK 601
+#define IMX8QM_ESAI1_TX_HF_CLK 602
+//#define IMX8QM_SPDIF0_RX 603
+#define IMX8QM_SPDIF1_RX 604
+#define IMX8QM_SAI0_RX_BCLK 605
+#define IMX8QM_SAI0_TX_BCLK 606
+#define IMX8QM_SAI1_RX_BCLK 607
+#define IMX8QM_SAI1_TX_BCLK 608
+#define IMX8QM_SAI2_RX_BCLK 609
+#define IMX8QM_SAI3_RX_BCLK 610
+#define IMX8QM_HDMI_RX_SAI0_RX_BCLK 611
+#define IMX8QM_SAI6_RX_BCLK 612
+#define IMX8QM_HDMI_TX_SAI0_TX_BCLK 613
+
+#define IMX8QM_ACM_AUD_CLK0_SEL 614
+#define IMX8QM_ACM_AUD_CLK0_CLK 615
+#define IMX8QM_ACM_AUD_CLK1_SEL 616
+#define IMX8QM_ACM_AUD_CLK1_CLK 617
+#define IMX8QM_ACM_MCLKOUT0_SEL 618
+#define IMX8QM_ACM_MCLKOUT0_CLK 619
+#define IMX8QM_ACM_MCLKOUT1_SEL 620
+#define IMX8QM_ACM_MCLKOUT1_CLK 621
+#define IMX8QM_ACM_ASRC0_MUX_CLK_SEL 622
+#define IMX8QM_ACM_ASRC0_MUX_CLK_CLK 623
+#define IMX8QM_ACM_ASRC1_MUX_CLK_SEL 624
+#define IMX8QM_ACM_ASRC1_MUX_CLK_CLK 625
+#define IMX8QM_ACM_ESAI0_MCLK_SEL 626
+#define IMX8QM_ACM_ESAI0_MCLK_CLK 627
+#define IMX8QM_ACM_ESAI1_MCLK_SEL 628
+#define IMX8QM_ACM_ESAI1_MCLK_CLK 629
+#define IMX8QM_ACM_GPT0_MUX_CLK_SEL 630
+#define IMX8QM_ACM_GPT0_MUX_CLK_CLK 631
+#define IMX8QM_ACM_GPT1_MUX_CLK_SEL 632
+#define IMX8QM_ACM_GPT1_MUX_CLK_CLK 633
+#define IMX8QM_ACM_GPT2_MUX_CLK_SEL 634
+#define IMX8QM_ACM_GPT2_MUX_CLK_CLK 635
+#define IMX8QM_ACM_GPT3_MUX_CLK_SEL 636
+#define IMX8QM_ACM_GPT3_MUX_CLK_CLK 637
+#define IMX8QM_ACM_GPT4_MUX_CLK_SEL 638
+#define IMX8QM_ACM_GPT4_MUX_CLK_CLK 639
+#define IMX8QM_ACM_GPT5_MUX_CLK_SEL 640
+#define IMX8QM_ACM_GPT5_MUX_CLK_CLK 641
+#define IMX8QM_ACM_SAI0_MCLK_SEL 642
+#define IMX8QM_ACM_SAI0_MCLK_CLK 643
+#define IMX8QM_ACM_SAI1_MCLK_SEL 644
+#define IMX8QM_ACM_SAI1_MCLK_CLK 645
+#define IMX8QM_ACM_SAI2_MCLK_SEL 646
+#define IMX8QM_ACM_SAI2_MCLK_CLK 647
+#define IMX8QM_ACM_SAI3_MCLK_SEL 648
+#define IMX8QM_ACM_SAI3_MCLK_CLK 649
+#define IMX8QM_ACM_HDMI_RX_SAI0_MCLK_SEL 650
+#define IMX8QM_ACM_HDMI_RX_SAI0_MCLK_CLK 651
+#define IMX8QM_ACM_HDMI_TX_SAI0_MCLK_SEL 652
+#define IMX8QM_ACM_HDMI_TX_SAI0_MCLK_CLK 653
+#define IMX8QM_ACM_SAI6_MCLK_SEL 654
+#define IMX8QM_ACM_SAI6_MCLK_CLK 655
+#define IMX8QM_ACM_SAI7_MCLK_SEL 656
+#define IMX8QM_ACM_SAI7_MCLK_CLK 657
+#define IMX8QM_ACM_SPDIF0_TX_CLK_SEL 658
+#define IMX8QM_ACM_SPDIF0_TX_CLK_CLK 659
+#define IMX8QM_ACM_SPDIF1_TX_CLK_SEL 660
+#define IMX8QM_ACM_SPDIF1_TX_CLK_CLK 661
+#define IMX8QM_ACM_MQS_TX_CLK_SEL 662
+#define IMX8QM_ACM_MQS_TX_CLK_CLK 663
+
+#define IMX8QM_ENET0_REF_25MHZ_125MHZ_SEL 664
+#define IMX8QM_ENET0_REF_25MHZ_125MHZ_CLK 665
+#define IMX8QM_ENET1_REF_25MHZ_125MHZ_SEL 666
+#define IMX8QM_ENET1_REF_25MHZ_125MHZ_CLK 667
+#define IMX8QM_ENET0_REF_50MHZ_CLK 668
+#define IMX8QM_ENET1_REF_50MHZ_CLK 669
+#define IMX8QM_ENET_25MHZ_CLK 670
+#define IMX8QM_ENET_125MHZ_CLK 671
+#define IMX8QM_ENET0_REF_DIV 672
+#define IMX8QM_ENET0_REF_CLK 673
+#define IMX8QM_ENET1_REF_DIV 674
+#define IMX8QM_ENET1_REF_CLK 675
+#define IMX8QM_ENET0_RMII_TX_CLK 676
+#define IMX8QM_ENET1_RMII_TX_CLK 677
+#define IMX8QM_ENET0_RMII_TX_SEL 678
+#define IMX8QM_ENET1_RMII_TX_SEL 679
+#define IMX8QM_ENET0_RMII_RX_CLK 680
+#define IMX8QM_ENET1_RMII_RX_CLK 681
+
+#define IMX8QM_KPP_CLK 683
+#define IMX8QM_GPT0_HF_CLK 684
+#define IMX8QM_GPT0_IPG_S_CLK 685
+#define IMX8QM_GPT0_IPG_SLV_CLK 686
+#define IMX8QM_GPT0_IPG_MSTR_CLK 687
+#define IMX8QM_GPT1_HF_CLK 688
+#define IMX8QM_GPT1_IPG_S_CLK 689
+#define IMX8QM_GPT1_IPG_SLV_CLK 690
+#define IMX8QM_GPT1_IPG_MSTR_CLK 691
+#define IMX8QM_GPT2_HF_CLK 692
+#define IMX8QM_GPT2_IPG_S_CLK 693
+#define IMX8QM_GPT2_IPG_SLV_CLK 694
+#define IMX8QM_GPT2_IPG_MSTR_CLK 695
+#define IMX8QM_GPT3_HF_CLK 696
+#define IMX8QM_GPT3_IPG_S_CLK 697
+#define IMX8QM_GPT3_IPG_SLV_CLK 698
+#define IMX8QM_GPT3_IPG_MSTR_CLK 699
+#define IMX8QM_GPT4_HF_CLK 700
+#define IMX8QM_GPT4_IPG_S_CLK 701
+#define IMX8QM_GPT4_IPG_SLV_CLK 702
+#define IMX8QM_GPT4_IPG_MSTR_CLK 703
+#define IMX8QM_PWM0_HF_CLK 704
+#define IMX8QM_PWM0_IPG_S_CLK 705
+#define IMX8QM_PWM0_IPG_SLV_CLK 706
+#define IMX8QM_PWM0_IPG_MSTR_CLK 707
+#define IMX8QM_PWM1_HF_CLK 708
+#define IMX8QM_PWM1_IPG_S_CLK 709
+#define IMX8QM_PWM1_IPG_SLV_CLK 710
+#define IMX8QM_PWM1_IPG_MSTR_CLK 711
+#define IMX8QM_PWM2_HF_CLK 712
+#define IMX8QM_PWM2_IPG_S_CLK 713
+#define IMX8QM_PWM2_IPG_SLV_CLK 714
+#define IMX8QM_PWM2_IPG_MSTR_CLK 715
+#define IMX8QM_PWM3_HF_CLK 716
+#define IMX8QM_PWM3_IPG_S_CLK 717
+#define IMX8QM_PWM3_IPG_SLV_CLK 718
+#define IMX8QM_PWM3_IPG_MSTR_CLK 719
+#define IMX8QM_PWM4_HF_CLK 720
+#define IMX8QM_PWM4_IPG_S_CLK 721
+#define IMX8QM_PWM4_IPG_SLV_CLK 722
+#define IMX8QM_PWM4_IPG_MSTR_CLK 723
+#define IMX8QM_PWM5_HF_CLK 724
+#define IMX8QM_PWM5_IPG_S_CLK 725
+#define IMX8QM_PWM5_IPG_SLV_CLK 726
+#define IMX8QM_PWM5_IPG_MSTR_CLK 727
+#define IMX8QM_PWM6_HF_CLK 728
+#define IMX8QM_PWM6_IPG_S_CLK 729
+#define IMX8QM_PWM6_IPG_SLV_CLK 730
+#define IMX8QM_PWM6_IPG_MSTR_CLK 731
+#define IMX8QM_PWM7_HF_CLK 732
+#define IMX8QM_PWM7_IPG_S_CLK 733
+#define IMX8QM_PWM7_IPG_SLV_CLK 734
+#define IMX8QM_PWM7_IPG_MSTR_CLK 735
+#define IMX8QM_FSPI0_HCLK 736
+#define IMX8QM_FSPI0_IPG_CLK 737
+#define IMX8QM_FSPI0_IPG_S_CLK 738
+#define IMX8QM_FSPI1_HCLK 736
+#define IMX8QM_FSPI1_IPG_CLK 737
+#define IMX8QM_FSPI1_IPG_S_CLK 738
+#define IMX8QM_GPIO0_IPG_S_CLK 739
+#define IMX8QM_GPIO1_IPG_S_CLK 740
+#define IMX8QM_GPIO2_IPG_S_CLK 741
+#define IMX8QM_GPIO3_IPG_S_CLK 742
+#define IMX8QM_GPIO4_IPG_S_CLK 743
+#define IMX8QM_GPIO5_IPG_S_CLK 744
+#define IMX8QM_GPIO6_IPG_S_CLK 745
+#define IMX8QM_GPIO7_IPG_S_CLK 746
+#define IMX8QM_ROMCP_CLK 747
+#define IMX8QM_ROMCP_REG_CLK 748
+#define IMX8QM_96KROM_CLK 749
+#define IMX8QM_OCRAM_MEM_CLK 750
+#define IMX8QM_OCRAM_CTRL_CLK 751
+#define IMX8QM_LSIO_BUS_CLK 752
+#define IMX8QM_LSIO_MEM_CLK 753
+#define IMX8QM_LVDS0_LIS_IPG_CLK 754
+#define IMX8QM_LVDS1_LIS_IPG_CLK 755
+#define IMX8QM_MIPI0_LIS_IPG_CLK 756
+#define IMX8QM_MIPI0_I2C0_IPG_S_CLK 757
+#define IMX8QM_MIPI0_I2C0_IPG_CLK 758
+#define IMX8QM_MIPI0_I2C1_IPG_S_CLK 759
+#define IMX8QM_MIPI0_I2C1_IPG_CLK 760
+#define IMX8QM_MIPI0_CLK_ROOT 761
+#define IMX8QM_MIPI1_LIS_IPG_CLK 762
+#define IMX8QM_MIPI1_I2C0_IPG_S_CLK 763
+#define IMX8QM_MIPI1_I2C0_IPG_CLK 764
+#define IMX8QM_MIPI1_I2C1_IPG_S_CLK 765
+#define IMX8QM_MIPI1_I2C1_IPG_CLK 766
+#define IMX8QM_MIPI1_CLK_ROOT 767
+#define IMX8QM_DC0_DISP0_SEL 768
+#define IMX8QM_DC0_DISP1_SEL 769
+#define IMX8QM_DC1_DISP0_SEL 770
+#define IMX8QM_DC1_DISP1_SEL 771
+
+/* CM40 */
+#define IMX8QM_CM40_IPG_CLK 772
+#define IMX8QM_CM40_I2C_DIV 773
+#define IMX8QM_CM40_I2C_CLK 774
+#define IMX8QM_CM40_I2C_IPG_CLK 775
+
+/* CM41 */
+#define IMX8QM_CM41_IPG_CLK 776
+#define IMX8QM_CM41_I2C_DIV 777
+#define IMX8QM_CM41_I2C_CLK 778
+#define IMX8QM_CM41_I2C_IPG_CLK 779
+
+#define IMX8QM_HDMI_PXL_SEL 780
+#define IMX8QM_HDMI_PXL_LINK_SEL 781
+#define IMX8QM_HDMI_PXL_MUX_SEL 782
+#define IMX8QM_HDMI_AV_PLL_BYPASS_CLK 783
+
+#define IMX8QM_HDMI_RX_PXL_SEL 784
+#define IMX8QM_HDMI_RX_HD_REF_SEL 785
+#define IMX8QM_HDMI_RX_HD_CORE_SEL 786
+#define IMX8QM_HDMI_RX_DIG_PLL_CLK 787
+
+#define IMX8QM_LSIO_MU5A_IPG_S_CLK 788
+#define IMX8QM_LSIO_MU5A_IPG_CLK 789
+#define IMX8QM_LSIO_MU6A_IPG_S_CLK 790
+#define IMX8QM_LSIO_MU6A_IPG_CLK 791
+
+/* DSP */
+#define IMX8QM_AUD_DSP_ADB_ACLK 792
+#define IMX8QM_AUD_DSP_IPG 793
+#define IMX8QM_AUD_DSP_CORE_CLK 794
+#define IMX8QM_AUD_OCRAM_IPG 795
+
+#define IMX8QM_CLK_END 796
+
+#endif /* __DT_BINDINGS_CLOCK_IMX8QM_H */
--
2.17.1
^ permalink raw reply related
* Re: [RFC PATCH V2 1/4] dt-bindings: mt8183: Added FD dt-bindings
From: CK Hu @ 2019-07-12 7:16 UTC (permalink / raw)
To: Jerry-ch Chen
Cc: devicetree, Sean.Cheng, laurent.pinchart+renesas, Rynn.Wu,
christie.yu, srv_heupstream, po-yang.huang, suleiman, sj.huang,
tfiga, jungo.lin, shik, yuzhao, hans.verkuil, zwisler,
frederic.chen, matthias.bgg, linux-mediatek, mchehab,
linux-arm-kernel, linux-media
In-Reply-To: <1562661672-22439-2-git-send-email-Jerry-Ch.chen@mediatek.com>
Hi, Jerry:
On Tue, 2019-07-09 at 16:41 +0800, Jerry-ch Chen wrote:
> From: Jerry-ch Chen <jerry-ch.chen@mediatek.com>
>
> This patch adds DT binding documentation for the Face Detection (FD)
> unit of the Mediatek's mt8183 SoC.
>
> Signed-off-by: Jerry-ch Chen <jerry-ch.chen@mediatek.com>
> ---
> .../bindings/media/mediatek,mt8183-fd.txt | 33 ++++++++++++++++++++++
> 1 file changed, 33 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/media/mediatek,mt8183-fd.txt
>
> diff --git a/Documentation/devicetree/bindings/media/mediatek,mt8183-fd.txt b/Documentation/devicetree/bindings/media/mediatek,mt8183-fd.txt
> new file mode 100644
> index 0000000..0837223
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/mediatek,mt8183-fd.txt
> @@ -0,0 +1,33 @@
> +* Mediatek Face Detection Unit (FD)
> +
> +Face Detection (FD) unit is a typical memory-to-memory HW device.
> +It provides hardware accelerated face detection function, and it
> +is able to detect different poses of faces. FD will writre result
> +of detected face into memory as output.
> +
> +Required properties:
> +- compatible: "mediatek,mt8183-fd"
> +- mediatek,scp : the node of system control processor (SCP), see
> + Documentation/devicetree/bindings/remoteproc/mtk,scp.txt for details.
> +- iommus: should point to the 3 entries: M4U_PORT_CAM_FDVT_RP,
> + M4U_PORT_CAM_FDVT_WR and M4U_PORT_CAM_FDVT_RB. (Please see
> + Documentation/devicetree/bindings/iommu/mediatek,iommu.txt for details.)
> +- reg: Physical base address and length of the register space.
> +- interrupts: interrupt number to the cpu.
> +- clocks : must contain the FDVT clock, see
> + Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
> +- clock-names: must be "fd".
> +
> +Example:
> + fd: fd@1502b000 {
> + compatible = "mediatek,mt8183-fd";
> + mediatek,scp = <&scp>;
> + iommus = <&iommu M4U_PORT_CAM_FDVT_RP>,
> + <&iommu M4U_PORT_CAM_FDVT_WR>,
> + <&iommu M4U_PORT_CAM_FDVT_RB>;
> + reg = <0 0x1502b000 0 0x1000>;
> + interrupts = <GIC_SPI 269 IRQ_TYPE_LEVEL_LOW>;
> + clocks = <&imgsys CLK_IMG_FDVT>;
> + clock-names = "fd";
This device has no power-domain?
Regards,
CK
> + };
> +
^ permalink raw reply
* Re: [PATCH v2] dt-bindings: rcar-{csi2,vin}: Rename bindings documentation files
From: Niklas Söderlund @ 2019-07-12 7:17 UTC (permalink / raw)
To: Rob Herring, devicetree, linux-media
Cc: linux-renesas-soc, Geert Uytterhoeven, Ulrich Hecht
In-Reply-To: <20190612211241.1455-1-niklas.soderlund+renesas@ragnatech.se>
Hi,
A gentle ping on this patch. I assume if it could get a ack from Rob it
could be taken in thru the media-tree?
On 2019-06-12 23:12:41 +0200, Niklas S�derlund wrote:
> Renesas media binding documentation files uses a naming schema of
> 'renesas,<module>.txt'. Rename VIN and CSI-2 files to match this
> pattern.
>
> Signed-off-by: Niklas S�derlund <niklas.soderlund+renesas@ragnatech.se>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> Reviewed-by: Ulrich Hecht <uli+renesas@fpond.eu>
> ---
> .../media/{renesas,rcar-csi2.txt => renesas,csi2.txt} | 0
> .../bindings/media/{rcar_vin.txt => renesas,vin.txt} | 0
> MAINTAINERS | 4 ++--
> 3 files changed, 2 insertions(+), 2 deletions(-)
> rename Documentation/devicetree/bindings/media/{renesas,rcar-csi2.txt => renesas,csi2.txt} (100%)
> rename Documentation/devicetree/bindings/media/{rcar_vin.txt => renesas,vin.txt} (100%)
>
> diff --git a/Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt b/Documentation/devicetree/bindings/media/renesas,csi2.txt
> similarity index 100%
> rename from Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt
> rename to Documentation/devicetree/bindings/media/renesas,csi2.txt
> diff --git a/Documentation/devicetree/bindings/media/rcar_vin.txt b/Documentation/devicetree/bindings/media/renesas,vin.txt
> similarity index 100%
> rename from Documentation/devicetree/bindings/media/rcar_vin.txt
> rename to Documentation/devicetree/bindings/media/renesas,vin.txt
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 6a3bac28ebb47830..a0d21ff13c8e8989 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -9807,8 +9807,8 @@ L: linux-media@vger.kernel.org
> L: linux-renesas-soc@vger.kernel.org
> T: git git://linuxtv.org/media_tree.git
> S: Supported
> -F: Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt
> -F: Documentation/devicetree/bindings/media/rcar_vin.txt
> +F: Documentation/devicetree/bindings/media/renesas,csi2.txt
> +F: Documentation/devicetree/bindings/media/renesas,vin.txt
> F: drivers/media/platform/rcar-vin/
>
> MEDIA DRIVERS FOR RENESAS - VSP1
> --
> 2.21.0
>
--
Regards,
Niklas S�derlund
^ permalink raw reply
* Re: [EXT] Re: [PATCH 00/10] Improvements and fixes for mxsfb DRM driver
From: Robert Chiras @ 2019-07-12 8:15 UTC (permalink / raw)
To: agx@sigxcpu.org
Cc: dl-linux-imx, marex@denx.de, robh+dt@kernel.org, stefan@agner.ch,
devicetree@vger.kernel.org, festevam@gmail.com, daniel@ffwll.ch,
mark.rutland@arm.com, dri-devel@lists.freedesktop.org,
shawnguo@kernel.org, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, airlied@linux.ie,
kernel@pengutronix.de, s.hauer@pengutronix.de
In-Reply-To: <20190711150403.GB23195@bogon.m.sigxcpu.org>
Hi Guido,
On Jo, 2019-07-11 at 17:04 +0200, Guido Günther wrote:
> Hi Robert,
> On Wed, Jun 26, 2019 at 04:32:08PM +0300, Robert Chiras wrote:
> >
> > This patch-set improves the use of eLCDIF block on iMX 8 SoCs (like
> > 8MQ, 8MM
> > and 8QXP). Following, are the new features added and fixes from
> > this
> > patch-set:
> >
> > 1. Add support for drm_bridge
> > On 8MQ and 8MM, the LCDIF block is not directly connected to a
> > parallel
> > display connector, where an LCD panel can be attached, but instead
> > it is
> > connected to DSI controller. Since this DSI stands between the
> > display
> > controller (eLCDIF) and the physical connector, the DSI can be
> > implemented
> > as a DRM bridge. So, in order to be able to connect the mxsfb
> > driver to
> > the DSI driver, the support for a drm_bridge was needed in mxsfb
> > DRM
> > driver (the actual driver for the eLCDIF block).
> So I wanted to test this but with both my somewhat cleaned up nwl
> driver¹ and the nwl driver forward ported from the nxp vendor tree
> I'm
> looking at a black screen with current mainline - while my dcss
> forward
> port gives me nice output on mipi dsi. Do you have a tree that uses
> mipi
> dsi on imx8mq where I could look at to check for differences?
Somewhere on the pixel path (between the display controller and the
DSI) there is a block that inverts the polarity. I can't remember
exactly what was the role of this block, but the polarity is inverted
when eLCDIF is used in combination with the DSI.
If you take a look at my DSI driver from NXP releases (I guess you have
them), you will see there is a hack in mode_fixup:
unsigned int *flags = &mode->flags;
if (dsi->sync_pol {
*flags |= DRM_MODE_FLAG_PHSYNC;
*flags |= DRM_MODE_FLAG_PVSYNC;
*flags &= ~DRM_MODE_FLAG_NHSYNC;
*flags &= ~DRM_MODE_FLAG_NVSYNC;
} else {
*flags &= ~DRM_MODE_FLAG_PHSYNC;
*flags &= ~DRM_MODE_FLAG_PVSYNC;
*flags |= DRM_MODE_FLAG_NHSYNC;
*flags |= DRM_MODE_FLAG_NVSYNC;
}
I know it's not clean, but it works for now. You can try this in your
driver and see if it helps.
These days I will also take your nwl-dsi driver and test it, and also
add support for bridge and eLCDIF to see if I can make it work.
Best regards,
Robert
>
> Cheers,
> -- Guido
>
> >
> >
> > 2. Add support for additional pixel formats
> > Some of the pixel formats needed by Android were not implemented in
> > this
> > driver, but they were actually supported. So, add support for them.
> >
> > 3. Add support for horizontal stride
> > Having support for horizontal stride allows the use of eLCDIF with
> > a GPU
> > (for example) that can only output resolution sizes multiple of a
> > power of
> > 8. For example, 1080 is not a power of 16, so in order to support
> > 1920x1080
> > output from GPUs that can produce linear buffers only in sizes
> > multiple to 16,
> > this feature is needed.
> >
> > 3. Few minor features and bug-fixing
> > The addition of max-res DT property was actually needed in order to
> > limit
> > the bandwidth usage of the eLCDIF block. This is need on systems
> > where
> > multiple display controllers are presend and the memory bandwidth
> > is not
> > enough to handle all of them at maximum capacity (like it is the
> > case on
> > 8MQ, where there are two display controllers: DCSS and eLCDIF).
> > The rest of the patches are bug-fixes.
> >
> > Mirela Rabulea (1):
> > drm/mxsfb: Signal mode changed when bpp changed
> >
> > Robert Chiras (9):
> > drm/mxsfb: Update mxsfb to support a bridge
> > drm/mxsfb: Update mxsfb with additional pixel formats
> > drm/mxsfb: Fix the vblank events
> > dt-bindings: display: Add max-res property for mxsfb
> > drm/mxsfb: Add max-res property for MXSFB
> > drm/mxsfb: Update mxsfb to support LCD reset
> > drm/mxsfb: Improve the axi clock usage
> > drm/mxsfb: Clear OUTSTANDING_REQS bits
> > drm/mxsfb: Add support for horizontal stride
> >
> > .../devicetree/bindings/display/mxsfb.txt | 6 +
> > drivers/gpu/drm/mxsfb/mxsfb_crtc.c | 290
> > ++++++++++++++++++---
> > drivers/gpu/drm/mxsfb/mxsfb_drv.c | 189
> > +++++++++++---
> > drivers/gpu/drm/mxsfb/mxsfb_drv.h | 10 +-
> > drivers/gpu/drm/mxsfb/mxsfb_out.c | 26 +-
> > drivers/gpu/drm/mxsfb/mxsfb_regs.h | 128 ++++++---
> > 6 files changed, 531 insertions(+), 118 deletions(-)
> >
> > --
> > 2.7.4
> >
> >
> > _______________________________________________
> > linux-arm-kernel mailing list
> > linux-arm-kernel@lists.infradead.org
> > https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fli
> > sts.infradead.org%2Fmailman%2Flistinfo%2Flinux-arm-
> > kernel&data=02%7C01%7Crobert.chiras%40nxp.com%7C7dc01a0bdf9245b
> > 8d87008d70611055b%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C6369
> > 84542481903425&sdata=ySInO6H1B4kJtJUwRs2uTIUve0SSNZF0s%2Bv%2FDU
> > 0Vy1E%3D&reserved=0
> >
> ¹ https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fl
> ists.freedesktop.org%2Farchives%2Fdri-devel%2F2019-
> March%2F209685.html&data=02%7C01%7Crobert.chiras%40nxp.com%7C7dc0
> 1a0bdf9245b8d87008d70611055b%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7
> C0%7C636984542481913416&sdata=ucYDQLiK7RalRF%2B5MeB3%2F76cFLGWa7C
> mxCFLEg4Wvqc%3D&reserved=0
^ permalink raw reply
* [PATCH v9 00/18] kunit: introduce KUnit, the Linux kernel unit testing framework
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
jpoimboe-H+wXaHxf7aLQT0dZR+AlfA, keescook-hpIqsD4AKlfQT0dZR+AlfA,
kieran.bingham-ryLnwIuWjnjg/C1BVhZhaw,
mcgrof-DgEjT+Ai2ygdnm+yROfE0A, peterz-wEGCiKHe2LqWVfeAwA7xHQ,
robh-DgEjT+Ai2ygdnm+yROfE0A, sboyd-DgEjT+Ai2ygdnm+yROfE0A,
shuah-DgEjT+Ai2ygdnm+yROfE0A, tytso-3s7WtUTddSA,
yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A
Cc: pmladek-IBi9RG/b67k, linux-doc-u79uwXL29TY76Z2rM5mHXA,
amir73il-Re5JQEeQqe8AvxtiuMwx3w, Brendan Higgins,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
Alexander.Levin-0li6OtcxBFHby3iVrkZq2A,
linux-kselftest-u79uwXL29TY76Z2rM5mHXA, Jonathan Corbet,
linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw,
khilman-rdvid1DuHRBWk0Htik3J/w, knut.omang-QHcLZuEGTsvQT0dZR+AlfA,
wfg-VuQAYsv1563Yd54FQh9/CA, joel-U3u1mxZcP9KHXe+LvDLADg,
rientjes-hpIqsD4AKlfQT0dZR+AlfA, Iurii Zaikin,
jdike-OPE4K8JWMJJBDgjK7y7TUQ,
dan.carpenter-QHcLZuEGTsvQT0dZR+AlfA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kbuild-u79uwXL29TY76Z2rM5mHXA, Tim.Bird-7U/KSKJipcs,
linux-um-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
rostedt-nx8X9YLhiw1AfugRpC6u6w, julia.lawall-L2FTfq7BK8M,
kunit-dev-/JYPxA39Uh5TLH3MbocFFw, Michal Marek,
richard-/L3Ra7n9ekc, rdunlap-wEGCiKHe2LqWVfeAwA7xHQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, daniel-/w4YWyX8dFk,
mpe-Gsx/Oe8HsFggBc27wqDAHg, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA
## TL;DR
This new patch set only contains a very minor change to address a sparse
warning in the PROC SYSCTL KUnit test. Otherwise this patchset is
identical to the previous.
As I mentioned in the previous patchset, all patches now have acks and
reviews.
## Background
This patch set proposes KUnit, a lightweight unit testing and mocking
framework for the Linux kernel.
Unlike Autotest and kselftest, KUnit is a true unit testing framework;
it does not require installing the kernel on a test machine or in a VM
(however, KUnit still allows you to run tests on test machines or in VMs
if you want[1]) and does not require tests to be written in userspace
running on a host kernel. Additionally, KUnit is fast: From invocation
to completion KUnit can run several dozen tests in about a second.
Currently, the entire KUnit test suite for KUnit runs in under a second
from the initial invocation (build time excluded).
KUnit is heavily inspired by JUnit, Python's unittest.mock, and
Googletest/Googlemock for C++. KUnit provides facilities for defining
unit test cases, grouping related test cases into test suites, providing
common infrastructure for running tests, mocking, spying, and much more.
### What's so special about unit testing?
A unit test is supposed to test a single unit of code in isolation,
hence the name. There should be no dependencies outside the control of
the test; this means no external dependencies, which makes tests orders
of magnitudes faster. Likewise, since there are no external dependencies,
there are no hoops to jump through to run the tests. Additionally, this
makes unit tests deterministic: a failing unit test always indicates a
problem. Finally, because unit tests necessarily have finer granularity,
they are able to test all code paths easily solving the classic problem
of difficulty in exercising error handling code.
### Is KUnit trying to replace other testing frameworks for the kernel?
No. Most existing tests for the Linux kernel are end-to-end tests, which
have their place. A well tested system has lots of unit tests, a
reasonable number of integration tests, and some end-to-end tests. KUnit
is just trying to address the unit test space which is currently not
being addressed.
### More information on KUnit
There is a bunch of documentation near the end of this patch set that
describes how to use KUnit and best practices for writing unit tests.
For convenience I am hosting the compiled docs here[2].
Additionally for convenience, I have applied these patches to a
branch[3]. The repo may be cloned with:
git clone https://kunit.googlesource.com/linux
This patchset is on the kunit/rfc/v5.2/v9 branch.
## Changes Since Last Version
Like I said in the TL;DR, there is only one minor change since the
previous revision. That change only affects patch 17/18; it addresses a
sparse warning in the PROC SYSCTL unit test.
Thanks to Masahiro for applying previous patches to a branch in his
kbuild tree and running sparse and other static analysis tools against
my patches.
[1] https://google.github.io/kunit-docs/third_party/kernel/docs/usage.html#kunit-on-non-uml-architectures
[2] https://google.github.io/kunit-docs/third_party/kernel/docs/
[3] https://kunit.googlesource.com/linux/+/kunit/rfc/v5.2/v9
--
2.22.0.410.gd8fdbe21b5-goog
^ permalink raw reply
* [PATCH v9 01/18] kunit: test: add KUnit test runner core
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
jpoimboe-H+wXaHxf7aLQT0dZR+AlfA, keescook-hpIqsD4AKlfQT0dZR+AlfA,
kieran.bingham-ryLnwIuWjnjg/C1BVhZhaw,
mcgrof-DgEjT+Ai2ygdnm+yROfE0A, peterz-wEGCiKHe2LqWVfeAwA7xHQ,
robh-DgEjT+Ai2ygdnm+yROfE0A, sboyd-DgEjT+Ai2ygdnm+yROfE0A,
shuah-DgEjT+Ai2ygdnm+yROfE0A, tytso-3s7WtUTddSA,
yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A
Cc: pmladek-IBi9RG/b67k, linux-doc-u79uwXL29TY76Z2rM5mHXA,
amir73il-Re5JQEeQqe8AvxtiuMwx3w, Brendan Higgins,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
Alexander.Levin-0li6OtcxBFHby3iVrkZq2A,
linux-kselftest-u79uwXL29TY76Z2rM5mHXA,
linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw,
khilman-rdvid1DuHRBWk0Htik3J/w, knut.omang-QHcLZuEGTsvQT0dZR+AlfA,
wfg-VuQAYsv1563Yd54FQh9/CA, joel-U3u1mxZcP9KHXe+LvDLADg,
rientjes-hpIqsD4AKlfQT0dZR+AlfA, jdike-OPE4K8JWMJJBDgjK7y7TUQ,
dan.carpenter-QHcLZuEGTsvQT0dZR+AlfA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kbuild-u79uwXL29TY76Z2rM5mHXA, Tim.Bird-7U/KSKJipcs,
linux-um-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
rostedt-nx8X9YLhiw1AfugRpC6u6w, julia.lawall-L2FTfq7BK8M,
kunit-dev-/JYPxA39Uh5TLH3MbocFFw, richard-/L3Ra7n9ekc,
rdunlap-wEGCiKHe2LqWVfeAwA7xHQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, daniel-/w4YWyX8dFk,
mpe-Gsx/Oe8HsFggBc27wqDAHg, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20190712081744.87097-1-brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Add core facilities for defining unit tests; this provides a common way
to define test cases, functions that execute code which is under test
and determine whether the code under test behaves as expected; this also
provides a way to group together related test cases in test suites (here
we call them test_modules).
Just define test cases and how to execute them for now; setting
expectations on code will be defined later.
Signed-off-by: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Reviewed-by: Greg Kroah-Hartman <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>
Reviewed-by: Logan Gunthorpe <logang-OTvnGxWRz7hWk0Htik3J/w@public.gmane.org>
Reviewed-by: Luis Chamberlain <mcgrof-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
include/kunit/test.h | 179 ++++++++++++++++++++++++++++++++++++++++
kunit/Kconfig | 17 ++++
kunit/Makefile | 1 +
kunit/test.c | 189 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 386 insertions(+)
create mode 100644 include/kunit/test.h
create mode 100644 kunit/Kconfig
create mode 100644 kunit/Makefile
create mode 100644 kunit/test.c
diff --git a/include/kunit/test.h b/include/kunit/test.h
new file mode 100644
index 0000000000000..e0b34acb9ee4e
--- /dev/null
+++ b/include/kunit/test.h
@@ -0,0 +1,179 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Base unit test (KUnit) API.
+ *
+ * Copyright (C) 2019, Google LLC.
+ * Author: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
+ */
+
+#ifndef _KUNIT_TEST_H
+#define _KUNIT_TEST_H
+
+#include <linux/types.h>
+
+struct kunit;
+
+/**
+ * struct kunit_case - represents an individual test case.
+ * @run_case: the function representing the actual test case.
+ * @name: the name of the test case.
+ *
+ * A test case is a function with the signature, ``void (*)(struct kunit *)``
+ * that makes expectations (see KUNIT_EXPECT_TRUE()) about code under test. Each
+ * test case is associated with a &struct kunit_suite and will be run after the
+ * suite's init function and followed by the suite's exit function.
+ *
+ * A test case should be static and should only be created with the KUNIT_CASE()
+ * macro; additionally, every array of test cases should be terminated with an
+ * empty test case.
+ *
+ * Example:
+ *
+ * .. code-block:: c
+ *
+ * void add_test_basic(struct kunit *test)
+ * {
+ * KUNIT_EXPECT_EQ(test, 1, add(1, 0));
+ * KUNIT_EXPECT_EQ(test, 2, add(1, 1));
+ * KUNIT_EXPECT_EQ(test, 0, add(-1, 1));
+ * KUNIT_EXPECT_EQ(test, INT_MAX, add(0, INT_MAX));
+ * KUNIT_EXPECT_EQ(test, -1, add(INT_MAX, INT_MIN));
+ * }
+ *
+ * static struct kunit_case example_test_cases[] = {
+ * KUNIT_CASE(add_test_basic),
+ * {}
+ * };
+ *
+ */
+struct kunit_case {
+ void (*run_case)(struct kunit *test);
+ const char *name;
+
+ /* private: internal use only. */
+ bool success;
+};
+
+/**
+ * KUNIT_CASE - A helper for creating a &struct kunit_case
+ * @test_name: a reference to a test case function.
+ *
+ * Takes a symbol for a function representing a test case and creates a
+ * &struct kunit_case object from it. See the documentation for
+ * &struct kunit_case for an example on how to use it.
+ */
+#define KUNIT_CASE(test_name) { .run_case = test_name, .name = #test_name }
+
+/**
+ * struct kunit_suite - describes a related collection of &struct kunit_case s.
+ * @name: the name of the test. Purely informational.
+ * @init: called before every test case.
+ * @exit: called after every test case.
+ * @test_cases: a null terminated array of test cases.
+ *
+ * A kunit_suite is a collection of related &struct kunit_case s, such that
+ * @init is called before every test case and @exit is called after every test
+ * case, similar to the notion of a *test fixture* or a *test class* in other
+ * unit testing frameworks like JUnit or Googletest.
+ *
+ * Every &struct kunit_case must be associated with a kunit_suite for KUnit to
+ * run it.
+ */
+struct kunit_suite {
+ const char name[256];
+ int (*init)(struct kunit *test);
+ void (*exit)(struct kunit *test);
+ struct kunit_case *test_cases;
+};
+
+/**
+ * struct kunit - represents a running instance of a test.
+ * @priv: for user to store arbitrary data. Commonly used to pass data created
+ * in the init function (see &struct kunit_suite).
+ *
+ * Used to store information about the current context under which the test is
+ * running. Most of this data is private and should only be accessed indirectly
+ * via public functions; the one exception is @priv which can be used by the
+ * test writer to store arbitrary data.
+ */
+struct kunit {
+ void *priv;
+
+ /* private: internal use only. */
+ const char *name; /* Read only after initialization! */
+ /*
+ * success starts as true, and may only be set to false during a test
+ * case; thus, it is safe to update this across multiple threads using
+ * WRITE_ONCE; however, as a consequence, it may only be read after the
+ * test case finishes once all threads associated with the test case
+ * have terminated.
+ */
+ bool success; /* Read only after test_case finishes! */
+};
+
+void kunit_init_test(struct kunit *test, const char *name);
+
+int kunit_run_tests(struct kunit_suite *suite);
+
+/**
+ * kunit_test_suite() - used to register a &struct kunit_suite with KUnit.
+ * @suite: a statically allocated &struct kunit_suite.
+ *
+ * Registers @suite with the test framework. See &struct kunit_suite for more
+ * information.
+ *
+ * NOTE: Currently KUnit tests are all run as late_initcalls; this means that
+ * they cannot test anything where tests must run at a different init phase. One
+ * significant restriction resulting from this is that KUnit cannot reliably
+ * test anything that is initialize in the late_init phase; another is that
+ * KUnit is useless to test things that need to be run in an earlier init phase.
+ */
+#define kunit_test_suite(suite) \
+ /*
+ * TODO(brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org): Don't run all KUnit tests as
+ * late_initcalls. I have some future work planned to dispatch
+ * all KUnit tests from the same place, and at the very least to
+ * do so after everything else is definitely initialized.
+ */ \
+ static int kunit_suite_init##suite(void) \
+ { \
+ return kunit_run_tests(&suite); \
+ } \
+ late_initcall(kunit_suite_init##suite)
+
+void __printf(3, 4) kunit_printk(const char *level,
+ const struct kunit *test,
+ const char *fmt, ...);
+
+/**
+ * kunit_info() - Prints an INFO level message associated with the current test.
+ * @test: The test context object.
+ * @fmt: A printk() style format string.
+ *
+ * Prints an info level message associated with the test suite being run. Takes
+ * a variable number of format parameters just like printk().
+ */
+#define kunit_info(test, fmt, ...) \
+ kunit_printk(KERN_INFO, test, fmt, ##__VA_ARGS__)
+
+/**
+ * kunit_warn() - Prints a WARN level message associated with the current test.
+ * @test: The test context object.
+ * @fmt: A printk() style format string.
+ *
+ * Prints a warning level message.
+ */
+#define kunit_warn(test, fmt, ...) \
+ kunit_printk(KERN_WARNING, test, fmt, ##__VA_ARGS__)
+
+/**
+ * kunit_err() - Prints an ERROR level message associated with the current test.
+ * @test: The test context object.
+ * @fmt: A printk() style format string.
+ *
+ * Prints an error level message.
+ */
+#define kunit_err(test, fmt, ...) \
+ kunit_printk(KERN_ERR, test, fmt, ##__VA_ARGS__)
+
+#endif /* _KUNIT_TEST_H */
diff --git a/kunit/Kconfig b/kunit/Kconfig
new file mode 100644
index 0000000000000..330ae83527c23
--- /dev/null
+++ b/kunit/Kconfig
@@ -0,0 +1,17 @@
+#
+# KUnit base configuration
+#
+
+menu "KUnit support"
+
+config KUNIT
+ bool "Enable support for unit tests (KUnit)"
+ help
+ Enables support for kernel unit tests (KUnit), a lightweight unit
+ testing and mocking framework for the Linux kernel. These tests are
+ able to be run locally on a developer's workstation without a VM or
+ special hardware when using UML. Can also be used on most other
+ architectures. For more information, please see
+ Documentation/dev-tools/kunit/.
+
+endmenu
diff --git a/kunit/Makefile b/kunit/Makefile
new file mode 100644
index 0000000000000..5efdc4dea2c08
--- /dev/null
+++ b/kunit/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_KUNIT) += test.o
diff --git a/kunit/test.c b/kunit/test.c
new file mode 100644
index 0000000000000..571e4c65deb5c
--- /dev/null
+++ b/kunit/test.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Base unit test (KUnit) API.
+ *
+ * Copyright (C) 2019, Google LLC.
+ * Author: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
+ */
+
+#include <linux/kernel.h>
+#include <kunit/test.h>
+
+static void kunit_set_failure(struct kunit *test)
+{
+ WRITE_ONCE(test->success, false);
+}
+
+static int kunit_vprintk_emit(int level, const char *fmt, va_list args)
+{
+ return vprintk_emit(0, level, NULL, 0, fmt, args);
+}
+
+static int kunit_printk_emit(int level, const char *fmt, ...)
+{
+ va_list args;
+ int ret;
+
+ va_start(args, fmt);
+ ret = kunit_vprintk_emit(level, fmt, args);
+ va_end(args);
+
+ return ret;
+}
+
+static void kunit_vprintk(const struct kunit *test,
+ const char *level,
+ struct va_format *vaf)
+{
+ kunit_printk_emit(level[1] - '0', "\t# %s: %pV", test->name, vaf);
+}
+
+static void kunit_print_tap_version(void)
+{
+ static bool kunit_has_printed_tap_version;
+
+ if (!kunit_has_printed_tap_version) {
+ kunit_printk_emit(LOGLEVEL_INFO, "TAP version 14\n");
+ kunit_has_printed_tap_version = true;
+ }
+}
+
+static size_t kunit_test_cases_len(struct kunit_case *test_cases)
+{
+ struct kunit_case *test_case;
+ size_t len = 0;
+
+ for (test_case = test_cases; test_case->run_case; test_case++)
+ len++;
+
+ return len;
+}
+
+static void kunit_print_subtest_start(struct kunit_suite *suite)
+{
+ kunit_print_tap_version();
+ kunit_printk_emit(LOGLEVEL_INFO, "\t# Subtest: %s\n", suite->name);
+ kunit_printk_emit(LOGLEVEL_INFO,
+ "\t1..%zd\n",
+ kunit_test_cases_len(suite->test_cases));
+}
+
+static void kunit_print_ok_not_ok(bool should_indent,
+ bool is_ok,
+ size_t test_number,
+ const char *description)
+{
+ const char *indent, *ok_not_ok;
+
+ if (should_indent)
+ indent = "\t";
+ else
+ indent = "";
+
+ if (is_ok)
+ ok_not_ok = "ok";
+ else
+ ok_not_ok = "not ok";
+
+ kunit_printk_emit(LOGLEVEL_INFO,
+ "%s%s %zd - %s\n",
+ indent, ok_not_ok, test_number, description);
+}
+
+static bool kunit_suite_has_succeeded(struct kunit_suite *suite)
+{
+ const struct kunit_case *test_case;
+
+ for (test_case = suite->test_cases; test_case->run_case; test_case++)
+ if (!test_case->success)
+ return false;
+
+ return true;
+}
+
+static void kunit_print_subtest_end(struct kunit_suite *suite)
+{
+ static size_t kunit_suite_counter = 1;
+
+ kunit_print_ok_not_ok(false,
+ kunit_suite_has_succeeded(suite),
+ kunit_suite_counter++,
+ suite->name);
+}
+
+static void kunit_print_test_case_ok_not_ok(struct kunit_case *test_case,
+ size_t test_number)
+{
+ kunit_print_ok_not_ok(true,
+ test_case->success,
+ test_number,
+ test_case->name);
+}
+
+void kunit_init_test(struct kunit *test, const char *name)
+{
+ test->name = name;
+ test->success = true;
+}
+
+/*
+ * Performs all logic to run a test case.
+ */
+static void kunit_run_case(struct kunit_suite *suite,
+ struct kunit_case *test_case)
+{
+ struct kunit test;
+ int ret = 0;
+
+ kunit_init_test(&test, test_case->name);
+
+ if (suite->init) {
+ ret = suite->init(&test);
+ if (ret) {
+ kunit_err(&test, "failed to initialize: %d\n", ret);
+ kunit_set_failure(&test);
+ return;
+ }
+ }
+
+ test_case->run_case(&test);
+
+ if (suite->exit)
+ suite->exit(&test);
+
+ test_case->success = test.success;
+}
+
+int kunit_run_tests(struct kunit_suite *suite)
+{
+ struct kunit_case *test_case;
+ size_t test_case_count = 1;
+
+ kunit_print_subtest_start(suite);
+
+ for (test_case = suite->test_cases; test_case->run_case; test_case++) {
+ kunit_run_case(suite, test_case);
+ kunit_print_test_case_ok_not_ok(test_case, test_case_count++);
+ }
+
+ kunit_print_subtest_end(suite);
+
+ return 0;
+}
+
+void kunit_printk(const char *level,
+ const struct kunit *test,
+ const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ kunit_vprintk(test, level, &vaf);
+
+ va_end(args);
+}
--
2.22.0.410.gd8fdbe21b5-goog
^ permalink raw reply related
* [PATCH v9 02/18] kunit: test: add test resource management API
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list, gregkh, jpoimboe, keescook, kieran.bingham, mcgrof,
peterz, robh, sboyd, shuah, tytso, yamada.masahiro
Cc: devicetree, dri-devel, kunit-dev, linux-doc, linux-fsdevel,
linux-kbuild, linux-kernel, linux-kselftest, linux-nvdimm,
linux-um, Alexander.Levin, Tim.Bird, amir73il, dan.carpenter,
daniel, jdike, joel, julia.lawall, khilman, knut.omang, logang,
mpe, pmladek, rdunlap, richard, rientjes, rostedt, wfg,
Brendan Higgins
In-Reply-To: <20190712081744.87097-1-brendanhiggins@google.com>
Create a common API for test managed resources like memory and test
objects. A lot of times a test will want to set up infrastructure to be
used in test cases; this could be anything from just wanting to allocate
some memory to setting up a driver stack; this defines facilities for
creating "test resources" which are managed by the test infrastructure
and are automatically cleaned up at the conclusion of the test.
Signed-off-by: Brendan Higgins <brendanhiggins@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
---
include/kunit/test.h | 116 +++++++++++++++++++++++++++++++++++++++++++
kunit/test.c | 94 +++++++++++++++++++++++++++++++++++
2 files changed, 210 insertions(+)
diff --git a/include/kunit/test.h b/include/kunit/test.h
index e0b34acb9ee4e..bdf41d31c343c 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -10,6 +10,70 @@
#define _KUNIT_TEST_H
#include <linux/types.h>
+#include <linux/slab.h>
+
+struct kunit_resource;
+
+typedef int (*kunit_resource_init_t)(struct kunit_resource *, void *);
+typedef void (*kunit_resource_free_t)(struct kunit_resource *);
+
+/**
+ * struct kunit_resource - represents a *test managed resource*
+ * @allocation: for the user to store arbitrary data.
+ * @free: a user supplied function to free the resource. Populated by
+ * kunit_alloc_resource().
+ *
+ * Represents a *test managed resource*, a resource which will automatically be
+ * cleaned up at the end of a test case.
+ *
+ * Example:
+ *
+ * .. code-block:: c
+ *
+ * struct kunit_kmalloc_params {
+ * size_t size;
+ * gfp_t gfp;
+ * };
+ *
+ * static int kunit_kmalloc_init(struct kunit_resource *res, void *context)
+ * {
+ * struct kunit_kmalloc_params *params = context;
+ * res->allocation = kmalloc(params->size, params->gfp);
+ *
+ * if (!res->allocation)
+ * return -ENOMEM;
+ *
+ * return 0;
+ * }
+ *
+ * static void kunit_kmalloc_free(struct kunit_resource *res)
+ * {
+ * kfree(res->allocation);
+ * }
+ *
+ * void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp)
+ * {
+ * struct kunit_kmalloc_params params;
+ * struct kunit_resource *res;
+ *
+ * params.size = size;
+ * params.gfp = gfp;
+ *
+ * res = kunit_alloc_resource(test, kunit_kmalloc_init,
+ * kunit_kmalloc_free, ¶ms);
+ * if (res)
+ * return res->allocation;
+ *
+ * return NULL;
+ * }
+ */
+struct kunit_resource {
+ void *allocation;
+ kunit_resource_free_t free;
+
+ /* private: internal use only. */
+ struct list_head node;
+};
struct kunit;
@@ -109,6 +173,13 @@ struct kunit {
* have terminated.
*/
bool success; /* Read only after test_case finishes! */
+ struct mutex lock; /* Gaurds all mutable test state. */
+ /*
+ * Because resources is a list that may be updated multiple times (with
+ * new resources) from any thread associated with a test case, we must
+ * protect it with some type of lock.
+ */
+ struct list_head resources; /* Protected by lock. */
};
void kunit_init_test(struct kunit *test, const char *name);
@@ -141,6 +212,51 @@ int kunit_run_tests(struct kunit_suite *suite);
} \
late_initcall(kunit_suite_init##suite)
+/**
+ * kunit_alloc_resource() - Allocates a *test managed resource*.
+ * @test: The test context object.
+ * @init: a user supplied function to initialize the resource.
+ * @free: a user supplied function to free the resource.
+ * @context: for the user to pass in arbitrary data to the init function.
+ *
+ * Allocates a *test managed resource*, a resource which will automatically be
+ * cleaned up at the end of a test case. See &struct kunit_resource for an
+ * example.
+ */
+struct kunit_resource *kunit_alloc_resource(struct kunit *test,
+ kunit_resource_init_t init,
+ kunit_resource_free_t free,
+ void *context);
+
+void kunit_free_resource(struct kunit *test, struct kunit_resource *res);
+
+/**
+ * kunit_kmalloc() - Like kmalloc() except the allocation is *test managed*.
+ * @test: The test context object.
+ * @size: The size in bytes of the desired memory.
+ * @gfp: flags passed to underlying kmalloc().
+ *
+ * Just like `kmalloc(...)`, except the allocation is managed by the test case
+ * and is automatically cleaned up after the test case concludes. See &struct
+ * kunit_resource for more information.
+ */
+void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp);
+
+/**
+ * kunit_kzalloc() - Just like kunit_kmalloc(), but zeroes the allocation.
+ * @test: The test context object.
+ * @size: The size in bytes of the desired memory.
+ * @gfp: flags passed to underlying kmalloc().
+ *
+ * See kzalloc() and kunit_kmalloc() for more information.
+ */
+static inline void *kunit_kzalloc(struct kunit *test, size_t size, gfp_t gfp)
+{
+ return kunit_kmalloc(test, size, gfp | __GFP_ZERO);
+}
+
+void kunit_cleanup(struct kunit *test);
+
void __printf(3, 4) kunit_printk(const char *level,
const struct kunit *test,
const char *fmt, ...);
diff --git a/kunit/test.c b/kunit/test.c
index 571e4c65deb5c..f165c9d8e10b0 100644
--- a/kunit/test.c
+++ b/kunit/test.c
@@ -122,6 +122,8 @@ static void kunit_print_test_case_ok_not_ok(struct kunit_case *test_case,
void kunit_init_test(struct kunit *test, const char *name)
{
+ mutex_init(&test->lock);
+ INIT_LIST_HEAD(&test->resources);
test->name = name;
test->success = true;
}
@@ -151,6 +153,8 @@ static void kunit_run_case(struct kunit_suite *suite,
if (suite->exit)
suite->exit(&test);
+ kunit_cleanup(&test);
+
test_case->success = test.success;
}
@@ -171,6 +175,96 @@ int kunit_run_tests(struct kunit_suite *suite)
return 0;
}
+struct kunit_resource *kunit_alloc_resource(struct kunit *test,
+ kunit_resource_init_t init,
+ kunit_resource_free_t free,
+ void *context)
+{
+ struct kunit_resource *res;
+ int ret;
+
+ res = kzalloc(sizeof(*res), GFP_KERNEL);
+ if (!res)
+ return NULL;
+
+ ret = init(res, context);
+ if (ret)
+ return NULL;
+
+ res->free = free;
+ mutex_lock(&test->lock);
+ list_add_tail(&res->node, &test->resources);
+ mutex_unlock(&test->lock);
+
+ return res;
+}
+
+void kunit_free_resource(struct kunit *test, struct kunit_resource *res)
+{
+ res->free(res);
+ list_del(&res->node);
+ kfree(res);
+}
+
+struct kunit_kmalloc_params {
+ size_t size;
+ gfp_t gfp;
+};
+
+static int kunit_kmalloc_init(struct kunit_resource *res, void *context)
+{
+ struct kunit_kmalloc_params *params = context;
+
+ res->allocation = kmalloc(params->size, params->gfp);
+ if (!res->allocation)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void kunit_kmalloc_free(struct kunit_resource *res)
+{
+ kfree(res->allocation);
+}
+
+void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp)
+{
+ struct kunit_kmalloc_params params;
+ struct kunit_resource *res;
+
+ params.size = size;
+ params.gfp = gfp;
+
+ res = kunit_alloc_resource(test,
+ kunit_kmalloc_init,
+ kunit_kmalloc_free,
+ ¶ms);
+
+ if (res)
+ return res->allocation;
+
+ return NULL;
+}
+
+void kunit_cleanup(struct kunit *test)
+{
+ struct kunit_resource *resource, *resource_safe;
+
+ mutex_lock(&test->lock);
+ /*
+ * test->resources is a stack - each allocation must be freed in the
+ * reverse order from which it was added since one resource may depend
+ * on another for its entire lifetime.
+ */
+ list_for_each_entry_safe_reverse(resource,
+ resource_safe,
+ &test->resources,
+ node) {
+ kunit_free_resource(test, resource);
+ }
+ mutex_unlock(&test->lock);
+}
+
void kunit_printk(const char *level,
const struct kunit *test,
const char *fmt, ...)
--
2.22.0.410.gd8fdbe21b5-goog
^ permalink raw reply related
* [PATCH v9 03/18] kunit: test: add string_stream a std::stream like string builder
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list, gregkh, jpoimboe, keescook, kieran.bingham, mcgrof,
peterz, robh, sboyd, shuah, tytso, yamada.masahiro
Cc: pmladek, linux-doc, amir73il, Brendan Higgins, dri-devel,
Alexander.Levin, linux-kselftest, linux-nvdimm, khilman,
knut.omang, wfg, joel, rientjes, jdike, dan.carpenter, devicetree,
linux-kbuild, Tim.Bird, linux-um, rostedt, julia.lawall,
kunit-dev, richard, rdunlap, linux-kernel, mpe, linux-fsdevel,
logang
In-Reply-To: <20190712081744.87097-1-brendanhiggins@google.com>
A number of test features need to do pretty complicated string printing
where it may not be possible to rely on a single preallocated string
with parameters.
So provide a library for constructing the string as you go similar to
C++'s std::string.
Signed-off-by: Brendan Higgins <brendanhiggins@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
---
include/kunit/string-stream.h | 49 ++++++++++++
kunit/Makefile | 3 +-
kunit/string-stream.c | 147 ++++++++++++++++++++++++++++++++++
3 files changed, 198 insertions(+), 1 deletion(-)
create mode 100644 include/kunit/string-stream.h
create mode 100644 kunit/string-stream.c
diff --git a/include/kunit/string-stream.h b/include/kunit/string-stream.h
new file mode 100644
index 0000000000000..0552a05781afe
--- /dev/null
+++ b/include/kunit/string-stream.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * C++ stream style string builder used in KUnit for building messages.
+ *
+ * Copyright (C) 2019, Google LLC.
+ * Author: Brendan Higgins <brendanhiggins@google.com>
+ */
+
+#ifndef _KUNIT_STRING_STREAM_H
+#define _KUNIT_STRING_STREAM_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/kref.h>
+#include <stdarg.h>
+
+struct string_stream_fragment {
+ struct list_head node;
+ char *fragment;
+};
+
+struct string_stream {
+ size_t length;
+ struct list_head fragments;
+ /* length and fragments are protected by this lock */
+ spinlock_t lock;
+};
+
+struct kunit;
+
+struct string_stream *alloc_string_stream(struct kunit *test);
+
+void string_stream_get(struct string_stream *stream);
+
+int string_stream_put(struct string_stream *stream);
+
+int string_stream_add(struct string_stream *stream, const char *fmt, ...);
+
+int string_stream_vadd(struct string_stream *stream,
+ const char *fmt,
+ va_list args);
+
+char *string_stream_get_string(struct string_stream *stream);
+
+void string_stream_clear(struct string_stream *stream);
+
+bool string_stream_is_empty(struct string_stream *stream);
+
+#endif /* _KUNIT_STRING_STREAM_H */
diff --git a/kunit/Makefile b/kunit/Makefile
index 5efdc4dea2c08..275b565a0e81f 100644
--- a/kunit/Makefile
+++ b/kunit/Makefile
@@ -1 +1,2 @@
-obj-$(CONFIG_KUNIT) += test.o
+obj-$(CONFIG_KUNIT) += test.o \
+ string-stream.o
diff --git a/kunit/string-stream.c b/kunit/string-stream.c
new file mode 100644
index 0000000000000..0463a92dad74b
--- /dev/null
+++ b/kunit/string-stream.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * C++ stream style string builder used in KUnit for building messages.
+ *
+ * Copyright (C) 2019, Google LLC.
+ * Author: Brendan Higgins <brendanhiggins@google.com>
+ */
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <kunit/string-stream.h>
+#include <kunit/test.h>
+
+int string_stream_vadd(struct string_stream *stream,
+ const char *fmt,
+ va_list args)
+{
+ struct string_stream_fragment *frag_container;
+ int len;
+ va_list args_for_counting;
+ unsigned long flags;
+
+ /* Make a copy because `vsnprintf` could change it */
+ va_copy(args_for_counting, args);
+
+ /* Need space for null byte. */
+ len = vsnprintf(NULL, 0, fmt, args_for_counting) + 1;
+
+ va_end(args_for_counting);
+
+ frag_container = kmalloc(sizeof(*frag_container), GFP_KERNEL);
+ if (!frag_container)
+ return -ENOMEM;
+
+ frag_container->fragment = kmalloc(len, GFP_KERNEL);
+ if (!frag_container->fragment) {
+ kfree(frag_container);
+ return -ENOMEM;
+ }
+
+ len = vsnprintf(frag_container->fragment, len, fmt, args);
+ spin_lock_irqsave(&stream->lock, flags);
+ stream->length += len;
+ list_add_tail(&frag_container->node, &stream->fragments);
+ spin_unlock_irqrestore(&stream->lock, flags);
+
+ return 0;
+}
+
+int string_stream_add(struct string_stream *stream, const char *fmt, ...)
+{
+ va_list args;
+ int result;
+
+ va_start(args, fmt);
+ result = string_stream_vadd(stream, fmt, args);
+ va_end(args);
+
+ return result;
+}
+
+void string_stream_clear(struct string_stream *stream)
+{
+ struct string_stream_fragment *frag_container, *frag_container_safe;
+ unsigned long flags;
+
+ spin_lock_irqsave(&stream->lock, flags);
+ list_for_each_entry_safe(frag_container,
+ frag_container_safe,
+ &stream->fragments,
+ node) {
+ list_del(&frag_container->node);
+ kfree(frag_container->fragment);
+ kfree(frag_container);
+ }
+ stream->length = 0;
+ spin_unlock_irqrestore(&stream->lock, flags);
+}
+
+char *string_stream_get_string(struct string_stream *stream)
+{
+ struct string_stream_fragment *frag_container;
+ size_t buf_len = stream->length + 1; /* +1 for null byte. */
+ char *buf;
+ unsigned long flags;
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ spin_lock_irqsave(&stream->lock, flags);
+ list_for_each_entry(frag_container, &stream->fragments, node)
+ strlcat(buf, frag_container->fragment, buf_len);
+ spin_unlock_irqrestore(&stream->lock, flags);
+
+ return buf;
+}
+
+bool string_stream_is_empty(struct string_stream *stream)
+{
+ bool is_empty;
+ unsigned long flags;
+
+ spin_lock_irqsave(&stream->lock, flags);
+ is_empty = list_empty(&stream->fragments);
+ spin_unlock_irqrestore(&stream->lock, flags);
+
+ return is_empty;
+}
+
+static int string_stream_init(struct kunit_resource *res, void *context)
+{
+ struct string_stream *stream;
+
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (!stream)
+ return -ENOMEM;
+
+ res->allocation = stream;
+ INIT_LIST_HEAD(&stream->fragments);
+ spin_lock_init(&stream->lock);
+
+ return 0;
+}
+
+static void string_stream_free(struct kunit_resource *res)
+{
+ struct string_stream *stream = res->allocation;
+
+ string_stream_clear(stream);
+ kfree(stream);
+}
+
+struct string_stream *alloc_string_stream(struct kunit *test)
+{
+ struct kunit_resource *res;
+
+ res = kunit_alloc_resource(test,
+ string_stream_init,
+ string_stream_free,
+ NULL);
+
+ if (!res)
+ return NULL;
+
+ return res->allocation;
+}
--
2.22.0.410.gd8fdbe21b5-goog
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v9 04/18] kunit: test: add kunit_stream a std::stream like logger
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list, gregkh, jpoimboe, keescook, kieran.bingham, mcgrof,
peterz, robh, sboyd, shuah, tytso, yamada.masahiro
Cc: pmladek, linux-doc, amir73il, Brendan Higgins, dri-devel,
Alexander.Levin, linux-kselftest, linux-nvdimm, khilman,
knut.omang, wfg, joel, rientjes, jdike, dan.carpenter, devicetree,
linux-kbuild, Tim.Bird, linux-um, rostedt, julia.lawall,
kunit-dev, richard, rdunlap, linux-kernel, mpe, linux-fsdevel,
logang
In-Reply-To: <20190712081744.87097-1-brendanhiggins@google.com>
A lot of the expectation and assertion infrastructure prints out fairly
complicated test failure messages, so add a C++ style log library for
for logging test results.
Signed-off-by: Brendan Higgins <brendanhiggins@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
---
include/kunit/kunit-stream.h | 81 +++++++++++++++++++++++
include/kunit/test.h | 3 +
kunit/Makefile | 3 +-
kunit/kunit-stream.c | 123 +++++++++++++++++++++++++++++++++++
kunit/test.c | 6 ++
5 files changed, 215 insertions(+), 1 deletion(-)
create mode 100644 include/kunit/kunit-stream.h
create mode 100644 kunit/kunit-stream.c
diff --git a/include/kunit/kunit-stream.h b/include/kunit/kunit-stream.h
new file mode 100644
index 0000000000000..a7b53eabf6be4
--- /dev/null
+++ b/include/kunit/kunit-stream.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * C++ stream style string formatter and printer used in KUnit for outputting
+ * KUnit messages.
+ *
+ * Copyright (C) 2019, Google LLC.
+ * Author: Brendan Higgins <brendanhiggins@google.com>
+ */
+
+#ifndef _KUNIT_KUNIT_STREAM_H
+#define _KUNIT_KUNIT_STREAM_H
+
+#include <linux/types.h>
+#include <kunit/string-stream.h>
+
+struct kunit;
+
+/**
+ * struct kunit_stream - a std::stream style string builder.
+ *
+ * A std::stream style string builder. Allows messages to be built up and
+ * printed all at once.
+ */
+struct kunit_stream {
+ /* private: internal use only. */
+ struct kunit *test;
+ const char *level;
+ struct string_stream *internal_stream;
+};
+
+/**
+ * alloc_kunit_stream() - constructs a new &struct kunit_stream.
+ * @test: The test context object.
+ * @level: The log level at which to print out the message.
+ *
+ * Constructs a new test managed &struct kunit_stream.
+ */
+struct kunit_stream *alloc_kunit_stream(struct kunit *test, const char *level);
+
+/**
+ * kunit_stream_add(): adds the formatted input to the internal buffer.
+ * @kstream: the stream being operated on.
+ * @fmt: printf style format string to append to stream.
+ *
+ * Appends the formatted string, @fmt, to the internal buffer.
+ */
+void __printf(2, 3) kunit_stream_add(struct kunit_stream *kstream,
+ const char *fmt, ...);
+
+/**
+ * kunit_stream_append(): appends the contents of @other to @kstream.
+ * @kstream: the stream to which @other is appended.
+ * @other: the stream whose contents are appended to @kstream.
+ *
+ * Appends the contents of @other to @kstream.
+ */
+void kunit_stream_append(struct kunit_stream *kstream,
+ struct kunit_stream *other);
+
+/**
+ * kunit_stream_commit(): prints out the internal buffer to the user.
+ * @kstream: the stream being operated on.
+ *
+ * Outputs the contents of the internal buffer as a kunit_printk formatted
+ * output. KUNIT_STREAM ONLY OUTPUTS ITS BUFFER TO THE USER IF COMMIT IS
+ * CALLED!!! The reason for this is that it allows us to construct a message
+ * before we know whether we want to print it out; this can be extremely handy
+ * if there is information you might need for a failure message that is easiest
+ * to collect in the steps leading up to the actual check.
+ */
+void kunit_stream_commit(struct kunit_stream *kstream);
+
+/**
+ * kunit_stream_clear(): clears the internal buffer.
+ * @kstream: the stream being operated on.
+ *
+ * Clears the contents of the internal buffer.
+ */
+void kunit_stream_clear(struct kunit_stream *kstream);
+
+#endif /* _KUNIT_KUNIT_STREAM_H */
diff --git a/include/kunit/test.h b/include/kunit/test.h
index bdf41d31c343c..bc7dbdcf8abab 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -11,6 +11,7 @@
#include <linux/types.h>
#include <linux/slab.h>
+#include <kunit/kunit-stream.h>
struct kunit_resource;
@@ -184,6 +185,8 @@ struct kunit {
void kunit_init_test(struct kunit *test, const char *name);
+void kunit_fail(struct kunit *test, struct kunit_stream *stream);
+
int kunit_run_tests(struct kunit_suite *suite);
/**
diff --git a/kunit/Makefile b/kunit/Makefile
index 275b565a0e81f..6ddc622ee6b1c 100644
--- a/kunit/Makefile
+++ b/kunit/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_KUNIT) += test.o \
- string-stream.o
+ string-stream.o \
+ kunit-stream.o
diff --git a/kunit/kunit-stream.c b/kunit/kunit-stream.c
new file mode 100644
index 0000000000000..8bea1f22eafb5
--- /dev/null
+++ b/kunit/kunit-stream.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * C++ stream style string formatter and printer used in KUnit for outputting
+ * KUnit messages.
+ *
+ * Copyright (C) 2019, Google LLC.
+ * Author: Brendan Higgins <brendanhiggins@google.com>
+ */
+
+#include <kunit/test.h>
+#include <kunit/kunit-stream.h>
+#include <kunit/string-stream.h>
+
+void kunit_stream_add(struct kunit_stream *kstream, const char *fmt, ...)
+{
+ va_list args;
+ struct string_stream *stream = kstream->internal_stream;
+
+ va_start(args, fmt);
+
+ if (string_stream_vadd(stream, fmt, args) < 0)
+ kunit_err(kstream->test,
+ "Failed to allocate fragment: %s\n",
+ fmt);
+
+ va_end(args);
+}
+
+void kunit_stream_append(struct kunit_stream *kstream,
+ struct kunit_stream *other)
+{
+ struct string_stream *other_stream = other->internal_stream;
+ const char *other_content;
+
+ other_content = string_stream_get_string(other_stream);
+
+ if (!other_content) {
+ kunit_err(kstream->test,
+ "Failed to get string from second argument for appending\n");
+ return;
+ }
+
+ kunit_stream_add(kstream, other_content);
+}
+
+void kunit_stream_clear(struct kunit_stream *kstream)
+{
+ string_stream_clear(kstream->internal_stream);
+}
+
+void kunit_stream_commit(struct kunit_stream *kstream)
+{
+ struct string_stream *stream = kstream->internal_stream;
+ struct string_stream_fragment *fragment;
+ struct kunit *test = kstream->test;
+ char *buf;
+
+ buf = string_stream_get_string(stream);
+ if (!buf) {
+ kunit_err(test,
+ "Could not allocate buffer, dumping stream:\n");
+ list_for_each_entry(fragment, &stream->fragments, node) {
+ kunit_err(test, fragment->fragment);
+ }
+ kunit_err(test, "\n");
+ goto cleanup;
+ }
+
+ kunit_printk(kstream->level, test, buf);
+ kfree(buf);
+
+cleanup:
+ kunit_stream_clear(kstream);
+}
+
+static int kunit_stream_init(struct kunit_resource *res, void *context)
+{
+ struct kunit *test = context;
+ struct kunit_stream *stream;
+
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (!stream)
+ return -ENOMEM;
+
+ res->allocation = stream;
+ stream->test = test;
+ stream->internal_stream = alloc_string_stream(test);
+
+ if (!stream->internal_stream)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void kunit_stream_free(struct kunit_resource *res)
+{
+ struct kunit_stream *stream = res->allocation;
+
+ if (!string_stream_is_empty(stream->internal_stream)) {
+ kunit_err(stream->test,
+ "End of test case reached with uncommitted stream entries\n");
+ kunit_stream_commit(stream);
+ }
+}
+
+struct kunit_stream *alloc_kunit_stream(struct kunit *test, const char *level)
+{
+ struct kunit_stream *kstream;
+ struct kunit_resource *res;
+
+ res = kunit_alloc_resource(test,
+ kunit_stream_init,
+ kunit_stream_free,
+ test);
+
+ if (!res)
+ return NULL;
+
+ kstream = res->allocation;
+ kstream->level = level;
+
+ return kstream;
+}
diff --git a/kunit/test.c b/kunit/test.c
index f165c9d8e10b0..29edf34a89a37 100644
--- a/kunit/test.c
+++ b/kunit/test.c
@@ -120,6 +120,12 @@ static void kunit_print_test_case_ok_not_ok(struct kunit_case *test_case,
test_case->name);
}
+void kunit_fail(struct kunit *test, struct kunit_stream *stream)
+{
+ kunit_set_failure(test);
+ kunit_stream_commit(stream);
+}
+
void kunit_init_test(struct kunit *test, const char *name)
{
mutex_init(&test->lock);
--
2.22.0.410.gd8fdbe21b5-goog
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v9 05/18] kunit: test: add the concept of expectations
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
jpoimboe-H+wXaHxf7aLQT0dZR+AlfA, keescook-hpIqsD4AKlfQT0dZR+AlfA,
kieran.bingham-ryLnwIuWjnjg/C1BVhZhaw,
mcgrof-DgEjT+Ai2ygdnm+yROfE0A, peterz-wEGCiKHe2LqWVfeAwA7xHQ,
robh-DgEjT+Ai2ygdnm+yROfE0A, sboyd-DgEjT+Ai2ygdnm+yROfE0A,
shuah-DgEjT+Ai2ygdnm+yROfE0A, tytso-3s7WtUTddSA,
yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A
Cc: pmladek-IBi9RG/b67k, linux-doc-u79uwXL29TY76Z2rM5mHXA,
amir73il-Re5JQEeQqe8AvxtiuMwx3w, Brendan Higgins,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
Alexander.Levin-0li6OtcxBFHby3iVrkZq2A,
linux-kselftest-u79uwXL29TY76Z2rM5mHXA,
linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw,
khilman-rdvid1DuHRBWk0Htik3J/w, knut.omang-QHcLZuEGTsvQT0dZR+AlfA,
wfg-VuQAYsv1563Yd54FQh9/CA, joel-U3u1mxZcP9KHXe+LvDLADg,
rientjes-hpIqsD4AKlfQT0dZR+AlfA, jdike-OPE4K8JWMJJBDgjK7y7TUQ,
dan.carpenter-QHcLZuEGTsvQT0dZR+AlfA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kbuild-u79uwXL29TY76Z2rM5mHXA, Tim.Bird-7U/KSKJipcs,
linux-um-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
rostedt-nx8X9YLhiw1AfugRpC6u6w, julia.lawall-L2FTfq7BK8M,
kunit-dev-/JYPxA39Uh5TLH3MbocFFw, richard-/L3Ra7n9ekc,
rdunlap-wEGCiKHe2LqWVfeAwA7xHQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, daniel-/w4YWyX8dFk,
mpe-Gsx/Oe8HsFggBc27wqDAHg, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20190712081744.87097-1-brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Add support for expectations, which allow properties to be specified and
then verified in tests.
Signed-off-by: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Reviewed-by: Greg Kroah-Hartman <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>
Reviewed-by: Logan Gunthorpe <logang-OTvnGxWRz7hWk0Htik3J/w@public.gmane.org>
---
include/kunit/test.h | 525 +++++++++++++++++++++++++++++++++++++++++++
kunit/test.c | 66 ++++++
2 files changed, 591 insertions(+)
diff --git a/include/kunit/test.h b/include/kunit/test.h
index bc7dbdcf8abab..df18765e6ea25 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -9,6 +9,7 @@
#ifndef _KUNIT_TEST_H
#define _KUNIT_TEST_H
+#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <kunit/kunit-stream.h>
@@ -295,4 +296,528 @@ void __printf(3, 4) kunit_printk(const char *level,
#define kunit_err(test, fmt, ...) \
kunit_printk(KERN_ERR, test, fmt, ##__VA_ARGS__)
+/*
+ * Generates a compile-time warning in case of comparing incompatible types.
+ */
+#define __kunit_typecheck(lhs, rhs) \
+ ((void) __typecheck(lhs, rhs))
+
+static inline struct kunit_stream *kunit_expect_start(struct kunit *test,
+ const char *file,
+ const char *line)
+{
+ struct kunit_stream *stream = alloc_kunit_stream(test, KERN_ERR);
+
+ kunit_stream_add(stream, "EXPECTATION FAILED at %s:%s\n\t", file, line);
+
+ return stream;
+}
+
+static inline void kunit_expect_end(struct kunit *test,
+ bool success,
+ struct kunit_stream *stream)
+{
+ if (!success)
+ kunit_fail(test, stream);
+ else
+ kunit_stream_clear(stream);
+}
+
+#define KUNIT_EXPECT_START(test) \
+ kunit_expect_start(test, __FILE__, __stringify(__LINE__))
+
+#define KUNIT_EXPECT_END(test, success, stream) \
+ kunit_expect_end(test, success, stream)
+
+#define KUNIT_EXPECT_MSG(test, success, message, fmt, ...) do { \
+ struct kunit_stream *__stream = KUNIT_EXPECT_START(test); \
+ \
+ kunit_stream_add(__stream, message); \
+ kunit_stream_add(__stream, fmt, ##__VA_ARGS__); \
+ KUNIT_EXPECT_END(test, success, __stream); \
+} while (0)
+
+#define KUNIT_EXPECT(test, success, message) do { \
+ struct kunit_stream *__stream = KUNIT_EXPECT_START(test); \
+ \
+ kunit_stream_add(__stream, message); \
+ KUNIT_EXPECT_END(test, success, __stream); \
+} while (0)
+
+/**
+ * KUNIT_SUCCEED() - A no-op expectation. Only exists for code clarity.
+ * @test: The test context object.
+ *
+ * The opposite of KUNIT_FAIL(), it is an expectation that cannot fail. In other
+ * words, it does nothing and only exists for code clarity. See
+ * KUNIT_EXPECT_TRUE() for more information.
+ */
+#define KUNIT_SUCCEED(test) do {} while (0)
+
+/**
+ * KUNIT_FAIL() - Always causes a test to fail when evaluated.
+ * @test: The test context object.
+ * @fmt: an informational message to be printed when the assertion is made.
+ * @...: string format arguments.
+ *
+ * The opposite of KUNIT_SUCCEED(), it is an expectation that always fails. In
+ * other words, it always results in a failed expectation, and consequently
+ * always causes the test case to fail when evaluated. See KUNIT_EXPECT_TRUE()
+ * for more information.
+ */
+#define KUNIT_FAIL(test, fmt, ...) do { \
+ struct kunit_stream *__stream = KUNIT_EXPECT_START(test); \
+ \
+ kunit_stream_add(__stream, fmt, ##__VA_ARGS__); \
+ KUNIT_EXPECT_END(test, false, __stream); \
+} while (0)
+
+/**
+ * KUNIT_EXPECT_TRUE() - Causes a test failure when the expression is not true.
+ * @test: The test context object.
+ * @condition: an arbitrary boolean expression. The test fails when this does
+ * not evaluate to true.
+ *
+ * This and expectations of the form `KUNIT_EXPECT_*` will cause the test case
+ * to fail when the specified condition is not met; however, it will not prevent
+ * the test case from continuing to run; this is otherwise known as an
+ * *expectation failure*.
+ */
+#define KUNIT_EXPECT_TRUE(test, condition) \
+ KUNIT_EXPECT(test, (condition), \
+ "Expected " #condition " is true, but is false\n")
+
+#define KUNIT_EXPECT_TRUE_MSG(test, condition, fmt, ...) \
+ KUNIT_EXPECT_MSG(test, (condition), \
+ "Expected " #condition " is true, but is false\n",\
+ fmt, ##__VA_ARGS__)
+
+/**
+ * KUNIT_EXPECT_FALSE() - Makes a test failure when the expression is not false.
+ * @test: The test context object.
+ * @condition: an arbitrary boolean expression. The test fails when this does
+ * not evaluate to false.
+ *
+ * Sets an expectation that @condition evaluates to false. See
+ * KUNIT_EXPECT_TRUE() for more information.
+ */
+#define KUNIT_EXPECT_FALSE(test, condition) \
+ KUNIT_EXPECT(test, !(condition), \
+ "Expected " #condition " is false, but is true\n")
+
+#define KUNIT_EXPECT_FALSE_MSG(test, condition, fmt, ...) \
+ KUNIT_EXPECT_MSG(test, !(condition), \
+ "Expected " #condition " is false, but is true\n",\
+ fmt, ##__VA_ARGS__)
+
+void kunit_expect_binary_msg(struct kunit *test,
+ long long left, const char *left_name,
+ long long right, const char *right_name,
+ bool compare_result,
+ const char *compare_name,
+ const char *file,
+ const char *line,
+ const char *fmt, ...);
+
+static inline void kunit_expect_binary(struct kunit *test,
+ long long left, const char *left_name,
+ long long right, const char *right_name,
+ bool compare_result,
+ const char *compare_name,
+ const char *file,
+ const char *line)
+{
+ kunit_expect_binary_msg(test,
+ left, left_name,
+ right, right_name,
+ compare_result,
+ compare_name,
+ file,
+ line,
+ NULL);
+}
+
+void kunit_expect_ptr_binary_msg(struct kunit *test,
+ void *left, const char *left_name,
+ void *right, const char *right_name,
+ bool compare_result,
+ const char *compare_name,
+ const char *file,
+ const char *line,
+ const char *fmt, ...);
+
+static inline void kunit_expect_ptr_binary(struct kunit *test,
+ void *left, const char *left_name,
+ void *right, const char *right_name,
+ bool compare_result,
+ const char *compare_name,
+ const char *file,
+ const char *line)
+{
+ kunit_expect_ptr_binary_msg(test,
+ left, left_name,
+ right, right_name,
+ compare_result,
+ compare_name,
+ file,
+ line,
+ NULL);
+}
+
+/*
+ * A factory macro for defining the expectations for the basic comparisons
+ * defined for the built in types.
+ *
+ * Unfortunately, there is no common type that all types can be promoted to for
+ * which all the binary operators behave the same way as for the actual types
+ * (for example, there is no type that long long and unsigned long long can
+ * both be cast to where the comparison result is preserved for all values). So
+ * the best we can do is do the comparison in the original types and then coerce
+ * everything to long long for printing; this way, the comparison behaves
+ * correctly and the printed out value usually makes sense without
+ * interpretation, but can always be interpretted to figure out the actual
+ * value.
+ */
+#define KUNIT_EXPECT_BINARY(test, left, condition, right) do { \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ __kunit_typecheck(__left, __right); \
+ kunit_expect_binary(test, \
+ (long long) __left, #left, \
+ (long long) __right, #right, \
+ __left condition __right, #condition, \
+ __FILE__, __stringify(__LINE__)); \
+} while (0)
+
+#define KUNIT_EXPECT_BINARY_MSG(test, left, condition, right, fmt, ...) do { \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ __kunit_typecheck(__left, __right); \
+ kunit_expect_binary_msg(test, \
+ (long long) __left, #left, \
+ (long long) __right, #right, \
+ __left condition __right, #condition, \
+ __FILE__, __stringify(__LINE__), \
+ fmt, ##__VA_ARGS__); \
+} while (0)
+
+/*
+ * Just like KUNIT_EXPECT_BINARY, but for comparing pointer types.
+ */
+#define KUNIT_EXPECT_PTR_BINARY(test, left, condition, right) do { \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ __kunit_typecheck(__left, __right); \
+ kunit_expect_ptr_binary(test, \
+ (void *) __left, #left, \
+ (void *) __right, #right, \
+ __left condition __right, #condition, \
+ __FILE__, __stringify(__LINE__)); \
+} while (0)
+
+#define KUNIT_EXPECT_PTR_BINARY_MSG(test, left, condition, right, fmt, ...) \
+do { \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ __kunit_typecheck(__left, __right); \
+ kunit_expect_ptr_binary_msg(test, \
+ (void *) __left, #left, \
+ (void *) __right, #right, \
+ __left condition __right, #condition, \
+ __FILE__, __stringify(__LINE__), \
+ fmt, ##__VA_ARGS__); \
+} while (0)
+
+/**
+ * KUNIT_EXPECT_EQ() - Sets an expectation that @left and @right are equal.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a primitive C type.
+ * @right: an arbitrary expression that evaluates to a primitive C type.
+ *
+ * Sets an expectation that the values that @left and @right evaluate to are
+ * equal. This is semantically equivalent to
+ * KUNIT_EXPECT_TRUE(@test, (@left) == (@right)). See KUNIT_EXPECT_TRUE() for
+ * more information.
+ */
+#define KUNIT_EXPECT_EQ(test, left, right) \
+ KUNIT_EXPECT_BINARY(test, left, ==, right)
+
+#define KUNIT_EXPECT_EQ_MSG(test, left, right, fmt, ...) \
+ KUNIT_EXPECT_BINARY_MSG(test, \
+ left, \
+ ==, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
+ * KUNIT_EXPECT_PTR_EQ() - Expects that pointers @left and @right are equal.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a pointer.
+ * @right: an arbitrary expression that evaluates to a pointer.
+ *
+ * Sets an expectation that the values that @left and @right evaluate to are
+ * equal. This is semantically equivalent to
+ * KUNIT_EXPECT_TRUE(@test, (@left) == (@right)). See KUNIT_EXPECT_TRUE() for
+ * more information.
+ */
+#define KUNIT_EXPECT_PTR_EQ(test, left, right) \
+ KUNIT_EXPECT_PTR_BINARY(test, left, ==, right)
+
+#define KUNIT_EXPECT_PTR_EQ_MSG(test, left, right, fmt, ...) \
+ KUNIT_EXPECT_PTR_BINARY_MSG(test, \
+ left, \
+ ==, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
+ * KUNIT_EXPECT_NE() - An expectation that @left and @right are not equal.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a primitive C type.
+ * @right: an arbitrary expression that evaluates to a primitive C type.
+ *
+ * Sets an expectation that the values that @left and @right evaluate to are not
+ * equal. This is semantically equivalent to
+ * KUNIT_EXPECT_TRUE(@test, (@left) != (@right)). See KUNIT_EXPECT_TRUE() for
+ * more information.
+ */
+#define KUNIT_EXPECT_NE(test, left, right) \
+ KUNIT_EXPECT_BINARY(test, left, !=, right)
+
+#define KUNIT_EXPECT_NE_MSG(test, left, right, fmt, ...) \
+ KUNIT_EXPECT_BINARY_MSG(test, \
+ left, \
+ !=, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
+ * KUNIT_EXPECT_PTR_NE() - Expects that pointers @left and @right are not equal.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a pointer.
+ * @right: an arbitrary expression that evaluates to a pointer.
+ *
+ * Sets an expectation that the values that @left and @right evaluate to are not
+ * equal. This is semantically equivalent to
+ * KUNIT_EXPECT_TRUE(@test, (@left) != (@right)). See KUNIT_EXPECT_TRUE() for
+ * more information.
+ */
+#define KUNIT_EXPECT_PTR_NE(test, left, right) \
+ KUNIT_EXPECT_PTR_BINARY(test, left, !=, right)
+
+#define KUNIT_EXPECT_PTR_NE_MSG(test, left, right, fmt, ...) \
+ KUNIT_EXPECT_PTR_BINARY_MSG(test, \
+ left, \
+ !=, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
+ * KUNIT_EXPECT_LT() - An expectation that @left is less than @right.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a primitive C type.
+ * @right: an arbitrary expression that evaluates to a primitive C type.
+ *
+ * Sets an expectation that the value that @left evaluates to is less than the
+ * value that @right evaluates to. This is semantically equivalent to
+ * KUNIT_EXPECT_TRUE(@test, (@left) < (@right)). See KUNIT_EXPECT_TRUE() for
+ * more information.
+ */
+#define KUNIT_EXPECT_LT(test, left, right) \
+ KUNIT_EXPECT_BINARY(test, left, <, right)
+
+#define KUNIT_EXPECT_LT_MSG(test, left, right, fmt, ...) \
+ KUNIT_EXPECT_BINARY_MSG(test, \
+ left, \
+ <, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
+ * KUNIT_EXPECT_LE() - Expects that @left is less than or equal to @right.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a primitive C type.
+ * @right: an arbitrary expression that evaluates to a primitive C type.
+ *
+ * Sets an expectation that the value that @left evaluates to is less than or
+ * equal to the value that @right evaluates to. Semantically this is equivalent
+ * to KUNIT_EXPECT_TRUE(@test, (@left) <= (@right)). See KUNIT_EXPECT_TRUE() for
+ * more information.
+ */
+#define KUNIT_EXPECT_LE(test, left, right) \
+ KUNIT_EXPECT_BINARY(test, left, <=, right)
+
+#define KUNIT_EXPECT_LE_MSG(test, left, right, fmt, ...) \
+ KUNIT_EXPECT_BINARY_MSG(test, \
+ left, \
+ <=, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
+ * KUNIT_EXPECT_GT() - An expectation that @left is greater than @right.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a primitive C type.
+ * @right: an arbitrary expression that evaluates to a primitive C type.
+ *
+ * Sets an expectation that the value that @left evaluates to is greater than
+ * the value that @right evaluates to. This is semantically equivalent to
+ * KUNIT_EXPECT_TRUE(@test, (@left) > (@right)). See KUNIT_EXPECT_TRUE() for
+ * more information.
+ */
+#define KUNIT_EXPECT_GT(test, left, right) \
+ KUNIT_EXPECT_BINARY(test, left, >, right)
+
+#define KUNIT_EXPECT_GT_MSG(test, left, right, fmt, ...) \
+ KUNIT_EXPECT_BINARY_MSG(test, \
+ left, \
+ >, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
+ * KUNIT_EXPECT_GE() - Expects that @left is greater than or equal to @right.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a primitive C type.
+ * @right: an arbitrary expression that evaluates to a primitive C type.
+ *
+ * Sets an expectation that the value that @left evaluates to is greater than
+ * the value that @right evaluates to. This is semantically equivalent to
+ * KUNIT_EXPECT_TRUE(@test, (@left) >= (@right)). See KUNIT_EXPECT_TRUE() for
+ * more information.
+ */
+#define KUNIT_EXPECT_GE(test, left, right) \
+ KUNIT_EXPECT_BINARY(test, left, >=, right)
+
+#define KUNIT_EXPECT_GE_MSG(test, left, right, fmt, ...) \
+ KUNIT_EXPECT_BINARY_MSG(test, \
+ left, \
+ >=, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
+ * KUNIT_EXPECT_STREQ() - Expects that strings @left and @right are equal.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a null terminated string.
+ * @right: an arbitrary expression that evaluates to a null terminated string.
+ *
+ * Sets an expectation that the values that @left and @right evaluate to are
+ * equal. This is semantically equivalent to
+ * KUNIT_EXPECT_TRUE(@test, !strcmp((@left), (@right))). See KUNIT_EXPECT_TRUE()
+ * for more information.
+ */
+#define KUNIT_EXPECT_STREQ(test, left, right) do { \
+ struct kunit_stream *__stream = KUNIT_EXPECT_START(test); \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ \
+ kunit_stream_add(__stream, "Expected " #left " == " #right ", but\n"); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #left, __left); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #right, __right); \
+ \
+ KUNIT_EXPECT_END(test, !strcmp(left, right), __stream); \
+} while (0)
+
+#define KUNIT_EXPECT_STREQ_MSG(test, left, right, fmt, ...) do { \
+ struct kunit_stream *__stream = KUNIT_EXPECT_START(test); \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ \
+ kunit_stream_add(__stream, "Expected " #left " == " #right ", but\n"); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #left, __left); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #right, __right); \
+ kunit_stream_add(__stream, fmt, ##__VA_ARGS__); \
+ \
+ KUNIT_EXPECT_END(test, !strcmp(left, right), __stream); \
+} while (0)
+
+/**
+ * KUNIT_EXPECT_STRNEQ() - Expects that strings @left and @right are not equal.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a null terminated string.
+ * @right: an arbitrary expression that evaluates to a null terminated string.
+ *
+ * Sets an expectation that the values that @left and @right evaluate to are
+ * not equal. This is semantically equivalent to
+ * KUNIT_EXPECT_TRUE(@test, strcmp((@left), (@right))). See KUNIT_EXPECT_TRUE()
+ * for more information.
+ */
+#define KUNIT_EXPECT_STRNEQ(test, left, right) do { \
+ struct kunit_stream *__stream = KUNIT_EXPECT_START(test); \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ \
+ kunit_stream_add(__stream, "Expected " #left " != " #right ", but\n"); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #left, __left); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #right, __right); \
+ \
+ KUNIT_EXPECT_END(test, strcmp(left, right), __stream); \
+} while (0)
+
+#define KUNIT_EXPECT_STRNEQ_MSG(test, left, right, fmt, ...) do { \
+ struct kunit_stream *__stream = KUNIT_EXPECT_START(test); \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ \
+ kunit_stream_add(__stream, "Expected " #left " != " #right ", but\n"); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #left, __left); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #right, __right); \
+ kunit_stream_add(__stream, fmt, ##__VA_ARGS__); \
+ \
+ KUNIT_EXPECT_END(test, strcmp(left, right), __stream); \
+} while (0)
+
+/**
+ * KUNIT_EXPECT_NOT_ERR_OR_NULL() - Expects that @ptr is not null and not err.
+ * @test: The test context object.
+ * @ptr: an arbitrary pointer.
+ *
+ * Sets an expectation that the value that @ptr evaluates to is not null and not
+ * an errno stored in a pointer. This is semantically equivalent to
+ * KUNIT_EXPECT_TRUE(@test, !IS_ERR_OR_NULL(@ptr)). See KUNIT_EXPECT_TRUE() for
+ * more information.
+ */
+#define KUNIT_EXPECT_NOT_ERR_OR_NULL(test, ptr) do { \
+ struct kunit_stream *__stream = KUNIT_EXPECT_START(test); \
+ typeof(ptr) __ptr = (ptr); \
+ \
+ if (!__ptr) \
+ kunit_stream_add(__stream, \
+ "Expected " #ptr " is not null, but is\n"); \
+ if (IS_ERR(__ptr)) \
+ kunit_stream_add(__stream, \
+ "Expected " #ptr " is not error, but is: %ld", \
+ PTR_ERR(__ptr)); \
+ \
+ KUNIT_EXPECT_END(test, !IS_ERR_OR_NULL(__ptr), __stream); \
+} while (0)
+
+#define KUNIT_EXPECT_NOT_ERR_OR_NULL_MSG(test, ptr, fmt, ...) do { \
+ struct kunit_stream *__stream = KUNIT_EXPECT_START(test); \
+ typeof(ptr) __ptr = (ptr); \
+ \
+ if (!__ptr) { \
+ kunit_stream_add(__stream, \
+ "Expected " #ptr " is not null, but is\n"); \
+ kunit_stream_add(__stream, fmt, ##__VA_ARGS__); \
+ } \
+ if (IS_ERR(__ptr)) { \
+ kunit_stream_add(__stream, \
+ "Expected " #ptr " is not error, but is: %ld", \
+ PTR_ERR(__ptr)); \
+ \
+ kunit_stream_add(__stream, fmt, ##__VA_ARGS__); \
+ } \
+ KUNIT_EXPECT_END(test, !IS_ERR_OR_NULL(__ptr), __stream); \
+} while (0)
+
#endif /* _KUNIT_TEST_H */
diff --git a/kunit/test.c b/kunit/test.c
index 29edf34a89a37..8c745fd0c82d3 100644
--- a/kunit/test.c
+++ b/kunit/test.c
@@ -287,3 +287,69 @@ void kunit_printk(const char *level,
va_end(args);
}
+
+void kunit_expect_binary_msg(struct kunit *test,
+ long long left, const char *left_name,
+ long long right, const char *right_name,
+ bool compare_result,
+ const char *compare_name,
+ const char *file,
+ const char *line,
+ const char *fmt, ...)
+{
+ struct kunit_stream *stream = kunit_expect_start(test, file, line);
+ struct va_format vaf;
+ va_list args;
+
+ kunit_stream_add(stream,
+ "Expected %s %s %s, but\n",
+ left_name, compare_name, right_name);
+ kunit_stream_add(stream, "\t\t%s == %lld\n", left_name, left);
+ kunit_stream_add(stream, "\t\t%s == %lld", right_name, right);
+
+ if (fmt) {
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ kunit_stream_add(stream, "\n%pV", &vaf);
+
+ va_end(args);
+ }
+
+ kunit_expect_end(test, compare_result, stream);
+}
+
+void kunit_expect_ptr_binary_msg(struct kunit *test,
+ void *left, const char *left_name,
+ void *right, const char *right_name,
+ bool compare_result,
+ const char *compare_name,
+ const char *file,
+ const char *line,
+ const char *fmt, ...)
+{
+ struct kunit_stream *stream = kunit_expect_start(test, file, line);
+ struct va_format vaf;
+ va_list args;
+
+ kunit_stream_add(stream,
+ "Expected %s %s %s, but\n",
+ left_name, compare_name, right_name);
+ kunit_stream_add(stream, "\t\t%s == %pK\n", left_name, left);
+ kunit_stream_add(stream, "\t\t%s == %pK", right_name, right);
+
+ if (fmt) {
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ kunit_stream_add(stream, "\n%pV", &vaf);
+
+ va_end(args);
+ }
+
+ kunit_expect_end(test, compare_result, stream);
+}
--
2.22.0.410.gd8fdbe21b5-goog
^ permalink raw reply related
* [PATCH v9 06/18] kbuild: enable building KUnit
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
jpoimboe-H+wXaHxf7aLQT0dZR+AlfA, keescook-hpIqsD4AKlfQT0dZR+AlfA,
kieran.bingham-ryLnwIuWjnjg/C1BVhZhaw,
mcgrof-DgEjT+Ai2ygdnm+yROfE0A, peterz-wEGCiKHe2LqWVfeAwA7xHQ,
robh-DgEjT+Ai2ygdnm+yROfE0A, sboyd-DgEjT+Ai2ygdnm+yROfE0A,
shuah-DgEjT+Ai2ygdnm+yROfE0A, tytso-3s7WtUTddSA,
yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A
Cc: pmladek-IBi9RG/b67k, linux-doc-u79uwXL29TY76Z2rM5mHXA,
amir73il-Re5JQEeQqe8AvxtiuMwx3w, Brendan Higgins,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
Alexander.Levin-0li6OtcxBFHby3iVrkZq2A,
linux-kselftest-u79uwXL29TY76Z2rM5mHXA,
linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw,
khilman-rdvid1DuHRBWk0Htik3J/w, knut.omang-QHcLZuEGTsvQT0dZR+AlfA,
wfg-VuQAYsv1563Yd54FQh9/CA, joel-U3u1mxZcP9KHXe+LvDLADg,
rientjes-hpIqsD4AKlfQT0dZR+AlfA, jdike-OPE4K8JWMJJBDgjK7y7TUQ,
dan.carpenter-QHcLZuEGTsvQT0dZR+AlfA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kbuild-u79uwXL29TY76Z2rM5mHXA, Tim.Bird-7U/KSKJipcs,
linux-um-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
rostedt-nx8X9YLhiw1AfugRpC6u6w, julia.lawall-L2FTfq7BK8M,
kunit-dev-/JYPxA39Uh5TLH3MbocFFw, Michal Marek,
richard-/L3Ra7n9ekc, rdunlap-wEGCiKHe2LqWVfeAwA7xHQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, daniel-/w4YWyX8dFk,
mpe-Gsx/Oe8HsFggBc27wqDAHg, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20190712081744.87097-1-brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
KUnit is a new unit testing framework for the kernel and when used is
built into the kernel as a part of it. Add KUnit to the root Kconfig and
Makefile to allow it to be actually built.
Signed-off-by: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Acked-by: Masahiro Yamada <yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org>
Cc: Michal Marek <michal.lkml-yyZNWGI4GtDR7s880joybQ@public.gmane.org>
Reviewed-by: Greg Kroah-Hartman <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>
Reviewed-by: Logan Gunthorpe <logang-OTvnGxWRz7hWk0Htik3J/w@public.gmane.org>
---
Kconfig | 2 ++
Makefile | 2 ++
2 files changed, 4 insertions(+)
diff --git a/Kconfig b/Kconfig
index 48a80beab6853..10428501edb78 100644
--- a/Kconfig
+++ b/Kconfig
@@ -30,3 +30,5 @@ source "crypto/Kconfig"
source "lib/Kconfig"
source "lib/Kconfig.debug"
+
+source "kunit/Kconfig"
diff --git a/Makefile b/Makefile
index 3e4868a6498b2..0ce1a8a2b6fec 100644
--- a/Makefile
+++ b/Makefile
@@ -993,6 +993,8 @@ PHONY += prepare0
ifeq ($(KBUILD_EXTMOD),)
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
+core-$(CONFIG_KUNIT) += kunit/
+
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
$(core-y) $(core-m) $(drivers-y) $(drivers-m) \
$(net-y) $(net-m) $(libs-y) $(libs-m) $(virt-y)))
--
2.22.0.410.gd8fdbe21b5-goog
^ permalink raw reply related
* [PATCH v9 07/18] kunit: test: add initial tests
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
jpoimboe-H+wXaHxf7aLQT0dZR+AlfA, keescook-hpIqsD4AKlfQT0dZR+AlfA,
kieran.bingham-ryLnwIuWjnjg/C1BVhZhaw,
mcgrof-DgEjT+Ai2ygdnm+yROfE0A, peterz-wEGCiKHe2LqWVfeAwA7xHQ,
robh-DgEjT+Ai2ygdnm+yROfE0A, sboyd-DgEjT+Ai2ygdnm+yROfE0A,
shuah-DgEjT+Ai2ygdnm+yROfE0A, tytso-3s7WtUTddSA,
yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A
Cc: pmladek-IBi9RG/b67k, linux-doc-u79uwXL29TY76Z2rM5mHXA,
amir73il-Re5JQEeQqe8AvxtiuMwx3w, Brendan Higgins,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
Alexander.Levin-0li6OtcxBFHby3iVrkZq2A,
linux-kselftest-u79uwXL29TY76Z2rM5mHXA,
linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw,
khilman-rdvid1DuHRBWk0Htik3J/w, knut.omang-QHcLZuEGTsvQT0dZR+AlfA,
wfg-VuQAYsv1563Yd54FQh9/CA, joel-U3u1mxZcP9KHXe+LvDLADg,
rientjes-hpIqsD4AKlfQT0dZR+AlfA, jdike-OPE4K8JWMJJBDgjK7y7TUQ,
dan.carpenter-QHcLZuEGTsvQT0dZR+AlfA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kbuild-u79uwXL29TY76Z2rM5mHXA, Tim.Bird-7U/KSKJipcs,
linux-um-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
rostedt-nx8X9YLhiw1AfugRpC6u6w, julia.lawall-L2FTfq7BK8M,
kunit-dev-/JYPxA39Uh5TLH3MbocFFw, richard-/L3Ra7n9ekc,
rdunlap-wEGCiKHe2LqWVfeAwA7xHQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, daniel-/w4YWyX8dFk,
mpe-Gsx/Oe8HsFggBc27wqDAHg, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20190712081744.87097-1-brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Add a test for string stream along with a simpler example.
Signed-off-by: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Reviewed-by: Greg Kroah-Hartman <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>
Reviewed-by: Logan Gunthorpe <logang-OTvnGxWRz7hWk0Htik3J/w@public.gmane.org>
---
kunit/Kconfig | 21 +++++++++
kunit/Makefile | 4 ++
kunit/example-test.c | 88 ++++++++++++++++++++++++++++++++++++++
kunit/string-stream-test.c | 75 ++++++++++++++++++++++++++++++++
4 files changed, 188 insertions(+)
create mode 100644 kunit/example-test.c
create mode 100644 kunit/string-stream-test.c
diff --git a/kunit/Kconfig b/kunit/Kconfig
index 330ae83527c23..8541ef95b65ad 100644
--- a/kunit/Kconfig
+++ b/kunit/Kconfig
@@ -14,4 +14,25 @@ config KUNIT
architectures. For more information, please see
Documentation/dev-tools/kunit/.
+config KUNIT_TEST
+ bool "KUnit test for KUnit"
+ depends on KUNIT
+ help
+ Enables the unit tests for the KUnit test framework. These tests test
+ the KUnit test framework itself; the tests are both written using
+ KUnit and test KUnit. This option should only be enabled for testing
+ purposes by developers interested in testing that KUnit works as
+ expected.
+
+config KUNIT_EXAMPLE_TEST
+ bool "Example test for KUnit"
+ depends on KUNIT
+ help
+ Enables an example unit test that illustrates some of the basic
+ features of KUnit. This test only exists to help new users understand
+ what KUnit is and how it is used. Please refer to the example test
+ itself, kunit/example-test.c, for more information. This option is
+ intended for curious hackers who would like to understand how to use
+ KUnit for kernel development.
+
endmenu
diff --git a/kunit/Makefile b/kunit/Makefile
index 6ddc622ee6b1c..60a9ea6cb4697 100644
--- a/kunit/Makefile
+++ b/kunit/Makefile
@@ -1,3 +1,7 @@
obj-$(CONFIG_KUNIT) += test.o \
string-stream.o \
kunit-stream.o
+
+obj-$(CONFIG_KUNIT_TEST) += string-stream-test.o
+
+obj-$(CONFIG_KUNIT_EXAMPLE_TEST) += example-test.o
diff --git a/kunit/example-test.c b/kunit/example-test.c
new file mode 100644
index 0000000000000..f64a829aa441f
--- /dev/null
+++ b/kunit/example-test.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Example KUnit test to show how to use KUnit.
+ *
+ * Copyright (C) 2019, Google LLC.
+ * Author: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
+ */
+
+#include <kunit/test.h>
+
+/*
+ * This is the most fundamental element of KUnit, the test case. A test case
+ * makes a set EXPECTATIONs and ASSERTIONs about the behavior of some code; if
+ * any expectations or assertions are not met, the test fails; otherwise, the
+ * test passes.
+ *
+ * In KUnit, a test case is just a function with the signature
+ * `void (*)(struct kunit *)`. `struct kunit` is a context object that stores
+ * information about the current test.
+ */
+static void example_simple_test(struct kunit *test)
+{
+ /*
+ * This is an EXPECTATION; it is how KUnit tests things. When you want
+ * to test a piece of code, you set some expectations about what the
+ * code should do. KUnit then runs the test and verifies that the code's
+ * behavior matched what was expected.
+ */
+ KUNIT_EXPECT_EQ(test, 1 + 1, 2);
+}
+
+/*
+ * This is run once before each test case, see the comment on
+ * example_test_suite for more information.
+ */
+static int example_test_init(struct kunit *test)
+{
+ kunit_info(test, "initializing\n");
+
+ return 0;
+}
+
+/*
+ * Here we make a list of all the test cases we want to add to the test suite
+ * below.
+ */
+static struct kunit_case example_test_cases[] = {
+ /*
+ * This is a helper to create a test case object from a test case
+ * function; its exact function is not important to understand how to
+ * use KUnit, just know that this is how you associate test cases with a
+ * test suite.
+ */
+ KUNIT_CASE(example_simple_test),
+ {}
+};
+
+/*
+ * This defines a suite or grouping of tests.
+ *
+ * Test cases are defined as belonging to the suite by adding them to
+ * `kunit_cases`.
+ *
+ * Often it is desirable to run some function which will set up things which
+ * will be used by every test; this is accomplished with an `init` function
+ * which runs before each test case is invoked. Similarly, an `exit` function
+ * may be specified which runs after every test case and can be used to for
+ * cleanup. For clarity, running tests in a test suite would behave as follows:
+ *
+ * suite.init(test);
+ * suite.test_case[0](test);
+ * suite.exit(test);
+ * suite.init(test);
+ * suite.test_case[1](test);
+ * suite.exit(test);
+ * ...;
+ */
+static struct kunit_suite example_test_suite = {
+ .name = "example",
+ .init = example_test_init,
+ .test_cases = example_test_cases,
+};
+
+/*
+ * This registers the above test suite telling KUnit that this is a suite of
+ * tests that need to be run.
+ */
+kunit_test_suite(example_test_suite);
diff --git a/kunit/string-stream-test.c b/kunit/string-stream-test.c
new file mode 100644
index 0000000000000..b5641b078b8f6
--- /dev/null
+++ b/kunit/string-stream-test.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit test for struct string_stream.
+ *
+ * Copyright (C) 2019, Google LLC.
+ * Author: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
+ */
+
+#include <linux/slab.h>
+#include <kunit/test.h>
+#include <kunit/string-stream.h>
+
+static void string_stream_test_empty_on_creation(struct kunit *test)
+{
+ struct string_stream *stream = alloc_string_stream(test);
+
+ KUNIT_EXPECT_TRUE(test, string_stream_is_empty(stream));
+}
+
+static void string_stream_test_not_empty_after_add(struct kunit *test)
+{
+ struct string_stream *stream = alloc_string_stream(test);
+
+ string_stream_add(stream, "Foo");
+
+ KUNIT_EXPECT_FALSE(test, string_stream_is_empty(stream));
+}
+static void string_stream_test_get_string(struct kunit *test)
+{
+ struct string_stream *stream = alloc_string_stream(test);
+ char *output;
+
+ string_stream_add(stream, "Foo");
+ string_stream_add(stream, " %s", "bar");
+
+ output = string_stream_get_string(stream);
+ KUNIT_EXPECT_STREQ(test, output, "Foo bar");
+ kfree(output);
+}
+
+static void string_stream_test_add_and_clear(struct kunit *test)
+{
+ struct string_stream *stream = alloc_string_stream(test);
+ char *output;
+ int i;
+
+ for (i = 0; i < 10; i++)
+ string_stream_add(stream, "A");
+
+ output = string_stream_get_string(stream);
+ KUNIT_EXPECT_STREQ(test, output, "AAAAAAAAAA");
+ KUNIT_EXPECT_EQ(test, stream->length, (size_t)10);
+ KUNIT_EXPECT_FALSE(test, string_stream_is_empty(stream));
+ kfree(output);
+
+ string_stream_clear(stream);
+
+ output = string_stream_get_string(stream);
+ KUNIT_EXPECT_STREQ(test, output, "");
+ KUNIT_EXPECT_TRUE(test, string_stream_is_empty(stream));
+}
+
+static struct kunit_case string_stream_test_cases[] = {
+ KUNIT_CASE(string_stream_test_empty_on_creation),
+ KUNIT_CASE(string_stream_test_not_empty_after_add),
+ KUNIT_CASE(string_stream_test_get_string),
+ KUNIT_CASE(string_stream_test_add_and_clear),
+ {}
+};
+
+static struct kunit_suite string_stream_test_suite = {
+ .name = "string-stream-test",
+ .test_cases = string_stream_test_cases
+};
+kunit_test_suite(string_stream_test_suite);
--
2.22.0.410.gd8fdbe21b5-goog
^ permalink raw reply related
* [PATCH v9 08/18] objtool: add kunit_try_catch_throw to the noreturn list
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list, gregkh, jpoimboe, keescook, kieran.bingham, mcgrof,
peterz, robh, sboyd, shuah, tytso, yamada.masahiro
Cc: pmladek, linux-doc, amir73il, Brendan Higgins, dri-devel,
Alexander.Levin, linux-kselftest, kbuild test robot, linux-nvdimm,
khilman, knut.omang, wfg, joel, rientjes, jdike, dan.carpenter,
devicetree, linux-kbuild, Tim.Bird, linux-um, rostedt,
julia.lawall, kunit-dev, richard, rdunlap, linux-kernel, mpe,
linux-fsdevel, logang
In-Reply-To: <20190712081744.87097-1-brendanhiggins@google.com>
Fix the following warning seen on GCC 7.3:
kunit/test-test.o: warning: objtool: kunit_test_unsuccessful_try() falls through to next function kunit_test_catch()
kunit_try_catch_throw is a function added in the following patch in this
series; it allows KUnit, a unit testing framework for the kernel, to
bail out of a broken test. As a consequence, it is a new __noreturn
function that objtool thinks is broken (as seen above). So fix this
warning by adding kunit_try_catch_throw to objtool's noreturn list.
Reported-by: kbuild test robot <lkp@intel.com>
Signed-off-by: Brendan Higgins <brendanhiggins@google.com>
Acked-by: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://www.spinics.net/lists/linux-kbuild/msg21708.html
Cc: Peter Zijlstra <peterz@infradead.org>
---
tools/objtool/check.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 172f991957269..98db5fe85c797 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -134,6 +134,7 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func,
"usercopy_abort",
"machine_real_restart",
"rewind_stack_do_exit",
+ "kunit_try_catch_throw",
};
if (func->bind == STB_WEAK)
--
2.22.0.410.gd8fdbe21b5-goog
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v9 09/18] kunit: test: add support for test abort
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
jpoimboe-H+wXaHxf7aLQT0dZR+AlfA, keescook-hpIqsD4AKlfQT0dZR+AlfA,
kieran.bingham-ryLnwIuWjnjg/C1BVhZhaw,
mcgrof-DgEjT+Ai2ygdnm+yROfE0A, peterz-wEGCiKHe2LqWVfeAwA7xHQ,
robh-DgEjT+Ai2ygdnm+yROfE0A, sboyd-DgEjT+Ai2ygdnm+yROfE0A,
shuah-DgEjT+Ai2ygdnm+yROfE0A, tytso-3s7WtUTddSA,
yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A
Cc: pmladek-IBi9RG/b67k, linux-doc-u79uwXL29TY76Z2rM5mHXA,
amir73il-Re5JQEeQqe8AvxtiuMwx3w, Brendan Higgins,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
Alexander.Levin-0li6OtcxBFHby3iVrkZq2A,
linux-kselftest-u79uwXL29TY76Z2rM5mHXA,
linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw,
khilman-rdvid1DuHRBWk0Htik3J/w, knut.omang-QHcLZuEGTsvQT0dZR+AlfA,
wfg-VuQAYsv1563Yd54FQh9/CA, joel-U3u1mxZcP9KHXe+LvDLADg,
rientjes-hpIqsD4AKlfQT0dZR+AlfA, jdike-OPE4K8JWMJJBDgjK7y7TUQ,
dan.carpenter-QHcLZuEGTsvQT0dZR+AlfA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kbuild-u79uwXL29TY76Z2rM5mHXA, Tim.Bird-7U/KSKJipcs,
linux-um-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
rostedt-nx8X9YLhiw1AfugRpC6u6w, julia.lawall-L2FTfq7BK8M,
kunit-dev-/JYPxA39Uh5TLH3MbocFFw, richard-/L3Ra7n9ekc,
rdunlap-wEGCiKHe2LqWVfeAwA7xHQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, daniel-/w4YWyX8dFk,
mpe-Gsx/Oe8HsFggBc27wqDAHg, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20190712081744.87097-1-brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Add support for aborting/bailing out of test cases, which is needed for
implementing assertions.
An assertion is like an expectation, but bails out of the test case
early if the assertion is not met. The idea with assertions is that you
use them to state all the preconditions for your test. Logically
speaking, these are the premises of the test case, so if a premise isn't
true, there is no point in continuing the test case because there are no
conclusions that can be drawn without the premises. Whereas, the
expectation is the thing you are trying to prove.
Signed-off-by: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Reviewed-by: Greg Kroah-Hartman <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>
Reviewed-by: Logan Gunthorpe <logang-OTvnGxWRz7hWk0Htik3J/w@public.gmane.org>
---
include/kunit/test.h | 16 ++++
include/kunit/try-catch.h | 69 +++++++++++++++
kunit/Makefile | 3 +-
kunit/test.c | 176 +++++++++++++++++++++++++++++++++++---
kunit/try-catch.c | 95 ++++++++++++++++++++
5 files changed, 344 insertions(+), 15 deletions(-)
create mode 100644 include/kunit/try-catch.h
create mode 100644 kunit/try-catch.c
diff --git a/include/kunit/test.h b/include/kunit/test.h
index df18765e6ea25..01440f3569847 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -13,6 +13,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <kunit/kunit-stream.h>
+#include <kunit/try-catch.h>
struct kunit_resource;
@@ -167,6 +168,7 @@ struct kunit {
/* private: internal use only. */
const char *name; /* Read only after initialization! */
+ struct kunit_try_catch try_catch;
/*
* success starts as true, and may only be set to false during a test
* case; thus, it is safe to update this across multiple threads using
@@ -176,6 +178,11 @@ struct kunit {
*/
bool success; /* Read only after test_case finishes! */
struct mutex lock; /* Gaurds all mutable test state. */
+ /*
+ * death_test may be both set and unset from multiple threads in a test
+ * case.
+ */
+ bool death_test; /* Protected by lock. */
/*
* Because resources is a list that may be updated multiple times (with
* new resources) from any thread associated with a test case, we must
@@ -184,10 +191,19 @@ struct kunit {
struct list_head resources; /* Protected by lock. */
};
+static inline void kunit_set_death_test(struct kunit *test, bool death_test)
+{
+ mutex_lock(&test->lock);
+ test->death_test = death_test;
+ mutex_unlock(&test->lock);
+}
+
void kunit_init_test(struct kunit *test, const char *name);
void kunit_fail(struct kunit *test, struct kunit_stream *stream);
+void kunit_abort(struct kunit *test);
+
int kunit_run_tests(struct kunit_suite *suite);
/**
diff --git a/include/kunit/try-catch.h b/include/kunit/try-catch.h
new file mode 100644
index 0000000000000..8a414a9af0b64
--- /dev/null
+++ b/include/kunit/try-catch.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * An API to allow a function, that may fail, to be executed, and recover in a
+ * controlled manner.
+ *
+ * Copyright (C) 2019, Google LLC.
+ * Author: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
+ */
+
+#ifndef _KUNIT_TRY_CATCH_H
+#define _KUNIT_TRY_CATCH_H
+
+#include <linux/types.h>
+
+typedef void (*kunit_try_catch_func_t)(void *);
+
+struct kunit;
+
+/*
+ * struct kunit_try_catch - provides a generic way to run code which might fail.
+ * @context: used to pass user data to the try and catch functions.
+ *
+ * kunit_try_catch provides a generic, architecture independent way to execute
+ * an arbitrary function of type kunit_try_catch_func_t which may bail out by
+ * calling kunit_try_catch_throw(). If kunit_try_catch_throw() is called, @try
+ * is stopped at the site of invocation and @catch is catch is called.
+ *
+ * struct kunit_try_catch provides a generic interface for the functionality
+ * needed to implement kunit->abort() which in turn is needed for implementing
+ * assertions. Assertions allow stating a precondition for a test simplifying
+ * how test cases are written and presented.
+ *
+ * Assertions are like expectations, except they abort (call
+ * kunit_try_catch_throw()) when the specified condition is not met. This is
+ * useful when you look at a test case as a logical statement about some piece
+ * of code, where assertions are the premises for the test case, and the
+ * conclusion is a set of predicates, rather expectations, that must all be
+ * true. If your premises are violated, it does not makes sense to continue.
+ */
+struct kunit_try_catch {
+ /* private: internal use only. */
+ struct kunit *test;
+ struct completion *try_completion;
+ int try_result;
+ kunit_try_catch_func_t try;
+ kunit_try_catch_func_t catch;
+ void *context;
+};
+
+void kunit_try_catch_init(struct kunit_try_catch *try_catch,
+ struct kunit *test,
+ kunit_try_catch_func_t try,
+ kunit_try_catch_func_t catch);
+
+void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context);
+
+void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch);
+
+static inline int kunit_try_catch_get_result(struct kunit_try_catch *try_catch)
+{
+ return try_catch->try_result;
+}
+
+/*
+ * Exposed for testing only.
+ */
+void kunit_generic_try_catch_init(struct kunit_try_catch *try_catch);
+
+#endif /* _KUNIT_TRY_CATCH_H */
diff --git a/kunit/Makefile b/kunit/Makefile
index 60a9ea6cb4697..1f7680cfa11ad 100644
--- a/kunit/Makefile
+++ b/kunit/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_KUNIT) += test.o \
string-stream.o \
- kunit-stream.o
+ kunit-stream.o \
+ try-catch.o
obj-$(CONFIG_KUNIT_TEST) += string-stream-test.o
diff --git a/kunit/test.c b/kunit/test.c
index 8c745fd0c82d3..731f3c9eecf20 100644
--- a/kunit/test.c
+++ b/kunit/test.c
@@ -7,13 +7,26 @@
*/
#include <linux/kernel.h>
+#include <linux/sched/debug.h>
#include <kunit/test.h>
+#include <kunit/try-catch.h>
static void kunit_set_failure(struct kunit *test)
{
WRITE_ONCE(test->success, false);
}
+static bool kunit_get_death_test(struct kunit *test)
+{
+ bool death_test;
+
+ mutex_lock(&test->lock);
+ death_test = test->death_test;
+ mutex_unlock(&test->lock);
+
+ return death_test;
+}
+
static int kunit_vprintk_emit(int level, const char *fmt, va_list args)
{
return vprintk_emit(0, level, NULL, 0, fmt, args);
@@ -126,40 +139,175 @@ void kunit_fail(struct kunit *test, struct kunit_stream *stream)
kunit_stream_commit(stream);
}
+void __noreturn kunit_abort(struct kunit *test)
+{
+ kunit_set_death_test(test, true);
+
+ kunit_try_catch_throw(&test->try_catch);
+
+ /*
+ * Throw could not abort from test.
+ *
+ * XXX: we should never reach this line! As kunit_try_catch_throw is
+ * marked __noreturn.
+ */
+ WARN_ONCE(true, "Throw could not abort from test!\n");
+}
+
void kunit_init_test(struct kunit *test, const char *name)
{
mutex_init(&test->lock);
INIT_LIST_HEAD(&test->resources);
test->name = name;
test->success = true;
+ test->death_test = false;
}
/*
- * Performs all logic to run a test case.
+ * Initializes and runs test case. Does not clean up or do post validations.
*/
-static void kunit_run_case(struct kunit_suite *suite,
- struct kunit_case *test_case)
+static void kunit_run_case_internal(struct kunit *test,
+ struct kunit_suite *suite,
+ struct kunit_case *test_case)
{
- struct kunit test;
- int ret = 0;
-
- kunit_init_test(&test, test_case->name);
+ int ret;
if (suite->init) {
- ret = suite->init(&test);
+ ret = suite->init(test);
if (ret) {
- kunit_err(&test, "failed to initialize: %d\n", ret);
- kunit_set_failure(&test);
+ kunit_err(test, "failed to initialize: %d\n", ret);
+ kunit_set_failure(test);
return;
}
}
- test_case->run_case(&test);
+ test_case->run_case(test);
+}
+
+static void kunit_case_internal_cleanup(struct kunit *test)
+{
+ kunit_cleanup(test);
+}
+/*
+ * Performs post validations and cleanup after a test case was run.
+ * XXX: Should ONLY BE CALLED AFTER kunit_run_case_internal!
+ */
+static void kunit_run_case_cleanup(struct kunit *test,
+ struct kunit_suite *suite)
+{
if (suite->exit)
- suite->exit(&test);
+ suite->exit(test);
+
+ kunit_case_internal_cleanup(test);
+}
+
+/*
+ * Handles an unexpected crash in a test case.
+ */
+static void kunit_handle_test_crash(struct kunit *test,
+ struct kunit_suite *suite,
+ struct kunit_case *test_case)
+{
+ kunit_err(test, "kunit test case crashed!");
+ /*
+ * TODO(brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org): This prints the stack trace up
+ * through this frame, not up to the frame that caused the crash.
+ */
+ show_stack(NULL, NULL);
+
+ kunit_case_internal_cleanup(test);
+}
+
+struct kunit_try_catch_context {
+ struct kunit *test;
+ struct kunit_suite *suite;
+ struct kunit_case *test_case;
+};
+
+static void kunit_try_run_case(void *data)
+{
+ struct kunit_try_catch_context *ctx = data;
+ struct kunit *test = ctx->test;
+ struct kunit_suite *suite = ctx->suite;
+ struct kunit_case *test_case = ctx->test_case;
+
+ /*
+ * kunit_run_case_internal may encounter a fatal error; if it does,
+ * abort will be called, this thread will exit, and finally the parent
+ * thread will resume control and handle any necessary clean up.
+ */
+ kunit_run_case_internal(test, suite, test_case);
+ /* This line may never be reached. */
+ kunit_run_case_cleanup(test, suite);
+}
+
+static void kunit_catch_run_case(void *data)
+{
+ struct kunit_try_catch_context *ctx = data;
+ struct kunit *test = ctx->test;
+ struct kunit_suite *suite = ctx->suite;
+ struct kunit_case *test_case = ctx->test_case;
+ int try_exit_code = kunit_try_catch_get_result(&test->try_catch);
+
+ if (try_exit_code) {
+ kunit_set_failure(test);
+ /*
+ * Test case could not finish, we have no idea what state it is
+ * in, so don't do clean up.
+ */
+ if (try_exit_code == -ETIMEDOUT)
+ kunit_err(test, "test case timed out\n");
+ /*
+ * Unknown internal error occurred preventing test case from
+ * running, so there is nothing to clean up.
+ */
+ else
+ kunit_err(test, "internal error occurred preventing test case from running: %d\n",
+ try_exit_code);
+ return;
+ }
+
+ if (kunit_get_death_test(test)) {
+ /*
+ * EXPECTED DEATH: kunit_run_case_internal encountered
+ * anticipated fatal error. Everything should be in a safe
+ * state.
+ */
+ kunit_run_case_cleanup(test, suite);
+ } else {
+ /*
+ * UNEXPECTED DEATH: kunit_run_case_internal encountered an
+ * unanticipated fatal error. We have no idea what the state of
+ * the test case is in.
+ */
+ kunit_handle_test_crash(test, suite, test_case);
+ kunit_set_failure(test);
+ }
+}
+
+/*
+ * Performs all logic to run a test case. It also catches most errors that
+ * occurs in a test case and reports them as failures.
+ */
+static void kunit_run_case_catch_errors(struct kunit_suite *suite,
+ struct kunit_case *test_case)
+{
+ struct kunit_try_catch_context context;
+ struct kunit_try_catch *try_catch;
+ struct kunit test;
+
+ kunit_init_test(&test, test_case->name);
+ try_catch = &test.try_catch;
- kunit_cleanup(&test);
+ kunit_try_catch_init(try_catch,
+ &test,
+ kunit_try_run_case,
+ kunit_catch_run_case);
+ context.test = &test;
+ context.suite = suite;
+ context.test_case = test_case;
+ kunit_try_catch_run(try_catch, &context);
test_case->success = test.success;
}
@@ -172,7 +320,7 @@ int kunit_run_tests(struct kunit_suite *suite)
kunit_print_subtest_start(suite);
for (test_case = suite->test_cases; test_case->run_case; test_case++) {
- kunit_run_case(suite, test_case);
+ kunit_run_case_catch_errors(suite, test_case);
kunit_print_test_case_ok_not_ok(test_case, test_case_count++);
}
diff --git a/kunit/try-catch.c b/kunit/try-catch.c
new file mode 100644
index 0000000000000..de580f074387b
--- /dev/null
+++ b/kunit/try-catch.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * An API to allow a function, that may fail, to be executed, and recover in a
+ * controlled manner.
+ *
+ * Copyright (C) 2019, Google LLC.
+ * Author: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
+ */
+
+#include <kunit/try-catch.h>
+#include <kunit/test.h>
+#include <linux/completion.h>
+#include <linux/kthread.h>
+
+void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch)
+{
+ try_catch->try_result = -EFAULT;
+ complete_and_exit(try_catch->try_completion, -EFAULT);
+}
+
+static int kunit_generic_run_threadfn_adapter(void *data)
+{
+ struct kunit_try_catch *try_catch = data;
+
+ try_catch->try(try_catch->context);
+
+ complete_and_exit(try_catch->try_completion, 0);
+}
+
+void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context)
+{
+ DECLARE_COMPLETION_ONSTACK(try_completion);
+ struct kunit *test = try_catch->test;
+ struct task_struct *task_struct;
+ int exit_code, status;
+
+ try_catch->context = context;
+ try_catch->try_completion = &try_completion;
+ try_catch->try_result = 0;
+ task_struct = kthread_run(kunit_generic_run_threadfn_adapter,
+ try_catch,
+ "kunit_try_catch_thread");
+ if (IS_ERR(task_struct)) {
+ try_catch->catch(try_catch->context);
+ return;
+ }
+
+ /*
+ * TODO(brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org): We should probably have some type of
+ * variable timeout here. The only question is what that timeout value
+ * should be.
+ *
+ * The intention has always been, at some point, to be able to label
+ * tests with some type of size bucket (unit/small, integration/medium,
+ * large/system/end-to-end, etc), where each size bucket would get a
+ * default timeout value kind of like what Bazel does:
+ * https://docs.bazel.build/versions/master/be/common-definitions.html#test.size
+ * There is still some debate to be had on exactly how we do this. (For
+ * one, we probably want to have some sort of test runner level
+ * timeout.)
+ *
+ * For more background on this topic, see:
+ * https://mike-bland.com/2011/11/01/small-medium-large.html
+ */
+ status = wait_for_completion_timeout(&try_completion,
+ 300 * MSEC_PER_SEC); /* 5 min */
+ if (status < 0) {
+ kunit_err(test, "try timed out\n");
+ try_catch->try_result = -ETIMEDOUT;
+ }
+
+ exit_code = try_catch->try_result;
+
+ if (!exit_code)
+ return;
+
+ if (exit_code == -EFAULT)
+ try_catch->try_result = 0;
+ else if (exit_code == -EINTR)
+ kunit_err(test, "wake_up_process() was never called\n");
+ else if (exit_code)
+ kunit_err(test, "Unknown error: %d\n", exit_code);
+
+ try_catch->catch(try_catch->context);
+}
+
+void kunit_try_catch_init(struct kunit_try_catch *try_catch,
+ struct kunit *test,
+ kunit_try_catch_func_t try,
+ kunit_try_catch_func_t catch)
+{
+ try_catch->test = test;
+ try_catch->try = try;
+ try_catch->catch = catch;
+}
--
2.22.0.410.gd8fdbe21b5-goog
^ permalink raw reply related
* [PATCH v9 10/18] kunit: test: add tests for kunit test abort
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list, gregkh, jpoimboe, keescook, kieran.bingham, mcgrof,
peterz, robh, sboyd, shuah, tytso, yamada.masahiro
Cc: pmladek, linux-doc, amir73il, Brendan Higgins, dri-devel,
Alexander.Levin, linux-kselftest, linux-nvdimm, khilman,
knut.omang, wfg, joel, rientjes, jdike, dan.carpenter, devicetree,
linux-kbuild, Tim.Bird, linux-um, rostedt, julia.lawall,
kunit-dev, richard, rdunlap, linux-kernel, mpe, linux-fsdevel,
logang
In-Reply-To: <20190712081744.87097-1-brendanhiggins@google.com>
Add KUnit tests for the KUnit test abort mechanism (see preceding
commit). Add tests both for general try catch mechanism as well as
non-architecture specific mechanism.
Signed-off-by: Brendan Higgins <brendanhiggins@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
---
kunit/Makefile | 3 +-
kunit/test-test.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 103 insertions(+), 1 deletion(-)
create mode 100644 kunit/test-test.c
diff --git a/kunit/Makefile b/kunit/Makefile
index 1f7680cfa11ad..533355867abd2 100644
--- a/kunit/Makefile
+++ b/kunit/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_KUNIT) += test.o \
kunit-stream.o \
try-catch.o
-obj-$(CONFIG_KUNIT_TEST) += string-stream-test.o
+obj-$(CONFIG_KUNIT_TEST) += test-test.o \
+ string-stream-test.o
obj-$(CONFIG_KUNIT_EXAMPLE_TEST) += example-test.o
diff --git a/kunit/test-test.c b/kunit/test-test.c
new file mode 100644
index 0000000000000..88f4cdf03db2a
--- /dev/null
+++ b/kunit/test-test.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit test for core test infrastructure.
+ *
+ * Copyright (C) 2019, Google LLC.
+ * Author: Brendan Higgins <brendanhiggins@google.com>
+ */
+#include <kunit/test.h>
+
+struct kunit_try_catch_test_context {
+ struct kunit_try_catch *try_catch;
+ bool function_called;
+};
+
+void kunit_test_successful_try(void *data)
+{
+ struct kunit *test = data;
+ struct kunit_try_catch_test_context *ctx = test->priv;
+
+ ctx->function_called = true;
+}
+
+void kunit_test_no_catch(void *data)
+{
+ struct kunit *test = data;
+
+ KUNIT_FAIL(test, "Catch should not be called\n");
+}
+
+static void kunit_test_try_catch_successful_try_no_catch(struct kunit *test)
+{
+ struct kunit_try_catch_test_context *ctx = test->priv;
+ struct kunit_try_catch *try_catch = ctx->try_catch;
+
+ kunit_try_catch_init(try_catch,
+ test,
+ kunit_test_successful_try,
+ kunit_test_no_catch);
+ kunit_try_catch_run(try_catch, test);
+
+ KUNIT_EXPECT_TRUE(test, ctx->function_called);
+}
+
+void kunit_test_unsuccessful_try(void *data)
+{
+ struct kunit *test = data;
+ struct kunit_try_catch_test_context *ctx = test->priv;
+ struct kunit_try_catch *try_catch = ctx->try_catch;
+
+ kunit_try_catch_throw(try_catch);
+ KUNIT_FAIL(test, "This line should never be reached\n");
+}
+
+void kunit_test_catch(void *data)
+{
+ struct kunit *test = data;
+ struct kunit_try_catch_test_context *ctx = test->priv;
+
+ ctx->function_called = true;
+}
+
+static void kunit_test_try_catch_unsuccessful_try_does_catch(struct kunit *test)
+{
+ struct kunit_try_catch_test_context *ctx = test->priv;
+ struct kunit_try_catch *try_catch = ctx->try_catch;
+
+ kunit_try_catch_init(try_catch,
+ test,
+ kunit_test_unsuccessful_try,
+ kunit_test_catch);
+ kunit_try_catch_run(try_catch, test);
+
+ KUNIT_EXPECT_TRUE(test, ctx->function_called);
+}
+
+static int kunit_try_catch_test_init(struct kunit *test)
+{
+ struct kunit_try_catch_test_context *ctx;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ test->priv = ctx;
+
+ ctx->try_catch = kunit_kmalloc(test,
+ sizeof(*ctx->try_catch),
+ GFP_KERNEL);
+
+ return 0;
+}
+
+static struct kunit_case kunit_try_catch_test_cases[] = {
+ KUNIT_CASE(kunit_test_try_catch_successful_try_no_catch),
+ KUNIT_CASE(kunit_test_try_catch_unsuccessful_try_does_catch),
+ {}
+};
+
+static struct kunit_suite kunit_try_catch_test_suite = {
+ .name = "kunit-try-catch-test",
+ .init = kunit_try_catch_test_init,
+ .test_cases = kunit_try_catch_test_cases,
+};
+kunit_test_suite(kunit_try_catch_test_suite);
--
2.22.0.410.gd8fdbe21b5-goog
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v9 11/18] kunit: test: add the concept of assertions
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list, gregkh, jpoimboe, keescook, kieran.bingham, mcgrof,
peterz, robh, sboyd, shuah, tytso, yamada.masahiro
Cc: pmladek, linux-doc, amir73il, Brendan Higgins, dri-devel,
Alexander.Levin, linux-kselftest, linux-nvdimm, khilman,
knut.omang, wfg, joel, rientjes, jdike, dan.carpenter, devicetree,
linux-kbuild, Tim.Bird, linux-um, rostedt, julia.lawall,
kunit-dev, richard, rdunlap, linux-kernel, mpe, linux-fsdevel,
logang
In-Reply-To: <20190712081744.87097-1-brendanhiggins@google.com>
Add support for assertions which are like expectations except the test
terminates if the assertion is not satisfied.
The idea with assertions is that you use them to state all the
preconditions for your test. Logically speaking, these are the premises
of the test case, so if a premise isn't true, there is no point in
continuing the test case because there are no conclusions that can be
drawn without the premises. Whereas, the expectation is the thing you
are trying to prove. It is not used universally in x-unit style test
frameworks, but I really like it as a convention. You could still
express the idea of a premise using the above idiom, but I think
KUNIT_ASSERT_* states the intended idea perfectly.
Signed-off-by: Brendan Higgins <brendanhiggins@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
---
include/kunit/test.h | 499 ++++++++++++++++++++++++++++++++++++-
kunit/string-stream-test.c | 12 +-
kunit/test-test.c | 2 +
kunit/test.c | 66 +++++
4 files changed, 570 insertions(+), 9 deletions(-)
diff --git a/include/kunit/test.h b/include/kunit/test.h
index 01440f3569847..e97273eb52f55 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -86,9 +86,10 @@ struct kunit;
* @name: the name of the test case.
*
* A test case is a function with the signature, ``void (*)(struct kunit *)``
- * that makes expectations (see KUNIT_EXPECT_TRUE()) about code under test. Each
- * test case is associated with a &struct kunit_suite and will be run after the
- * suite's init function and followed by the suite's exit function.
+ * that makes expectations and assertions (see KUNIT_EXPECT_TRUE() and
+ * KUNIT_ASSERT_TRUE()) about code under test. Each test case is associated with
+ * a &struct kunit_suite and will be run after the suite's init function and
+ * followed by the suite's exit function.
*
* A test case should be static and should only be created with the KUNIT_CASE()
* macro; additionally, every array of test cases should be terminated with an
@@ -836,4 +837,496 @@ do { \
KUNIT_EXPECT_END(test, !IS_ERR_OR_NULL(__ptr), __stream); \
} while (0)
+static inline struct kunit_stream *kunit_assert_start(struct kunit *test,
+ const char *file,
+ const char *line)
+{
+ struct kunit_stream *stream = alloc_kunit_stream(test, KERN_ERR);
+
+ kunit_stream_add(stream, "ASSERTION FAILED at %s:%s\n\t", file, line);
+
+ return stream;
+}
+
+static inline void kunit_assert_end(struct kunit *test,
+ bool success,
+ struct kunit_stream *stream)
+{
+ if (!success) {
+ kunit_fail(test, stream);
+ kunit_abort(test);
+ } else {
+ kunit_stream_clear(stream);
+ }
+}
+
+#define KUNIT_ASSERT_START(test) \
+ kunit_assert_start(test, __FILE__, __stringify(__LINE__))
+
+#define KUNIT_ASSERT_END(test, success, stream) \
+ kunit_assert_end(test, success, stream)
+
+#define KUNIT_ASSERT(test, success, message) do { \
+ struct kunit_stream *__stream = KUNIT_ASSERT_START(test); \
+ \
+ kunit_stream_add(__stream, message); \
+ KUNIT_ASSERT_END(test, success, __stream); \
+} while (0)
+
+#define KUNIT_ASSERT_MSG(test, success, message, fmt, ...) do { \
+ struct kunit_stream *__stream = KUNIT_ASSERT_START(test); \
+ \
+ kunit_stream_add(__stream, message); \
+ kunit_stream_add(__stream, fmt, ##__VA_ARGS__); \
+ KUNIT_ASSERT_END(test, success, __stream); \
+} while (0)
+
+#define KUNIT_ASSERT_FAILURE(test, fmt, ...) do { \
+ struct kunit_stream *__stream = KUNIT_ASSERT_START(test); \
+ \
+ kunit_stream_add(__stream, fmt, ##__VA_ARGS__); \
+ KUNIT_ASSERT_END(test, false, __stream); \
+} while (0)
+
+/**
+ * KUNIT_ASSERT_TRUE() - Sets an assertion that @condition is true.
+ * @test: The test context object.
+ * @condition: an arbitrary boolean expression. The test fails and aborts when
+ * this does not evaluate to true.
+ *
+ * This and assertions of the form `KUNIT_ASSERT_*` will cause the test case to
+ * fail *and immediately abort* when the specified condition is not met. Unlike
+ * an expectation failure, it will prevent the test case from continuing to run;
+ * this is otherwise known as an *assertion failure*.
+ */
+#define KUNIT_ASSERT_TRUE(test, condition) \
+ KUNIT_ASSERT(test, (condition), \
+ "Asserted " #condition " is true, but is false\n")
+
+#define KUNIT_ASSERT_TRUE_MSG(test, condition, fmt, ...) \
+ KUNIT_ASSERT_MSG(test, (condition), \
+ "Asserted " #condition " is true, but is false\n",\
+ fmt, ##__VA_ARGS__)
+
+/**
+ * KUNIT_ASSERT_FALSE() - Sets an assertion that @condition is false.
+ * @test: The test context object.
+ * @condition: an arbitrary boolean expression.
+ *
+ * Sets an assertion that the value that @condition evaluates to is false. This
+ * is the same as KUNIT_EXPECT_FALSE(), except it causes an assertion failure
+ * (see KUNIT_ASSERT_TRUE()) when the assertion is not met.
+ */
+#define KUNIT_ASSERT_FALSE(test, condition) \
+ KUNIT_ASSERT(test, !(condition), \
+ "Asserted " #condition " is false, but is true\n")
+
+#define KUNIT_ASSERT_FALSE_MSG(test, condition, fmt, ...) \
+ KUNIT_ASSERT_MSG(test, !(condition), \
+ "Asserted " #condition " is false, but is true\n",\
+ fmt, ##__VA_ARGS__)
+
+void kunit_assert_binary_msg(struct kunit *test,
+ long long left, const char *left_name,
+ long long right, const char *right_name,
+ bool compare_result,
+ const char *compare_name,
+ const char *file,
+ const char *line,
+ const char *fmt, ...);
+
+static inline void kunit_assert_binary(struct kunit *test,
+ long long left, const char *left_name,
+ long long right, const char *right_name,
+ bool compare_result,
+ const char *compare_name,
+ const char *file,
+ const char *line)
+{
+ kunit_assert_binary_msg(test,
+ left, left_name,
+ right, right_name,
+ compare_result,
+ compare_name,
+ file,
+ line,
+ NULL);
+}
+
+void kunit_assert_ptr_binary_msg(struct kunit *test,
+ void *left, const char *left_name,
+ void *right, const char *right_name,
+ bool compare_result,
+ const char *compare_name,
+ const char *file,
+ const char *line,
+ const char *fmt, ...);
+
+static inline void kunit_assert_ptr_binary(struct kunit *test,
+ void *left, const char *left_name,
+ void *right, const char *right_name,
+ bool compare_result,
+ const char *compare_name,
+ const char *file,
+ const char *line)
+{
+ kunit_assert_ptr_binary_msg(test,
+ left, left_name,
+ right, right_name,
+ compare_result,
+ compare_name,
+ file,
+ line,
+ NULL);
+}
+
+/*
+ * A factory macro for defining the expectations for the basic comparisons
+ * defined for the built in types.
+ *
+ * Unfortunately, there is no common type that all types can be promoted to for
+ * which all the binary operators behave the same way as for the actual types
+ * (for example, there is no type that long long and unsigned long long can
+ * both be cast to where the comparison result is preserved for all values). So
+ * the best we can do is do the comparison in the original types and then coerce
+ * everything to long long for printing; this way, the comparison behaves
+ * correctly and the printed out value usually makes sense without
+ * interpretation, but can always be interpretted to figure out the actual
+ * value.
+ */
+#define KUNIT_ASSERT_BINARY(test, left, condition, right) do { \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ __kunit_typecheck(__left, __right); \
+ kunit_assert_binary(test, \
+ (long long) __left, #left, \
+ (long long) __right, #right, \
+ __left condition __right, #condition, \
+ __FILE__, __stringify(__LINE__)); \
+} while (0)
+
+#define KUNIT_ASSERT_BINARY_MSG(test, left, condition, right, fmt, ...) do { \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ __kunit_typecheck(__left, __right); \
+ kunit_assert_binary_msg(test, \
+ (long long) __left, #left, \
+ (long long) __right, #right, \
+ __left condition __right, #condition, \
+ __FILE__, __stringify(__LINE__), \
+ fmt, ##__VA_ARGS__); \
+} while (0)
+
+/*
+ * Just like KUNIT_EXPECT_BINARY, but for comparing pointer types.
+ */
+#define KUNIT_ASSERT_PTR_BINARY(test, left, condition, right) do { \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ __kunit_typecheck(__left, __right); \
+ kunit_assert_ptr_binary(test, \
+ (void *) __left, #left, \
+ (void *) __right, #right, \
+ __left condition __right, #condition, \
+ __FILE__, __stringify(__LINE__)); \
+} while (0)
+
+#define KUNIT_ASSERT_PTR_BINARY_MSG(test, left, condition, right, fmt, ...) \
+do { \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ __kunit_typecheck(__left, __right); \
+ kunit_assert_ptr_binary_msg(test, \
+ (void *) __left, #left, \
+ (void *) __right, #right, \
+ __left condition __right, #condition, \
+ __FILE__, __stringify(__LINE__), \
+ fmt, ##__VA_ARGS__); \
+} while (0)
+
+/**
+ * KUNIT_ASSERT_EQ() - Sets an assertion that @left and @right are equal.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a primitive C type.
+ * @right: an arbitrary expression that evaluates to a primitive C type.
+ *
+ * Sets an assertion that the values that @left and @right evaluate to are
+ * equal. This is the same as KUNIT_EXPECT_EQ(), except it causes an assertion
+ * failure (see KUNIT_ASSERT_TRUE()) when the assertion is not met.
+ */
+#define KUNIT_ASSERT_EQ(test, left, right) \
+ KUNIT_ASSERT_BINARY(test, left, ==, right)
+
+#define KUNIT_ASSERT_EQ_MSG(test, left, right, fmt, ...) \
+ KUNIT_ASSERT_BINARY_MSG(test, \
+ left, \
+ ==, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
+ * KUNIT_ASSERT_PTR_EQ() - Asserts that pointers @left and @right are equal.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a pointer.
+ * @right: an arbitrary expression that evaluates to a pointer.
+ *
+ * Sets an assertion that the values that @left and @right evaluate to are
+ * equal. This is the same as KUNIT_EXPECT_EQ(), except it causes an assertion
+ * failure (see KUNIT_ASSERT_TRUE()) when the assertion is not met.
+ */
+#define KUNIT_ASSERT_PTR_EQ(test, left, right) \
+ KUNIT_ASSERT_PTR_BINARY(test, left, ==, right)
+
+#define KUNIT_ASSERT_PTR_EQ_MSG(test, left, right, fmt, ...) \
+ KUNIT_ASSERT_PTR_BINARY_MSG(test, \
+ left, \
+ ==, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
+ * KUNIT_ASSERT_NE() - An assertion that @left and @right are not equal.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a primitive C type.
+ * @right: an arbitrary expression that evaluates to a primitive C type.
+ *
+ * Sets an assertion that the values that @left and @right evaluate to are not
+ * equal. This is the same as KUNIT_EXPECT_NE(), except it causes an assertion
+ * failure (see KUNIT_ASSERT_TRUE()) when the assertion is not met.
+ */
+#define KUNIT_ASSERT_NE(test, left, right) \
+ KUNIT_ASSERT_BINARY(test, left, !=, right)
+
+#define KUNIT_ASSERT_NE_MSG(test, left, right, fmt, ...) \
+ KUNIT_ASSERT_BINARY_MSG(test, \
+ left, \
+ !=, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
+ * KUNIT_ASSERT_PTR_NE() - Asserts that pointers @left and @right are not equal.
+ * KUNIT_ASSERT_PTR_EQ() - Asserts that pointers @left and @right are equal.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a pointer.
+ * @right: an arbitrary expression that evaluates to a pointer.
+ *
+ * Sets an assertion that the values that @left and @right evaluate to are not
+ * equal. This is the same as KUNIT_EXPECT_NE(), except it causes an assertion
+ * failure (see KUNIT_ASSERT_TRUE()) when the assertion is not met.
+ */
+#define KUNIT_ASSERT_PTR_NE(test, left, right) \
+ KUNIT_ASSERT_PTR_BINARY(test, left, !=, right)
+
+#define KUNIT_ASSERT_PTR_NE_MSG(test, left, right, fmt, ...) \
+ KUNIT_ASSERT_PTR_BINARY_MSG(test, \
+ left, \
+ !=, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+/**
+ * KUNIT_ASSERT_LT() - An assertion that @left is less than @right.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a primitive C type.
+ * @right: an arbitrary expression that evaluates to a primitive C type.
+ *
+ * Sets an assertion that the value that @left evaluates to is less than the
+ * value that @right evaluates to. This is the same as KUNIT_EXPECT_LT(), except
+ * it causes an assertion failure (see KUNIT_ASSERT_TRUE()) when the assertion
+ * is not met.
+ */
+#define KUNIT_ASSERT_LT(test, left, right) \
+ KUNIT_ASSERT_BINARY(test, left, <, right)
+
+#define KUNIT_ASSERT_LT_MSG(test, left, right, fmt, ...) \
+ KUNIT_ASSERT_BINARY_MSG(test, \
+ left, \
+ <, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+/**
+ * KUNIT_ASSERT_LE() - An assertion that @left is less than or equal to @right.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a primitive C type.
+ * @right: an arbitrary expression that evaluates to a primitive C type.
+ *
+ * Sets an assertion that the value that @left evaluates to is less than or
+ * equal to the value that @right evaluates to. This is the same as
+ * KUNIT_EXPECT_LE(), except it causes an assertion failure (see
+ * KUNIT_ASSERT_TRUE()) when the assertion is not met.
+ */
+#define KUNIT_ASSERT_LE(test, left, right) \
+ KUNIT_ASSERT_BINARY(test, left, <=, right)
+
+#define KUNIT_ASSERT_LE_MSG(test, left, right, fmt, ...) \
+ KUNIT_ASSERT_BINARY_MSG(test, \
+ left, \
+ <=, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+/**
+ * KUNIT_ASSERT_GT() - An assertion that @left is greater than @right.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a primitive C type.
+ * @right: an arbitrary expression that evaluates to a primitive C type.
+ *
+ * Sets an assertion that the value that @left evaluates to is greater than the
+ * value that @right evaluates to. This is the same as KUNIT_EXPECT_GT(), except
+ * it causes an assertion failure (see KUNIT_ASSERT_TRUE()) when the assertion
+ * is not met.
+ */
+#define KUNIT_ASSERT_GT(test, left, right) \
+ KUNIT_ASSERT_BINARY(test, left, >, right)
+
+#define KUNIT_ASSERT_GT_MSG(test, left, right, fmt, ...) \
+ KUNIT_ASSERT_BINARY_MSG(test, \
+ left, \
+ >, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
+ * KUNIT_ASSERT_GE() - Assertion that @left is greater than or equal to @right.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a primitive C type.
+ * @right: an arbitrary expression that evaluates to a primitive C type.
+ *
+ * Sets an assertion that the value that @left evaluates to is greater than the
+ * value that @right evaluates to. This is the same as KUNIT_EXPECT_GE(), except
+ * it causes an assertion failure (see KUNIT_ASSERT_TRUE()) when the assertion
+ * is not met.
+ */
+#define KUNIT_ASSERT_GE(test, left, right) \
+ KUNIT_ASSERT_BINARY(test, left, >=, right)
+
+#define KUNIT_ASSERT_GE_MSG(test, left, right, fmt, ...) \
+ KUNIT_ASSERT_BINARY_MSG(test, \
+ left, \
+ >=, \
+ right, \
+ fmt, \
+ ##__VA_ARGS__)
+
+/**
+ * KUNIT_ASSERT_STREQ() - An assertion that strings @left and @right are equal.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a null terminated string.
+ * @right: an arbitrary expression that evaluates to a null terminated string.
+ *
+ * Sets an assertion that the values that @left and @right evaluate to are
+ * equal. This is the same as KUNIT_EXPECT_STREQ(), except it causes an
+ * assertion failure (see KUNIT_ASSERT_TRUE()) when the assertion is not met.
+ */
+#define KUNIT_ASSERT_STREQ(test, left, right) do { \
+ struct kunit_stream *__stream = KUNIT_ASSERT_START(test); \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ \
+ kunit_stream_add(__stream, "Asserted " #left " == " #right ", but\n"); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #left, __left); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #right, __right); \
+ \
+ KUNIT_ASSERT_END(test, !strcmp(left, right), __stream); \
+} while (0)
+
+#define KUNIT_ASSERT_STREQ_MSG(test, left, right, fmt, ...) do { \
+ struct kunit_stream *__stream = KUNIT_ASSERT_START(test); \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ \
+ kunit_stream_add(__stream, "Asserted " #left " == " #right ", but\n"); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #left, __left); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #right, __right); \
+ kunit_stream_add(__stream, fmt, ##__VA_ARGS__); \
+ \
+ KUNIT_ASSERT_END(test, !strcmp(left, right), __stream); \
+} while (0)
+
+/**
+ * KUNIT_ASSERT_STRNEQ() - Expects that strings @left and @right are not equal.
+ * @test: The test context object.
+ * @left: an arbitrary expression that evaluates to a null terminated string.
+ * @right: an arbitrary expression that evaluates to a null terminated string.
+ *
+ * Sets an expectation that the values that @left and @right evaluate to are
+ * not equal. This is semantically equivalent to
+ * KUNIT_ASSERT_TRUE(@test, strcmp((@left), (@right))). See KUNIT_ASSERT_TRUE()
+ * for more information.
+ */
+#define KUNIT_ASSERT_STRNEQ(test, left, right) do { \
+ struct kunit_stream *__stream = KUNIT_ASSERT_START(test); \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ \
+ kunit_stream_add(__stream, "Asserted " #left " == " #right ", but\n"); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #left, __left); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #right, __right); \
+ \
+ KUNIT_ASSERT_END(test, strcmp(left, right), __stream); \
+} while (0)
+
+#define KUNIT_ASSERT_STRNEQ_MSG(test, left, right, fmt, ...) do { \
+ struct kunit_stream *__stream = KUNIT_ASSERT_START(test); \
+ typeof(left) __left = (left); \
+ typeof(right) __right = (right); \
+ \
+ kunit_stream_add(__stream, "Asserted " #left " == " #right ", but\n"); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #left, __left); \
+ kunit_stream_add(__stream, "\t\t%s == %s\n", #right, __right); \
+ kunit_stream_add(__stream, fmt, ##__VA_ARGS__); \
+ \
+ KUNIT_ASSERT_END(test, strcmp(left, right), __stream); \
+} while (0)
+
+/**
+ * KUNIT_ASSERT_NOT_ERR_OR_NULL() - Assertion that @ptr is not null and not err.
+ * @test: The test context object.
+ * @ptr: an arbitrary pointer.
+ *
+ * Sets an assertion that the value that @ptr evaluates to is not null and not
+ * an errno stored in a pointer. This is the same as
+ * KUNIT_EXPECT_NOT_ERR_OR_NULL(), except it causes an assertion failure (see
+ * KUNIT_ASSERT_TRUE()) when the assertion is not met.
+ */
+#define KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr) do { \
+ struct kunit_stream *__stream = KUNIT_ASSERT_START(test); \
+ typeof(ptr) __ptr = (ptr); \
+ \
+ if (!__ptr) \
+ kunit_stream_add(__stream, \
+ "Asserted " #ptr " is not null, but is\n"); \
+ if (IS_ERR(__ptr)) \
+ kunit_stream_add(__stream, \
+ "Asserted " #ptr " is not error, but is: %ld\n",\
+ PTR_ERR(__ptr)); \
+ \
+ KUNIT_ASSERT_END(test, !IS_ERR_OR_NULL(__ptr), __stream); \
+} while (0)
+
+#define KUNIT_ASSERT_NOT_ERR_OR_NULL_MSG(test, ptr, fmt, ...) do { \
+ struct kunit_stream *__stream = KUNIT_ASSERT_START(test); \
+ typeof(ptr) __ptr = (ptr); \
+ \
+ if (!__ptr) { \
+ kunit_stream_add(__stream, \
+ "Asserted " #ptr " is not null, but is\n"); \
+ kunit_stream_add(__stream, fmt, ##__VA_ARGS__); \
+ } \
+ if (IS_ERR(__ptr)) { \
+ kunit_stream_add(__stream, \
+ "Asserted " #ptr " is not error, but is: %ld\n",\
+ PTR_ERR(__ptr)); \
+ \
+ kunit_stream_add(__stream, fmt, ##__VA_ARGS__); \
+ } \
+ KUNIT_ASSERT_END(test, !IS_ERR_OR_NULL(__ptr), __stream); \
+} while (0)
+
#endif /* _KUNIT_TEST_H */
diff --git a/kunit/string-stream-test.c b/kunit/string-stream-test.c
index b5641b078b8f6..5f27d576d2daf 100644
--- a/kunit/string-stream-test.c
+++ b/kunit/string-stream-test.c
@@ -34,7 +34,7 @@ static void string_stream_test_get_string(struct kunit *test)
string_stream_add(stream, " %s", "bar");
output = string_stream_get_string(stream);
- KUNIT_EXPECT_STREQ(test, output, "Foo bar");
+ KUNIT_ASSERT_STREQ(test, output, "Foo bar");
kfree(output);
}
@@ -48,16 +48,16 @@ static void string_stream_test_add_and_clear(struct kunit *test)
string_stream_add(stream, "A");
output = string_stream_get_string(stream);
- KUNIT_EXPECT_STREQ(test, output, "AAAAAAAAAA");
- KUNIT_EXPECT_EQ(test, stream->length, (size_t)10);
- KUNIT_EXPECT_FALSE(test, string_stream_is_empty(stream));
+ KUNIT_ASSERT_STREQ(test, output, "AAAAAAAAAA");
+ KUNIT_ASSERT_EQ(test, stream->length, (size_t)10);
+ KUNIT_ASSERT_FALSE(test, string_stream_is_empty(stream));
kfree(output);
string_stream_clear(stream);
output = string_stream_get_string(stream);
- KUNIT_EXPECT_STREQ(test, output, "");
- KUNIT_EXPECT_TRUE(test, string_stream_is_empty(stream));
+ KUNIT_ASSERT_STREQ(test, output, "");
+ KUNIT_ASSERT_TRUE(test, string_stream_is_empty(stream));
}
static struct kunit_case string_stream_test_cases[] = {
diff --git a/kunit/test-test.c b/kunit/test-test.c
index 88f4cdf03db2a..058f3fb37458a 100644
--- a/kunit/test-test.c
+++ b/kunit/test-test.c
@@ -78,11 +78,13 @@ static int kunit_try_catch_test_init(struct kunit *test)
struct kunit_try_catch_test_context *ctx;
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
test->priv = ctx;
ctx->try_catch = kunit_kmalloc(test,
sizeof(*ctx->try_catch),
GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->try_catch);
return 0;
}
diff --git a/kunit/test.c b/kunit/test.c
index 731f3c9eecf20..52b818d756704 100644
--- a/kunit/test.c
+++ b/kunit/test.c
@@ -501,3 +501,69 @@ void kunit_expect_ptr_binary_msg(struct kunit *test,
kunit_expect_end(test, compare_result, stream);
}
+
+void kunit_assert_binary_msg(struct kunit *test,
+ long long left, const char *left_name,
+ long long right, const char *right_name,
+ bool compare_result,
+ const char *compare_name,
+ const char *file,
+ const char *line,
+ const char *fmt, ...)
+{
+ struct kunit_stream *stream = kunit_assert_start(test, file, line);
+ struct va_format vaf;
+ va_list args;
+
+ kunit_stream_add(stream,
+ "Asserted %s %s %s, but\n",
+ left_name, compare_name, right_name);
+ kunit_stream_add(stream, "\t\t%s == %lld\n", left_name, left);
+ kunit_stream_add(stream, "\t\t%s == %lld\n", right_name, right);
+
+ if (fmt) {
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ kunit_stream_add(stream, "\n%pV", &vaf);
+
+ va_end(args);
+ }
+
+ kunit_assert_end(test, compare_result, stream);
+}
+
+void kunit_assert_ptr_binary_msg(struct kunit *test,
+ void *left, const char *left_name,
+ void *right, const char *right_name,
+ bool compare_result,
+ const char *compare_name,
+ const char *file,
+ const char *line,
+ const char *fmt, ...)
+{
+ struct kunit_stream *stream = kunit_assert_start(test, file, line);
+ struct va_format vaf;
+ va_list args;
+
+ kunit_stream_add(stream,
+ "Asserted %s %s %s, but\n",
+ left_name, compare_name, right_name);
+ kunit_stream_add(stream, "\t\t%s == %pK\n", left_name, left);
+ kunit_stream_add(stream, "\t\t%s == %pK", right_name, right);
+
+ if (fmt) {
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ kunit_stream_add(stream, "\n%pV", &vaf);
+
+ va_end(args);
+ }
+
+ kunit_assert_end(test, compare_result, stream);
+}
--
2.22.0.410.gd8fdbe21b5-goog
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v9 12/18] kunit: test: add tests for KUnit managed resources
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list, gregkh, jpoimboe, keescook, kieran.bingham, mcgrof,
peterz, robh, sboyd, shuah, tytso, yamada.masahiro
Cc: pmladek, linux-doc, amir73il, Brendan Higgins, dri-devel,
Alexander.Levin, linux-kselftest, linux-nvdimm, khilman,
knut.omang, wfg, joel, rientjes, jdike, dan.carpenter, devicetree,
linux-kbuild, Tim.Bird, Avinash Kondareddy, linux-um, rostedt,
julia.lawall, kunit-dev, richard, rdunlap, linux-kernel, mpe,
linux-fsdevel, logang
In-Reply-To: <20190712081744.87097-1-brendanhiggins@google.com>
From: Avinash Kondareddy <akndr41@gmail.com>
Add unit tests for KUnit managed resources. KUnit managed resources
(struct kunit_resource) are resources that are automatically cleaned up
at the end of a KUnit test, similar to the concept of devm_* managed
resources.
Signed-off-by: Avinash Kondareddy <akndr41@gmail.com>
Signed-off-by: Brendan Higgins <brendanhiggins@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
---
kunit/test-test.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 219 insertions(+)
diff --git a/kunit/test-test.c b/kunit/test-test.c
index 058f3fb37458a..b044659fe868b 100644
--- a/kunit/test-test.c
+++ b/kunit/test-test.c
@@ -101,3 +101,222 @@ static struct kunit_suite kunit_try_catch_test_suite = {
.test_cases = kunit_try_catch_test_cases,
};
kunit_test_suite(kunit_try_catch_test_suite);
+
+/*
+ * Context for testing test managed resources
+ * is_resource_initialized is used to test arbitrary resources
+ */
+struct kunit_test_resource_context {
+ struct kunit test;
+ bool is_resource_initialized;
+ int allocate_order[2];
+ int free_order[2];
+};
+
+static int fake_resource_init(struct kunit_resource *res, void *context)
+{
+ struct kunit_test_resource_context *ctx = context;
+
+ res->allocation = &ctx->is_resource_initialized;
+ ctx->is_resource_initialized = true;
+ return 0;
+}
+
+static void fake_resource_free(struct kunit_resource *res)
+{
+ bool *is_resource_initialized = res->allocation;
+
+ *is_resource_initialized = false;
+}
+
+static void kunit_resource_test_init_resources(struct kunit *test)
+{
+ struct kunit_test_resource_context *ctx = test->priv;
+
+ kunit_init_test(&ctx->test, "testing_test_init_test");
+
+ KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
+}
+
+static void kunit_resource_test_alloc_resource(struct kunit *test)
+{
+ struct kunit_test_resource_context *ctx = test->priv;
+ struct kunit_resource *res;
+ kunit_resource_free_t free = fake_resource_free;
+
+ res = kunit_alloc_resource(&ctx->test,
+ fake_resource_init,
+ fake_resource_free,
+ ctx);
+
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res);
+ KUNIT_EXPECT_PTR_EQ(test,
+ &ctx->is_resource_initialized,
+ (bool *) res->allocation);
+ KUNIT_EXPECT_TRUE(test, list_is_last(&res->node, &ctx->test.resources));
+ KUNIT_EXPECT_PTR_EQ(test, free, res->free);
+}
+
+static void kunit_resource_test_free_resource(struct kunit *test)
+{
+ struct kunit_test_resource_context *ctx = test->priv;
+ struct kunit_resource *res = kunit_alloc_resource(&ctx->test,
+ fake_resource_init,
+ fake_resource_free,
+ ctx);
+
+ kunit_free_resource(&ctx->test, res);
+
+ KUNIT_EXPECT_FALSE(test, ctx->is_resource_initialized);
+ KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
+}
+
+static void kunit_resource_test_cleanup_resources(struct kunit *test)
+{
+ int i;
+ struct kunit_test_resource_context *ctx = test->priv;
+ struct kunit_resource *resources[5];
+
+ for (i = 0; i < ARRAY_SIZE(resources); i++) {
+ resources[i] = kunit_alloc_resource(&ctx->test,
+ fake_resource_init,
+ fake_resource_free,
+ ctx);
+ }
+
+ kunit_cleanup(&ctx->test);
+
+ KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
+}
+
+static void kunit_resource_test_mark_order(int order_array[],
+ size_t order_size,
+ int key)
+{
+ int i;
+
+ for (i = 0; i < order_size && order_array[i]; i++)
+ ;
+
+ order_array[i] = key;
+}
+
+#define KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, order_field, key) \
+ kunit_resource_test_mark_order(ctx->order_field, \
+ ARRAY_SIZE(ctx->order_field), \
+ key)
+
+static int fake_resource_2_init(struct kunit_resource *res, void *context)
+{
+ struct kunit_test_resource_context *ctx = context;
+
+ KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 2);
+
+ res->allocation = ctx;
+
+ return 0;
+}
+
+static void fake_resource_2_free(struct kunit_resource *res)
+{
+ struct kunit_test_resource_context *ctx = res->allocation;
+
+ KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 2);
+}
+
+static int fake_resource_1_init(struct kunit_resource *res, void *context)
+{
+ struct kunit_test_resource_context *ctx = context;
+
+ kunit_alloc_resource(&ctx->test,
+ fake_resource_2_init,
+ fake_resource_2_free,
+ ctx);
+
+ KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 1);
+
+ res->allocation = ctx;
+
+ return 0;
+}
+
+static void fake_resource_1_free(struct kunit_resource *res)
+{
+ struct kunit_test_resource_context *ctx = res->allocation;
+
+ KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 1);
+}
+
+/*
+ * TODO(brendanhiggins@google.com): replace the arrays that keep track of the
+ * order of allocation and freeing with strict mocks using the IN_SEQUENCE macro
+ * to assert allocation and freeing order when the feature becomes available.
+ */
+static void kunit_resource_test_proper_free_ordering(struct kunit *test)
+{
+ struct kunit_test_resource_context *ctx = test->priv;
+
+ /* fake_resource_1 allocates a fake_resource_2 in its init. */
+ kunit_alloc_resource(&ctx->test,
+ fake_resource_1_init,
+ fake_resource_1_free,
+ ctx);
+
+ /*
+ * Since fake_resource_2_init calls KUNIT_RESOURCE_TEST_MARK_ORDER
+ * before returning to fake_resource_1_init, it should be the first to
+ * put its key in the allocate_order array.
+ */
+ KUNIT_EXPECT_EQ(test, ctx->allocate_order[0], 2);
+ KUNIT_EXPECT_EQ(test, ctx->allocate_order[1], 1);
+
+ kunit_cleanup(&ctx->test);
+
+ /*
+ * Because fake_resource_2 finishes allocation before fake_resource_1,
+ * fake_resource_1 should be freed first since it could depend on
+ * fake_resource_2.
+ */
+ KUNIT_EXPECT_EQ(test, ctx->free_order[0], 1);
+ KUNIT_EXPECT_EQ(test, ctx->free_order[1], 2);
+}
+
+static int kunit_resource_test_init(struct kunit *test)
+{
+ struct kunit_test_resource_context *ctx =
+ kzalloc(sizeof(*ctx), GFP_KERNEL);
+
+ if (!ctx)
+ return -ENOMEM;
+
+ test->priv = ctx;
+
+ kunit_init_test(&ctx->test, "test_test_context");
+
+ return 0;
+}
+
+static void kunit_resource_test_exit(struct kunit *test)
+{
+ struct kunit_test_resource_context *ctx = test->priv;
+
+ kunit_cleanup(&ctx->test);
+ kfree(ctx);
+}
+
+static struct kunit_case kunit_resource_test_cases[] = {
+ KUNIT_CASE(kunit_resource_test_init_resources),
+ KUNIT_CASE(kunit_resource_test_alloc_resource),
+ KUNIT_CASE(kunit_resource_test_free_resource),
+ KUNIT_CASE(kunit_resource_test_cleanup_resources),
+ KUNIT_CASE(kunit_resource_test_proper_free_ordering),
+ {}
+};
+
+static struct kunit_suite kunit_resource_test_suite = {
+ .name = "kunit-resource-test",
+ .init = kunit_resource_test_init,
+ .exit = kunit_resource_test_exit,
+ .test_cases = kunit_resource_test_cases,
+};
+kunit_test_suite(kunit_resource_test_suite);
--
2.22.0.410.gd8fdbe21b5-goog
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v9 13/18] kunit: tool: add Python wrappers for running KUnit tests
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
jpoimboe-H+wXaHxf7aLQT0dZR+AlfA, keescook-hpIqsD4AKlfQT0dZR+AlfA,
kieran.bingham-ryLnwIuWjnjg/C1BVhZhaw,
mcgrof-DgEjT+Ai2ygdnm+yROfE0A, peterz-wEGCiKHe2LqWVfeAwA7xHQ,
robh-DgEjT+Ai2ygdnm+yROfE0A, sboyd-DgEjT+Ai2ygdnm+yROfE0A,
shuah-DgEjT+Ai2ygdnm+yROfE0A, tytso-3s7WtUTddSA,
yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A
Cc: pmladek-IBi9RG/b67k, linux-doc-u79uwXL29TY76Z2rM5mHXA,
amir73il-Re5JQEeQqe8AvxtiuMwx3w, Brendan Higgins,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
Alexander.Levin-0li6OtcxBFHby3iVrkZq2A,
linux-kselftest-u79uwXL29TY76Z2rM5mHXA,
linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw,
khilman-rdvid1DuHRBWk0Htik3J/w, knut.omang-QHcLZuEGTsvQT0dZR+AlfA,
Felix Guo, wfg-VuQAYsv1563Yd54FQh9/CA,
joel-U3u1mxZcP9KHXe+LvDLADg, rientjes-hpIqsD4AKlfQT0dZR+AlfA,
jdike-OPE4K8JWMJJBDgjK7y7TUQ,
dan.carpenter-QHcLZuEGTsvQT0dZR+AlfA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kbuild-u79uwXL29TY76Z2rM5mHXA, Tim.Bird-7U/KSKJipcs,
linux-um-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
rostedt-nx8X9YLhiw1AfugRpC6u6w, julia.lawall-L2FTfq7BK8M,
kunit-dev-/JYPxA39Uh5TLH3MbocFFw, richard-/L3Ra7n9ekc,
rdunlap-wEGCiKHe2LqWVfeAwA7xHQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, daniel-/w4YWyX8dFk,
mpe-Gsx/Oe8HsFggBc27wqDAHg, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20190712081744.87097-1-brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
From: Felix Guo <felixguoxiuping-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
The ultimate goal is to create minimal isolated test binaries; in the
meantime we are using UML to provide the infrastructure to run tests, so
define an abstract way to configure and run tests that allow us to
change the context in which tests are built without affecting the user.
This also makes pretty and dynamic error reporting, and a lot of other
nice features easier.
kunit_config.py:
- parse .config and Kconfig files.
kunit_kernel.py: provides helper functions to:
- configure the kernel using kunitconfig.
- build the kernel with the appropriate configuration.
- provide function to invoke the kernel and stream the output back.
kunit_parser.py: parses raw logs returned out by kunit_kernel and
displays them in a user friendly way.
test_data/*: samples of test data for testing kunit.py, kunit_config.py,
etc.
Signed-off-by: Felix Guo <felixguoxiuping-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Reviewed-by: Greg Kroah-Hartman <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>
Reviewed-by: Logan Gunthorpe <logang-OTvnGxWRz7hWk0Htik3J/w@public.gmane.org>
---
tools/testing/kunit/.gitignore | 3 +
tools/testing/kunit/kunit.py | 116 +++++++
tools/testing/kunit/kunit_config.py | 66 ++++
tools/testing/kunit/kunit_kernel.py | 148 +++++++++
tools/testing/kunit/kunit_parser.py | 290 ++++++++++++++++++
tools/testing/kunit/kunit_tool_test.py | 206 +++++++++++++
.../test_is_test_passed-all_passed.log | 32 ++
.../test_data/test_is_test_passed-crash.log | 69 +++++
.../test_data/test_is_test_passed-failure.log | 36 +++
.../test_is_test_passed-no_tests_run.log | 75 +++++
.../test_output_isolated_correctly.log | 106 +++++++
.../test_data/test_read_from_file.kconfig | 17 +
12 files changed, 1164 insertions(+)
create mode 100644 tools/testing/kunit/.gitignore
create mode 100755 tools/testing/kunit/kunit.py
create mode 100644 tools/testing/kunit/kunit_config.py
create mode 100644 tools/testing/kunit/kunit_kernel.py
create mode 100644 tools/testing/kunit/kunit_parser.py
create mode 100755 tools/testing/kunit/kunit_tool_test.py
create mode 100644 tools/testing/kunit/test_data/test_is_test_passed-all_passed.log
create mode 100644 tools/testing/kunit/test_data/test_is_test_passed-crash.log
create mode 100644 tools/testing/kunit/test_data/test_is_test_passed-failure.log
create mode 100644 tools/testing/kunit/test_data/test_is_test_passed-no_tests_run.log
create mode 100644 tools/testing/kunit/test_data/test_output_isolated_correctly.log
create mode 100644 tools/testing/kunit/test_data/test_read_from_file.kconfig
diff --git a/tools/testing/kunit/.gitignore b/tools/testing/kunit/.gitignore
new file mode 100644
index 0000000000000..c791ff59a37a9
--- /dev/null
+++ b/tools/testing/kunit/.gitignore
@@ -0,0 +1,3 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
\ No newline at end of file
diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
new file mode 100755
index 0000000000000..da11bd62a4b82
--- /dev/null
+++ b/tools/testing/kunit/kunit.py
@@ -0,0 +1,116 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# A thin wrapper on top of the KUnit Kernel
+#
+# Copyright (C) 2019, Google LLC.
+# Author: Felix Guo <felixguoxiuping-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+# Author: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
+
+import argparse
+import sys
+import os
+import time
+
+from collections import namedtuple
+from enum import Enum, auto
+
+import kunit_config
+import kunit_kernel
+import kunit_parser
+
+KunitResult = namedtuple('KunitResult', ['status','result'])
+
+KunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs', 'build_dir'])
+
+class KunitStatus(Enum):
+ SUCCESS = auto()
+ CONFIG_FAILURE = auto()
+ BUILD_FAILURE = auto()
+ TEST_FAILURE = auto()
+
+def run_tests(linux: kunit_kernel.LinuxSourceTree,
+ request: KunitRequest) -> KunitResult:
+ config_start = time.time()
+ success = linux.build_reconfig(request.build_dir)
+ config_end = time.time()
+ if not success:
+ return KunitResult(KunitStatus.CONFIG_FAILURE, 'could not configure kernel')
+
+ kunit_parser.print_with_timestamp('Building KUnit Kernel ...')
+
+ build_start = time.time()
+ success = linux.build_um_kernel(request.jobs, request.build_dir)
+ build_end = time.time()
+ if not success:
+ return KunitResult(KunitStatus.BUILD_FAILURE, 'could not build kernel')
+
+ kunit_parser.print_with_timestamp('Starting KUnit Kernel ...')
+ test_start = time.time()
+
+ test_result = kunit_parser.TestResult(kunit_parser.TestStatus.SUCCESS,
+ [],
+ 'Tests not Parsed.')
+ if request.raw_output:
+ kunit_parser.raw_output(
+ linux.run_kernel(timeout=request.timeout))
+ else:
+ kunit_output = linux.run_kernel(timeout=request.timeout)
+ test_result = kunit_parser.parse_run_tests(kunit_output)
+ test_end = time.time()
+
+ kunit_parser.print_with_timestamp((
+ 'Elapsed time: %.3fs total, %.3fs configuring, %.3fs ' +
+ 'building, %.3fs running\n') % (
+ test_end - config_start,
+ config_end - config_start,
+ build_end - build_start,
+ test_end - test_start))
+
+ if test_result.status != kunit_parser.TestStatus.SUCCESS:
+ return KunitResult(KunitStatus.TEST_FAILURE, test_result)
+ else:
+ return KunitResult(KunitStatus.SUCCESS, test_result)
+
+def main(argv, linux):
+ parser = argparse.ArgumentParser(
+ description='Helps writing and running KUnit tests.')
+ subparser = parser.add_subparsers(dest='subcommand')
+
+ run_parser = subparser.add_parser('run', help='Runs KUnit tests.')
+ run_parser.add_argument('--raw_output', help='don\'t format output from kernel',
+ action='store_true')
+
+ run_parser.add_argument('--timeout',
+ help='maximum number of seconds to allow for all tests '
+ 'to run. This does not include time taken to build the '
+ 'tests.',
+ type=int,
+ default=300,
+ metavar='timeout')
+
+ run_parser.add_argument('--jobs',
+ help='As in the make command, "Specifies the number of '
+ 'jobs (commands) to run simultaneously."',
+ type=int, default=8, metavar='jobs')
+
+ run_parser.add_argument('--build_dir',
+ help='As in the make command, it specifies the build '
+ 'directory.',
+ type=str, default=None, metavar='build_dir')
+
+ cli_args = parser.parse_args(argv)
+
+ if cli_args.subcommand == 'run':
+ request = KunitRequest(cli_args.raw_output,
+ cli_args.timeout,
+ cli_args.jobs,
+ cli_args.build_dir)
+ result = run_tests(linux, request)
+ if result.status != KunitStatus.SUCCESS:
+ sys.exit(1)
+ else:
+ parser.print_help()
+
+if __name__ == '__main__':
+ main(sys.argv[1:], kunit_kernel.LinuxSourceTree())
diff --git a/tools/testing/kunit/kunit_config.py b/tools/testing/kunit/kunit_config.py
new file mode 100644
index 0000000000000..ebf3942b23f51
--- /dev/null
+++ b/tools/testing/kunit/kunit_config.py
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Builds a .config from a kunitconfig.
+#
+# Copyright (C) 2019, Google LLC.
+# Author: Felix Guo <felixguoxiuping-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+# Author: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
+
+import collections
+import re
+
+CONFIG_IS_NOT_SET_PATTERN = r'^# CONFIG_\w+ is not set$'
+CONFIG_PATTERN = r'^CONFIG_\w+=\S+$'
+
+KconfigEntryBase = collections.namedtuple('KconfigEntry', ['raw_entry'])
+
+
+class KconfigEntry(KconfigEntryBase):
+
+ def __str__(self) -> str:
+ return self.raw_entry
+
+
+class KconfigParseError(Exception):
+ """Error parsing Kconfig defconfig or .config."""
+
+
+class Kconfig(object):
+ """Represents defconfig or .config specified using the Kconfig language."""
+
+ def __init__(self):
+ self._entries = []
+
+ def entries(self):
+ return set(self._entries)
+
+ def add_entry(self, entry: KconfigEntry) -> None:
+ self._entries.append(entry)
+
+ def is_subset_of(self, other: 'Kconfig') -> bool:
+ return self.entries().issubset(other.entries())
+
+ def write_to_file(self, path: str) -> None:
+ with open(path, 'w') as f:
+ for entry in self.entries():
+ f.write(str(entry) + '\n')
+
+ def parse_from_string(self, blob: str) -> None:
+ """Parses a string containing KconfigEntrys and populates this Kconfig."""
+ self._entries = []
+ is_not_set_matcher = re.compile(CONFIG_IS_NOT_SET_PATTERN)
+ config_matcher = re.compile(CONFIG_PATTERN)
+ for line in blob.split('\n'):
+ line = line.strip()
+ if not line:
+ continue
+ elif config_matcher.match(line) or is_not_set_matcher.match(line):
+ self._entries.append(KconfigEntry(line))
+ elif line[0] == '#':
+ continue
+ else:
+ raise KconfigParseError('Failed to parse: ' + line)
+
+ def read_from_file(self, path: str) -> None:
+ with open(path, 'r') as f:
+ self.parse_from_string(f.read())
diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py
new file mode 100644
index 0000000000000..07c0abf2f47df
--- /dev/null
+++ b/tools/testing/kunit/kunit_kernel.py
@@ -0,0 +1,148 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Runs UML kernel, collects output, and handles errors.
+#
+# Copyright (C) 2019, Google LLC.
+# Author: Felix Guo <felixguoxiuping-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+# Author: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
+
+
+import logging
+import subprocess
+import os
+
+import kunit_config
+
+KCONFIG_PATH = '.config'
+
+class ConfigError(Exception):
+ """Represents an error trying to configure the Linux kernel."""
+
+
+class BuildError(Exception):
+ """Represents an error trying to build the Linux kernel."""
+
+
+class LinuxSourceTreeOperations(object):
+ """An abstraction over command line operations performed on a source tree."""
+
+ def make_mrproper(self):
+ try:
+ subprocess.check_output(['make', 'mrproper'])
+ except OSError as e:
+ raise ConfigError('Could not call make command: ' + e)
+ except subprocess.CalledProcessError as e:
+ raise ConfigError(e.output)
+
+ def make_olddefconfig(self, build_dir):
+ command = ['make', 'ARCH=um', 'olddefconfig']
+ if build_dir:
+ command += ['O=' + build_dir]
+ try:
+ subprocess.check_output(command)
+ except OSError as e:
+ raise ConfigError('Could not call make command: ' + e)
+ except subprocess.CalledProcessError as e:
+ raise ConfigError(e.output)
+
+ def make(self, jobs, build_dir):
+ command = ['make', 'ARCH=um', '--jobs=' + str(jobs)]
+ if build_dir:
+ command += ['O=' + build_dir]
+ try:
+ subprocess.check_output(command)
+ except OSError as e:
+ raise BuildError('Could not call execute make: ' + e)
+ except subprocess.CalledProcessError as e:
+ raise BuildError(e.output)
+
+ def linux_bin(self, params, timeout, build_dir):
+ """Runs the Linux UML binary. Must be named 'linux'."""
+ linux_bin = './linux'
+ if build_dir:
+ linux_bin = os.path.join(build_dir, 'linux')
+ process = subprocess.Popen(
+ [linux_bin] + params,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ process.wait(timeout=timeout)
+ return process
+
+
+def get_kconfig_path(build_dir):
+ kconfig_path = KCONFIG_PATH
+ if build_dir:
+ kconfig_path = os.path.join(build_dir, KCONFIG_PATH)
+ return kconfig_path
+
+class LinuxSourceTree(object):
+ """Represents a Linux kernel source tree with KUnit tests."""
+
+ def __init__(self):
+ self._kconfig = kunit_config.Kconfig()
+ self._kconfig.read_from_file('kunitconfig')
+ self._ops = LinuxSourceTreeOperations()
+
+ def clean(self):
+ try:
+ self._ops.make_mrproper()
+ except ConfigError as e:
+ logging.error(e)
+ return False
+ return True
+
+ def build_config(self, build_dir):
+ kconfig_path = get_kconfig_path(build_dir)
+ if build_dir and not os.path.exists(build_dir):
+ os.mkdir(build_dir)
+ self._kconfig.write_to_file(kconfig_path)
+ try:
+ self._ops.make_olddefconfig(build_dir)
+ except ConfigError as e:
+ logging.error(e)
+ return False
+ validated_kconfig = kunit_config.Kconfig()
+ validated_kconfig.read_from_file(kconfig_path)
+ if not self._kconfig.is_subset_of(validated_kconfig):
+ logging.error('Provided Kconfig is not contained in validated .config!')
+ return False
+ return True
+
+ def build_reconfig(self, build_dir):
+ """Creates a new .config if it is not a subset of the kunitconfig."""
+ kconfig_path = get_kconfig_path(build_dir)
+ if os.path.exists(kconfig_path):
+ existing_kconfig = kunit_config.Kconfig()
+ existing_kconfig.read_from_file(kconfig_path)
+ if not self._kconfig.is_subset_of(existing_kconfig):
+ print('Regenerating .config ...')
+ os.remove(kconfig_path)
+ return self.build_config(build_dir)
+ else:
+ return True
+ else:
+ print('Generating .config ...')
+ return self.build_config(build_dir)
+
+ def build_um_kernel(self, jobs, build_dir):
+ try:
+ self._ops.make_olddefconfig(build_dir)
+ self._ops.make(jobs, build_dir)
+ except (ConfigError, BuildError) as e:
+ logging.error(e)
+ return False
+ used_kconfig = kunit_config.Kconfig()
+ used_kconfig.read_from_file(get_kconfig_path(build_dir))
+ if not self._kconfig.is_subset_of(used_kconfig):
+ logging.error('Provided Kconfig is not contained in final config!')
+ return False
+ return True
+
+ def run_kernel(self, args=[], timeout=None, build_dir=None):
+ args.extend(['mem=256M'])
+ process = self._ops.linux_bin(args, timeout, build_dir)
+ with open('test.log', 'w') as f:
+ for line in process.stdout:
+ f.write(line.rstrip().decode('ascii') + '\n')
+ yield line.rstrip().decode('ascii')
diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
new file mode 100644
index 0000000000000..f27f3d675c3bb
--- /dev/null
+++ b/tools/testing/kunit/kunit_parser.py
@@ -0,0 +1,290 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Parses test results from a kernel dmesg log.
+#
+# Copyright (C) 2019, Google LLC.
+# Author: Felix Guo <felixguoxiuping-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+# Author: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
+
+import re
+
+from collections import namedtuple
+from datetime import datetime
+from enum import Enum, auto
+from functools import reduce
+from typing import List
+
+TestResult = namedtuple('TestResult', ['status','suites','log'])
+
+class TestSuite(object):
+ def __init__(self):
+ self.status = None
+ self.name = None
+ self.cases = []
+
+ def __str__(self):
+ return 'TestSuite(' + self.status + ',' + self.name + ',' + str(self.cases) + ')'
+
+ def __repr__(self):
+ return str(self)
+
+class TestCase(object):
+ def __init__(self):
+ self.status = None
+ self.name = ''
+ self.log = []
+
+ def __str__(self):
+ return 'TestCase(' + self.status + ',' + self.name + ',' + str(self.log) + ')'
+
+ def __repr__(self):
+ return str(self)
+
+class TestStatus(Enum):
+ SUCCESS = auto()
+ FAILURE = auto()
+ TEST_CRASHED = auto()
+ NO_TESTS = auto()
+
+kunit_start_re = re.compile(r'^TAP version [0-9]+$')
+kunit_end_re = re.compile('List of all partitions:')
+
+def isolate_kunit_output(kernel_output):
+ started = False
+ for line in kernel_output:
+ if kunit_start_re.match(line):
+ started = True
+ yield line
+ elif kunit_end_re.match(line):
+ break
+ elif started:
+ yield line
+
+def raw_output(kernel_output):
+ for line in kernel_output:
+ print(line)
+
+DIVIDER = '=' * 60
+
+RESET = '\033[0;0m'
+
+def red(text):
+ return '\033[1;31m' + text + RESET
+
+def yellow(text):
+ return '\033[1;33m' + text + RESET
+
+def green(text):
+ return '\033[1;32m' + text + RESET
+
+def print_with_timestamp(message):
+ print('[%s] %s' % (datetime.now().strftime('%H:%M:%S'), message))
+
+def format_suite_divider(message):
+ return '======== ' + message + ' ========'
+
+def print_suite_divider(message):
+ print_with_timestamp(DIVIDER)
+ print_with_timestamp(format_suite_divider(message))
+
+def print_log(log):
+ for m in log:
+ print_with_timestamp(m)
+
+TAP_ENTRIES = re.compile(r'^(TAP|\t?ok|\t?not ok|\t?[0-9]+\.\.[0-9]+|\t?#).*$')
+
+def consume_non_diagnositic(lines: List[str]) -> None:
+ while not TAP_ENTRIES.match(lines[0]):
+ lines.pop(0)
+
+def save_non_diagnositic(lines: List[str], test_case: TestCase) -> None:
+ while not TAP_ENTRIES.match(lines[0]):
+ test_case.log.append(lines[0])
+ lines.pop(0)
+
+OkNotOkResult = namedtuple('OkNotOkResult', ['is_ok','description', 'text'])
+
+OK_NOT_OK_SUBTEST = re.compile(r'^\t(ok|not ok) [0-9]+ - (.*)$')
+
+OK_NOT_OK_MODULE = re.compile(r'^(ok|not ok) [0-9]+ - (.*)$')
+
+def parse_ok_not_ok_test_case(lines: List[str], test_case: TestCase) -> bool:
+ save_non_diagnositic(lines, test_case)
+ line = lines[0]
+ match = OK_NOT_OK_SUBTEST.match(line)
+ if match:
+ test_case.log.append(lines.pop(0))
+ test_case.name = match.group(2)
+ if test_case.status == TestStatus.TEST_CRASHED:
+ return True
+ if match.group(1) == 'ok':
+ test_case.status = TestStatus.SUCCESS
+ else:
+ test_case.status = TestStatus.FAILURE
+ return True
+ else:
+ return False
+
+SUBTEST_DIAGNOSTIC = re.compile(r'^\t# .*?: (.*)$')
+DIAGNOSTIC_CRASH_MESSAGE = 'kunit test case crashed!'
+
+def parse_diagnostic(lines: List[str], test_case: TestCase) -> bool:
+ save_non_diagnositic(lines, test_case)
+ line = lines[0]
+ match = SUBTEST_DIAGNOSTIC.match(line)
+ if match:
+ test_case.log.append(lines.pop(0))
+ if match.group(1) == DIAGNOSTIC_CRASH_MESSAGE:
+ test_case.status = TestStatus.TEST_CRASHED
+ return True
+ else:
+ return False
+
+def parse_test_case(lines: List[str]) -> TestCase:
+ test_case = TestCase()
+ save_non_diagnositic(lines, test_case)
+ while parse_diagnostic(lines, test_case):
+ pass
+ if parse_ok_not_ok_test_case(lines, test_case):
+ return test_case
+ else:
+ return None
+
+SUBTEST_HEADER = re.compile(r'^\t# Subtest: (.*)$')
+
+def parse_subtest_header(lines: List[str]) -> str:
+ consume_non_diagnositic(lines)
+ match = SUBTEST_HEADER.match(lines[0])
+ if match:
+ lines.pop(0)
+ return match.group(1)
+ else:
+ return None
+
+SUBTEST_PLAN = re.compile(r'\t[0-9]+\.\.([0-9]+)')
+
+def parse_subtest_plan(lines: List[str]) -> int:
+ consume_non_diagnositic(lines)
+ match = SUBTEST_PLAN.match(lines[0])
+ if match:
+ lines.pop(0)
+ return match.group(1)
+ else:
+ return None
+
+def max_status(left: TestStatus, right: TestStatus) -> TestStatus:
+ if left == TestStatus.TEST_CRASHED or right == TestStatus.TEST_CRASHED:
+ return TestStatus.TEST_CRASHED
+ elif left == TestStatus.FAILURE or right == TestStatus.FAILURE:
+ return TestStatus.FAILURE
+ elif left != TestStatus.SUCCESS:
+ return left
+ elif right != TestStatus.SUCCESS:
+ return right
+ else:
+ return TestStatus.SUCCESS
+
+def parse_ok_not_ok_test_suite(lines: List[str], test_suite: TestSuite) -> bool:
+ consume_non_diagnositic(lines)
+ line = lines[0]
+ match = OK_NOT_OK_MODULE.match(line)
+ if match:
+ lines.pop(0)
+ if match.group(1) == 'ok':
+ test_suite.status = TestStatus.SUCCESS
+ else:
+ test_suite.status = TestStatus.FAILURE
+ return True
+ else:
+ return False
+
+def bubble_up_errors(to_status, status_container_list) -> TestStatus:
+ status_list = map(to_status, status_container_list)
+ return reduce(max_status, status_list, TestStatus.SUCCESS)
+
+def bubble_up_test_case_errors(test_suite: TestSuite) -> TestStatus:
+ max_test_case_status = bubble_up_errors(lambda x: x.status, test_suite.cases)
+ return max_status(max_test_case_status, test_suite.status)
+
+def parse_test_suite(lines: List[str]) -> TestSuite:
+ if not lines:
+ return None
+ consume_non_diagnositic(lines)
+ test_suite = TestSuite()
+ test_suite.status = TestStatus.SUCCESS
+ name = parse_subtest_header(lines)
+ if not name:
+ return None
+ test_suite.name = name
+ test_case_num = parse_subtest_plan(lines)
+ if not test_case_num:
+ return None
+ test_case = parse_test_case(lines)
+ while test_case:
+ test_suite.cases.append(test_case)
+ test_case = parse_test_case(lines)
+ if parse_ok_not_ok_test_suite(lines, test_suite):
+ test_suite.status = bubble_up_test_case_errors(test_suite)
+ return test_suite
+ else:
+ print('failed to parse end of suite' + lines[0])
+ return None
+
+TAP_HEADER = re.compile(r'^TAP version 14$')
+
+def parse_tap_header(lines: List[str]) -> bool:
+ consume_non_diagnositic(lines)
+ if TAP_HEADER.match(lines[0]):
+ lines.pop(0)
+ return True
+ else:
+ return False
+
+def bubble_up_suite_errors(test_suite_list: List[TestSuite]) -> TestStatus:
+ return bubble_up_errors(lambda x: x.status, test_suite_list)
+
+def parse_test_result(lines: List[str]) -> TestResult:
+ if not lines:
+ return TestResult(TestStatus.NO_TESTS, [], lines)
+ consume_non_diagnositic(lines)
+ if not parse_tap_header(lines):
+ return None
+ test_suites = []
+ test_suite = parse_test_suite(lines)
+ while test_suite:
+ test_suites.append(test_suite)
+ test_suite = parse_test_suite(lines)
+ return TestResult(bubble_up_suite_errors(test_suites), test_suites, lines)
+
+def parse_run_tests(kernel_output) -> TestResult:
+ total_tests = 0
+ failed_tests = 0
+ crashed_tests = 0
+ test_result = parse_test_result(list(isolate_kunit_output(kernel_output)))
+ for test_suite in test_result.suites:
+ if test_suite.status == TestStatus.SUCCESS:
+ print_suite_divider(green('[PASSED] ') + test_suite.name)
+ elif test_suite.status == TestStatus.TEST_CRASHED:
+ print_suite_divider(red('[CRASHED] ' + test_suite.name))
+ else:
+ print_suite_divider(red('[FAILED] ') + test_suite.name)
+ for test_case in test_suite.cases:
+ total_tests += 1
+ if test_case.status == TestStatus.SUCCESS:
+ print_with_timestamp(green('[PASSED] ') + test_case.name)
+ elif test_case.status == TestStatus.TEST_CRASHED:
+ crashed_tests += 1
+ print_with_timestamp(red('[CRASHED] ' + test_case.name))
+ print_log(map(yellow, test_case.log))
+ print_with_timestamp('')
+ else:
+ failed_tests += 1
+ print_with_timestamp(red('[FAILED] ') + test_case.name)
+ print_log(map(yellow, test_case.log))
+ print_with_timestamp('')
+ print_with_timestamp(DIVIDER)
+ fmt = green if test_result.status == TestStatus.SUCCESS else red
+ print_with_timestamp(
+ fmt('Testing complete. %d tests run. %d failed. %d crashed.' %
+ (total_tests, failed_tests, crashed_tests)))
+ return test_result
diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
new file mode 100755
index 0000000000000..4a12baa0cd4e0
--- /dev/null
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -0,0 +1,206 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# A collection of tests for tools/testing/kunit/kunit.py
+#
+# Copyright (C) 2019, Google LLC.
+# Author: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
+
+import unittest
+from unittest import mock
+
+import tempfile, shutil # Handling test_tmpdir
+
+import os
+
+import kunit_config
+import kunit_parser
+import kunit_kernel
+import kunit
+
+test_tmpdir = ''
+
+def setUpModule():
+ global test_tmpdir
+ test_tmpdir = tempfile.mkdtemp()
+
+def tearDownModule():
+ shutil.rmtree(test_tmpdir)
+
+def get_absolute_path(path):
+ return os.path.join(os.path.dirname(__file__), path)
+
+class KconfigTest(unittest.TestCase):
+
+ def test_is_subset_of(self):
+ kconfig0 = kunit_config.Kconfig()
+ self.assertTrue(kconfig0.is_subset_of(kconfig0))
+
+ kconfig1 = kunit_config.Kconfig()
+ kconfig1.add_entry(kunit_config.KconfigEntry('CONFIG_TEST=y'))
+ self.assertTrue(kconfig1.is_subset_of(kconfig1))
+ self.assertTrue(kconfig0.is_subset_of(kconfig1))
+ self.assertFalse(kconfig1.is_subset_of(kconfig0))
+
+ def test_read_from_file(self):
+ kconfig = kunit_config.Kconfig()
+ kconfig_path = get_absolute_path(
+ 'test_data/test_read_from_file.kconfig')
+
+ kconfig.read_from_file(kconfig_path)
+
+ expected_kconfig = kunit_config.Kconfig()
+ expected_kconfig.add_entry(
+ kunit_config.KconfigEntry('CONFIG_UML=y'))
+ expected_kconfig.add_entry(
+ kunit_config.KconfigEntry('CONFIG_MMU=y'))
+ expected_kconfig.add_entry(
+ kunit_config.KconfigEntry('CONFIG_TEST=y'))
+ expected_kconfig.add_entry(
+ kunit_config.KconfigEntry('CONFIG_EXAMPLE_TEST=y'))
+ expected_kconfig.add_entry(
+ kunit_config.KconfigEntry('# CONFIG_MK8 is not set'))
+
+ self.assertEqual(kconfig.entries(), expected_kconfig.entries())
+
+ def test_write_to_file(self):
+ kconfig_path = os.path.join(test_tmpdir, '.config')
+
+ expected_kconfig = kunit_config.Kconfig()
+ expected_kconfig.add_entry(
+ kunit_config.KconfigEntry('CONFIG_UML=y'))
+ expected_kconfig.add_entry(
+ kunit_config.KconfigEntry('CONFIG_MMU=y'))
+ expected_kconfig.add_entry(
+ kunit_config.KconfigEntry('CONFIG_TEST=y'))
+ expected_kconfig.add_entry(
+ kunit_config.KconfigEntry('CONFIG_EXAMPLE_TEST=y'))
+ expected_kconfig.add_entry(
+ kunit_config.KconfigEntry('# CONFIG_MK8 is not set'))
+
+ expected_kconfig.write_to_file(kconfig_path)
+
+ actual_kconfig = kunit_config.Kconfig()
+ actual_kconfig.read_from_file(kconfig_path)
+
+ self.assertEqual(actual_kconfig.entries(),
+ expected_kconfig.entries())
+
+class KUnitParserTest(unittest.TestCase):
+
+ def assertContains(self, needle, haystack):
+ for line in haystack:
+ if needle in line:
+ return
+ raise AssertionError('"' +
+ str(needle) + '" not found in "' + str(haystack) + '"!')
+
+ def test_output_isolated_correctly(self):
+ log_path = get_absolute_path(
+ 'test_data/test_output_isolated_correctly.log')
+ file = open(log_path)
+ result = kunit_parser.isolate_kunit_output(file.readlines())
+ self.assertContains('TAP version 14\n', result)
+ self.assertContains(' # Subtest: example', result)
+ self.assertContains(' 1..2', result)
+ self.assertContains(' ok 1 - example_simple_test', result)
+ self.assertContains(' ok 2 - example_mock_test', result)
+ self.assertContains('ok 1 - example', result)
+ file.close()
+
+ def test_parse_successful_test_log(self):
+ all_passed_log = get_absolute_path(
+ 'test_data/test_is_test_passed-all_passed.log')
+ file = open(all_passed_log)
+ result = kunit_parser.parse_run_tests(file.readlines())
+ self.assertEqual(
+ kunit_parser.TestStatus.SUCCESS,
+ result.status)
+ file.close()
+
+ def test_parse_failed_test_log(self):
+ failed_log = get_absolute_path(
+ 'test_data/test_is_test_passed-failure.log')
+ file = open(failed_log)
+ result = kunit_parser.parse_run_tests(file.readlines())
+ self.assertEqual(
+ kunit_parser.TestStatus.FAILURE,
+ result.status)
+ file.close()
+
+ def test_no_tests(self):
+ empty_log = get_absolute_path(
+ 'test_data/test_is_test_passed-no_tests_run.log')
+ file = open(empty_log)
+ result = kunit_parser.parse_run_tests(
+ kunit_parser.isolate_kunit_output(file.readlines()))
+ self.assertEqual(0, len(result.suites))
+ self.assertEqual(
+ kunit_parser.TestStatus.NO_TESTS,
+ result.status)
+ file.close()
+
+ def test_crashed_test(self):
+ crashed_log = get_absolute_path(
+ 'test_data/test_is_test_passed-crash.log')
+ file = open(crashed_log)
+ result = kunit_parser.parse_run_tests(file.readlines())
+ self.assertEqual(
+ kunit_parser.TestStatus.TEST_CRASHED,
+ result.status)
+ file.close()
+
+class StrContains(str):
+ def __eq__(self, other):
+ return self in other
+
+class KUnitMainTest(unittest.TestCase):
+ def setUp(self):
+ path = get_absolute_path('test_data/test_is_test_passed-all_passed.log')
+ file = open(path)
+ all_passed_log = file.readlines()
+ self.print_patch = mock.patch('builtins.print')
+ self.print_mock = self.print_patch.start()
+ self.linux_source_mock = mock.Mock()
+ self.linux_source_mock.build_reconfig = mock.Mock(return_value=True)
+ self.linux_source_mock.build_um_kernel = mock.Mock(return_value=True)
+ self.linux_source_mock.run_kernel = mock.Mock(return_value=all_passed_log)
+
+ def tearDown(self):
+ self.print_patch.stop()
+ pass
+
+ def test_run_passes_args_pass(self):
+ kunit.main(['run'], self.linux_source_mock)
+ assert self.linux_source_mock.build_reconfig.call_count == 1
+ assert self.linux_source_mock.run_kernel.call_count == 1
+ self.print_mock.assert_any_call(StrContains('Testing complete.'))
+
+ def test_run_passes_args_fail(self):
+ self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
+ with self.assertRaises(SystemExit) as e:
+ kunit.main(['run'], self.linux_source_mock)
+ assert type(e.exception) == SystemExit
+ assert e.exception.code == 1
+ assert self.linux_source_mock.build_reconfig.call_count == 1
+ assert self.linux_source_mock.run_kernel.call_count == 1
+ self.print_mock.assert_any_call(StrContains(' 0 tests run'))
+
+ def test_run_raw_output(self):
+ self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
+ kunit.main(['run', '--raw_output'], self.linux_source_mock)
+ assert self.linux_source_mock.build_reconfig.call_count == 1
+ assert self.linux_source_mock.run_kernel.call_count == 1
+ for kall in self.print_mock.call_args_list:
+ assert kall != mock.call(StrContains('Testing complete.'))
+ assert kall != mock.call(StrContains(' 0 tests run'))
+
+ def test_run_timeout(self):
+ timeout = 3453
+ kunit.main(['run', '--timeout', str(timeout)], self.linux_source_mock)
+ assert self.linux_source_mock.build_reconfig.call_count == 1
+ self.linux_source_mock.run_kernel.assert_called_once_with(timeout=timeout)
+ self.print_mock.assert_any_call(StrContains('Testing complete.'))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tools/testing/kunit/test_data/test_is_test_passed-all_passed.log b/tools/testing/kunit/test_data/test_is_test_passed-all_passed.log
new file mode 100644
index 0000000000000..62ebc0288355c
--- /dev/null
+++ b/tools/testing/kunit/test_data/test_is_test_passed-all_passed.log
@@ -0,0 +1,32 @@
+TAP version 14
+ # Subtest: sysctl_test
+ 1..8
+ # sysctl_test_dointvec_null_tbl_data: sysctl_test_dointvec_null_tbl_data passed
+ ok 1 - sysctl_test_dointvec_null_tbl_data
+ # sysctl_test_dointvec_table_maxlen_unset: sysctl_test_dointvec_table_maxlen_unset passed
+ ok 2 - sysctl_test_dointvec_table_maxlen_unset
+ # sysctl_test_dointvec_table_len_is_zero: sysctl_test_dointvec_table_len_is_zero passed
+ ok 3 - sysctl_test_dointvec_table_len_is_zero
+ # sysctl_test_dointvec_table_read_but_position_set: sysctl_test_dointvec_table_read_but_position_set passed
+ ok 4 - sysctl_test_dointvec_table_read_but_position_set
+ # sysctl_test_dointvec_happy_single_positive: sysctl_test_dointvec_happy_single_positive passed
+ ok 5 - sysctl_test_dointvec_happy_single_positive
+ # sysctl_test_dointvec_happy_single_negative: sysctl_test_dointvec_happy_single_negative passed
+ ok 6 - sysctl_test_dointvec_happy_single_negative
+ # sysctl_test_dointvec_single_less_int_min: sysctl_test_dointvec_single_less_int_min passed
+ ok 7 - sysctl_test_dointvec_single_less_int_min
+ # sysctl_test_dointvec_single_greater_int_max: sysctl_test_dointvec_single_greater_int_max passed
+ ok 8 - sysctl_test_dointvec_single_greater_int_max
+kunit sysctl_test: all tests passed
+ok 1 - sysctl_test
+ # Subtest: example
+ 1..2
+init_suite
+ # example_simple_test: initializing
+ # example_simple_test: example_simple_test passed
+ ok 1 - example_simple_test
+ # example_mock_test: initializing
+ # example_mock_test: example_mock_test passed
+ ok 2 - example_mock_test
+kunit example: all tests passed
+ok 2 - example
diff --git a/tools/testing/kunit/test_data/test_is_test_passed-crash.log b/tools/testing/kunit/test_data/test_is_test_passed-crash.log
new file mode 100644
index 0000000000000..0b249870c8be4
--- /dev/null
+++ b/tools/testing/kunit/test_data/test_is_test_passed-crash.log
@@ -0,0 +1,69 @@
+printk: console [tty0] enabled
+printk: console [mc-1] enabled
+TAP version 14
+ # Subtest: sysctl_test
+ 1..8
+ # sysctl_test_dointvec_null_tbl_data: sysctl_test_dointvec_null_tbl_data passed
+ ok 1 - sysctl_test_dointvec_null_tbl_data
+ # sysctl_test_dointvec_table_maxlen_unset: sysctl_test_dointvec_table_maxlen_unset passed
+ ok 2 - sysctl_test_dointvec_table_maxlen_unset
+ # sysctl_test_dointvec_table_len_is_zero: sysctl_test_dointvec_table_len_is_zero passed
+ ok 3 - sysctl_test_dointvec_table_len_is_zero
+ # sysctl_test_dointvec_table_read_but_position_set: sysctl_test_dointvec_table_read_but_position_set passed
+ ok 4 - sysctl_test_dointvec_table_read_but_position_set
+ # sysctl_test_dointvec_happy_single_positive: sysctl_test_dointvec_happy_single_positive passed
+ ok 5 - sysctl_test_dointvec_happy_single_positive
+ # sysctl_test_dointvec_happy_single_negative: sysctl_test_dointvec_happy_single_negative passed
+ ok 6 - sysctl_test_dointvec_happy_single_negative
+ # sysctl_test_dointvec_single_less_int_min: sysctl_test_dointvec_single_less_int_min passed
+ ok 7 - sysctl_test_dointvec_single_less_int_min
+ # sysctl_test_dointvec_single_greater_int_max: sysctl_test_dointvec_single_greater_int_max passed
+ ok 8 - sysctl_test_dointvec_single_greater_int_max
+kunit sysctl_test: all tests passed
+ok 1 - sysctl_test
+ # Subtest: example
+ 1..2
+init_suite
+ # example_simple_test: initializing
+Stack:
+ 6016f7db 6f81bd30 6f81bdd0 60021450
+ 6024b0e8 60021440 60018bbe 16f81bdc0
+ 00000001 6f81bd30 6f81bd20 6f81bdd0
+Call Trace:
+ [<6016f7db>] ? kunit_try_run_case+0xab/0xf0
+ [<60021450>] ? set_signals+0x0/0x60
+ [<60021440>] ? get_signals+0x0/0x10
+ [<60018bbe>] ? kunit_um_run_try_catch+0x5e/0xc0
+ [<60021450>] ? set_signals+0x0/0x60
+ [<60021440>] ? get_signals+0x0/0x10
+ [<60018bb3>] ? kunit_um_run_try_catch+0x53/0xc0
+ [<6016f321>] ? kunit_run_case_catch_errors+0x121/0x1a0
+ [<60018b60>] ? kunit_um_run_try_catch+0x0/0xc0
+ [<600189e0>] ? kunit_um_throw+0x0/0x180
+ [<6016f730>] ? kunit_try_run_case+0x0/0xf0
+ [<6016f600>] ? kunit_catch_run_case+0x0/0x130
+ [<6016edd0>] ? kunit_vprintk+0x0/0x30
+ [<6016ece0>] ? kunit_fail+0x0/0x40
+ [<6016eca0>] ? kunit_abort+0x0/0x40
+ [<6016ed20>] ? kunit_printk_emit+0x0/0xb0
+ [<6016f200>] ? kunit_run_case_catch_errors+0x0/0x1a0
+ [<6016f46e>] ? kunit_run_tests+0xce/0x260
+ [<6005b390>] ? unregister_console+0x0/0x190
+ [<60175b70>] ? suite_kunit_initexample_test_suite+0x0/0x20
+ [<60001cbb>] ? do_one_initcall+0x0/0x197
+ [<60001d47>] ? do_one_initcall+0x8c/0x197
+ [<6005cd20>] ? irq_to_desc+0x0/0x30
+ [<60002005>] ? kernel_init_freeable+0x1b3/0x272
+ [<6005c5ec>] ? printk+0x0/0x9b
+ [<601c0086>] ? kernel_init+0x26/0x160
+ [<60014442>] ? new_thread_handler+0x82/0xc0
+
+ # example_simple_test: kunit test case crashed!
+ # example_simple_test: example_simple_test failed
+ not ok 1 - example_simple_test
+ # example_mock_test: initializing
+ # example_mock_test: example_mock_test passed
+ ok 2 - example_mock_test
+kunit example: one or more tests failed
+not ok 2 - example
+List of all partitions:
diff --git a/tools/testing/kunit/test_data/test_is_test_passed-failure.log b/tools/testing/kunit/test_data/test_is_test_passed-failure.log
new file mode 100644
index 0000000000000..2ed870b6de72f
--- /dev/null
+++ b/tools/testing/kunit/test_data/test_is_test_passed-failure.log
@@ -0,0 +1,36 @@
+TAP version 14
+ # Subtest: sysctl_test
+ 1..8
+ # sysctl_test_dointvec_null_tbl_data: sysctl_test_dointvec_null_tbl_data passed
+ ok 1 - sysctl_test_dointvec_null_tbl_data
+ # sysctl_test_dointvec_table_maxlen_unset: sysctl_test_dointvec_table_maxlen_unset passed
+ ok 2 - sysctl_test_dointvec_table_maxlen_unset
+ # sysctl_test_dointvec_table_len_is_zero: sysctl_test_dointvec_table_len_is_zero passed
+ ok 3 - sysctl_test_dointvec_table_len_is_zero
+ # sysctl_test_dointvec_table_read_but_position_set: sysctl_test_dointvec_table_read_but_position_set passed
+ ok 4 - sysctl_test_dointvec_table_read_but_position_set
+ # sysctl_test_dointvec_happy_single_positive: sysctl_test_dointvec_happy_single_positive passed
+ ok 5 - sysctl_test_dointvec_happy_single_positive
+ # sysctl_test_dointvec_happy_single_negative: sysctl_test_dointvec_happy_single_negative passed
+ ok 6 - sysctl_test_dointvec_happy_single_negative
+ # sysctl_test_dointvec_single_less_int_min: sysctl_test_dointvec_single_less_int_min passed
+ ok 7 - sysctl_test_dointvec_single_less_int_min
+ # sysctl_test_dointvec_single_greater_int_max: sysctl_test_dointvec_single_greater_int_max passed
+ ok 8 - sysctl_test_dointvec_single_greater_int_max
+kunit sysctl_test: all tests passed
+ok 1 - sysctl_test
+ # Subtest: example
+ 1..2
+init_suite
+ # example_simple_test: initializing
+ # example_simple_test: EXPECTATION FAILED at kunit/example-test.c:30
+ Expected 1 + 1 == 3, but
+ 1 + 1 == 2
+ 3 == 3
+ # example_simple_test: example_simple_test failed
+ not ok 1 - example_simple_test
+ # example_mock_test: initializing
+ # example_mock_test: example_mock_test passed
+ ok 2 - example_mock_test
+kunit example: one or more tests failed
+not ok 2 - example
diff --git a/tools/testing/kunit/test_data/test_is_test_passed-no_tests_run.log b/tools/testing/kunit/test_data/test_is_test_passed-no_tests_run.log
new file mode 100644
index 0000000000000..ba69f5c94b75f
--- /dev/null
+++ b/tools/testing/kunit/test_data/test_is_test_passed-no_tests_run.log
@@ -0,0 +1,75 @@
+Core dump limits :
+ soft - 0
+ hard - NONE
+Checking environment variables for a tempdir...none found
+Checking if /dev/shm is on tmpfs...OK
+Checking PROT_EXEC mmap in /dev/shm...OK
+Adding 24743936 bytes to physical memory to account for exec-shield gap
+Linux version 4.12.0-rc3-00010-g7319eb35f493-dirty (brendanhiggins-woRtfX0xupevss2yl3NHrPyj43VRqXoZVpNB7YpNyf8@public.gmane.org) (gcc version 7.3.0 (Debian 7.3.0-5) ) #29 Thu Mar 15 14:57:19 PDT 2018
+Built 1 zonelists in Zone order, mobility grouping on. Total pages: 14038
+Kernel command line: root=98:0
+PID hash table entries: 256 (order: -1, 2048 bytes)
+Dentry cache hash table entries: 8192 (order: 4, 65536 bytes)
+Inode-cache hash table entries: 4096 (order: 3, 32768 bytes)
+Memory: 27868K/56932K available (1681K kernel code, 480K rwdata, 400K rodata, 89K init, 205K bss, 29064K reserved, 0K cma-reserved)
+SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
+NR_IRQS:15
+clocksource: timer: mask: 0xffffffffffffffff max_cycles: 0x1cd42e205, max_idle_ns: 881590404426 ns
+Calibrating delay loop... 7384.26 BogoMIPS (lpj=36921344)
+pid_max: default: 32768 minimum: 301
+Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
+Mountpoint-cache hash table entries: 512 (order: 0, 4096 bytes)
+Checking that host ptys support output SIGIO...Yes
+Checking that host ptys support SIGIO on close...No, enabling workaround
+Using 2.6 host AIO
+clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
+futex hash table entries: 256 (order: 0, 6144 bytes)
+clocksource: Switched to clocksource timer
+console [stderr0] disabled
+mconsole (version 2) initialized on /usr/local/google/home/brendanhiggins/.uml/6Ijecl/mconsole
+Checking host MADV_REMOVE support...OK
+workingset: timestamp_bits=62 max_order=13 bucket_order=0
+Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
+io scheduler noop registered
+io scheduler deadline registered
+io scheduler cfq registered (default)
+io scheduler mq-deadline registered
+io scheduler kyber registered
+Initialized stdio console driver
+Using a channel type which is configured out of UML
+setup_one_line failed for device 1 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 2 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 3 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 4 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 5 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 6 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 7 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 8 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 9 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 10 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 11 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 12 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 13 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 14 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 15 : Configuration failed
+Console initialized on /dev/tty0
+console [tty0] enabled
+console [mc-1] enabled
+List of all partitions:
+No filesystem could mount root, tried:
+
+Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(98,0)
diff --git a/tools/testing/kunit/test_data/test_output_isolated_correctly.log b/tools/testing/kunit/test_data/test_output_isolated_correctly.log
new file mode 100644
index 0000000000000..94a6b3aeaa922
--- /dev/null
+++ b/tools/testing/kunit/test_data/test_output_isolated_correctly.log
@@ -0,0 +1,106 @@
+Linux version 5.1.0-rc7-00061-g04652f1cb4aa0 (brendanhiggins-woRtfX0xupevss2yl3NHrPyj43VRqXoZVpNB7YpNyf8@public.gmane.org) (gcc version 7.3.0 (Debian 7.3.0-18)) #163 Wed May 8 16:18:20 PDT 2019
+Built 1 zonelists, mobility grouping on. Total pages: 69906
+Kernel command line: mem=256M root=98:0
+Dentry cache hash table entries: 65536 (order: 7, 524288 bytes)
+Inode-cache hash table entries: 32768 (order: 6, 262144 bytes)
+Memory: 254468K/283500K available (1734K kernel code, 489K rwdata, 396K rodata, 85K init, 216K bss, 29032K reserved, 0K cma-reserved)
+SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
+NR_IRQS: 15
+clocksource: timer: mask: 0xffffffffffffffff max_cycles: 0x1cd42e205, max_idle_ns: 881590404426 ns
+------------[ cut here ]------------
+WARNING: CPU: 0 PID: 0 at kernel/time/clockevents.c:458 clockevents_register_device+0x143/0x160
+posix-timer cpumask == cpu_all_mask, using cpu_possible_mask instead
+CPU: 0 PID: 0 Comm: swapper Not tainted 5.1.0-rc7-00061-g04652f1cb4aa0 #163
+Stack:
+ 6005cc00 60233e18 60233e60 60233e18
+ 60233e60 00000009 00000000 6002a1b4
+ 1ca00000000 60071c23 60233e78 100000000000062
+Call Trace:
+ [<600214c5>] ? os_is_signal_stack+0x15/0x30
+ [<6005c5ec>] ? printk+0x0/0x9b
+ [<6001597e>] ? show_stack+0xbe/0x1c0
+ [<6005cc00>] ? __printk_safe_exit+0x0/0x40
+ [<6002a1b4>] ? __warn+0x144/0x170
+ [<60071c23>] ? clockevents_register_device+0x143/0x160
+ [<60021440>] ? get_signals+0x0/0x10
+ [<6005c5ec>] ? printk+0x0/0x9b
+ [<6002a27b>] ? warn_slowpath_fmt+0x9b/0xb0
+ [<6005c5ec>] ? printk+0x0/0x9b
+ [<6002a1e0>] ? warn_slowpath_fmt+0x0/0xb0
+ [<6005c5ec>] ? printk+0x0/0x9b
+ [<60021440>] ? get_signals+0x0/0x10
+ [<600213f0>] ? block_signals+0x0/0x20
+ [<60071c23>] ? clockevents_register_device+0x143/0x160
+ [<60021440>] ? get_signals+0x0/0x10
+ [<600213f0>] ? block_signals+0x0/0x20
+ [<6005c5ec>] ? printk+0x0/0x9b
+ [<60001bc8>] ? start_kernel+0x477/0x56a
+ [<600036f1>] ? start_kernel_proc+0x46/0x4d
+ [<60014442>] ? new_thread_handler+0x82/0xc0
+
+random: get_random_bytes called from print_oops_end_marker+0x4c/0x60 with crng_init=0
+---[ end trace c83434852b3702d3 ]---
+Calibrating delay loop... 6958.28 BogoMIPS (lpj=34791424)
+pid_max: default: 32768 minimum: 301
+Mount-cache hash table entries: 1024 (order: 1, 8192 bytes)
+Mountpoint-cache hash table entries: 1024 (order: 1, 8192 bytes)
+*** VALIDATE proc ***
+Checking that host ptys support output SIGIO...Yes
+Checking that host ptys support SIGIO on close...No, enabling workaround
+clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
+futex hash table entries: 256 (order: 0, 6144 bytes)
+clocksource: Switched to clocksource timer
+printk: console [stderr0] disabled
+mconsole (version 2) initialized on /usr/local/google/home/brendanhiggins/.uml/VZ2qMm/mconsole
+Checking host MADV_REMOVE support...OK
+workingset: timestamp_bits=62 max_order=16 bucket_order=0
+Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
+io scheduler mq-deadline registered
+io scheduler kyber registered
+Initialized stdio console driver
+Using a channel type which is configured out of UML
+setup_one_line failed for device 1 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 2 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 3 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 4 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 5 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 6 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 7 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 8 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 9 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 10 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 11 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 12 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 13 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 14 : Configuration failed
+Using a channel type which is configured out of UML
+setup_one_line failed for device 15 : Configuration failed
+Console initialized on /dev/tty0
+printk: console [tty0] enabled
+printk: console [mc-1] enabled
+TAP version 14
+ # Subtest: example
+ 1..2
+init_suite
+ # example_simple_test: initializing
+ # example_simple_test: example_simple_test passed
+ ok 1 - example_simple_test
+ # example_mock_test: initializing
+ # example_mock_test: example_mock_test passed
+ ok 2 - example_mock_test
+kunit example: all tests passed
+ok 1 - example
+List of all partitions:
diff --git a/tools/testing/kunit/test_data/test_read_from_file.kconfig b/tools/testing/kunit/test_data/test_read_from_file.kconfig
new file mode 100644
index 0000000000000..d2a4928ac773b
--- /dev/null
+++ b/tools/testing/kunit/test_data/test_read_from_file.kconfig
@@ -0,0 +1,17 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# User Mode Linux/x86 4.12.0-rc3 Kernel Configuration
+#
+CONFIG_UML=y
+CONFIG_MMU=y
+
+#
+# UML-specific options
+#
+
+#
+# Host processor type and features
+#
+# CONFIG_MK8 is not set
+CONFIG_TEST=y
+CONFIG_EXAMPLE_TEST=y
--
2.22.0.410.gd8fdbe21b5-goog
^ permalink raw reply related
* [PATCH v9 14/18] kunit: defconfig: add defconfigs for building KUnit tests
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
jpoimboe-H+wXaHxf7aLQT0dZR+AlfA, keescook-hpIqsD4AKlfQT0dZR+AlfA,
kieran.bingham-ryLnwIuWjnjg/C1BVhZhaw,
mcgrof-DgEjT+Ai2ygdnm+yROfE0A, peterz-wEGCiKHe2LqWVfeAwA7xHQ,
robh-DgEjT+Ai2ygdnm+yROfE0A, sboyd-DgEjT+Ai2ygdnm+yROfE0A,
shuah-DgEjT+Ai2ygdnm+yROfE0A, tytso-3s7WtUTddSA,
yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A
Cc: pmladek-IBi9RG/b67k, linux-doc-u79uwXL29TY76Z2rM5mHXA,
amir73il-Re5JQEeQqe8AvxtiuMwx3w, Brendan Higgins,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
Alexander.Levin-0li6OtcxBFHby3iVrkZq2A,
linux-kselftest-u79uwXL29TY76Z2rM5mHXA,
linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw,
khilman-rdvid1DuHRBWk0Htik3J/w, knut.omang-QHcLZuEGTsvQT0dZR+AlfA,
wfg-VuQAYsv1563Yd54FQh9/CA, joel-U3u1mxZcP9KHXe+LvDLADg,
rientjes-hpIqsD4AKlfQT0dZR+AlfA, jdike-OPE4K8JWMJJBDgjK7y7TUQ,
dan.carpenter-QHcLZuEGTsvQT0dZR+AlfA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kbuild-u79uwXL29TY76Z2rM5mHXA, Tim.Bird-7U/KSKJipcs,
linux-um-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
rostedt-nx8X9YLhiw1AfugRpC6u6w, julia.lawall-L2FTfq7BK8M,
kunit-dev-/JYPxA39Uh5TLH3MbocFFw, richard-/L3Ra7n9ekc,
rdunlap-wEGCiKHe2LqWVfeAwA7xHQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, daniel-/w4YWyX8dFk,
mpe-Gsx/Oe8HsFggBc27wqDAHg, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20190712081744.87097-1-brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Add defconfig for UML and a fragment that can be used to configure other
architectures for building KUnit tests. Add option to kunit_tool to use
a defconfig to create the kunitconfig.
Signed-off-by: Brendan Higgins <brendanhiggins-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Reviewed-by: Greg Kroah-Hartman <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>
Reviewed-by: Logan Gunthorpe <logang-OTvnGxWRz7hWk0Htik3J/w@public.gmane.org>
---
arch/um/configs/kunit_defconfig | 8 ++++++++
tools/testing/kunit/configs/all_tests.config | 8 ++++++++
tools/testing/kunit/kunit.py | 18 ++++++++++++++++--
tools/testing/kunit/kunit_kernel.py | 3 ++-
4 files changed, 34 insertions(+), 3 deletions(-)
create mode 100644 arch/um/configs/kunit_defconfig
create mode 100644 tools/testing/kunit/configs/all_tests.config
diff --git a/arch/um/configs/kunit_defconfig b/arch/um/configs/kunit_defconfig
new file mode 100644
index 0000000000000..bfe49689038f1
--- /dev/null
+++ b/arch/um/configs/kunit_defconfig
@@ -0,0 +1,8 @@
+CONFIG_OF=y
+CONFIG_OF_UNITTEST=y
+CONFIG_OF_OVERLAY=y
+CONFIG_I2C=y
+CONFIG_I2C_MUX=y
+CONFIG_KUNIT=y
+CONFIG_KUNIT_TEST=y
+CONFIG_KUNIT_EXAMPLE_TEST=y
diff --git a/tools/testing/kunit/configs/all_tests.config b/tools/testing/kunit/configs/all_tests.config
new file mode 100644
index 0000000000000..bfe49689038f1
--- /dev/null
+++ b/tools/testing/kunit/configs/all_tests.config
@@ -0,0 +1,8 @@
+CONFIG_OF=y
+CONFIG_OF_UNITTEST=y
+CONFIG_OF_OVERLAY=y
+CONFIG_I2C=y
+CONFIG_I2C_MUX=y
+CONFIG_KUNIT=y
+CONFIG_KUNIT_TEST=y
+CONFIG_KUNIT_EXAMPLE_TEST=y
diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
index da11bd62a4b82..3e51dc4febfdc 100755
--- a/tools/testing/kunit/kunit.py
+++ b/tools/testing/kunit/kunit.py
@@ -11,6 +11,7 @@ import argparse
import sys
import os
import time
+import shutil
from collections import namedtuple
from enum import Enum, auto
@@ -21,7 +22,7 @@ import kunit_parser
KunitResult = namedtuple('KunitResult', ['status','result'])
-KunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs', 'build_dir'])
+KunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs', 'build_dir', 'defconfig'])
class KunitStatus(Enum):
SUCCESS = auto()
@@ -29,8 +30,16 @@ class KunitStatus(Enum):
BUILD_FAILURE = auto()
TEST_FAILURE = auto()
+def create_default_kunitconfig():
+ if not os.path.exists(kunit_kernel.KUNITCONFIG_PATH):
+ shutil.copyfile('arch/um/configs/kunit_defconfig',
+ kunit_kernel.KUNITCONFIG_PATH)
+
def run_tests(linux: kunit_kernel.LinuxSourceTree,
request: KunitRequest) -> KunitResult:
+ if request.defconfig:
+ create_default_kunitconfig()
+
config_start = time.time()
success = linux.build_reconfig(request.build_dir)
config_end = time.time()
@@ -99,13 +108,18 @@ def main(argv, linux):
'directory.',
type=str, default=None, metavar='build_dir')
+ run_parser.add_argument('--defconfig',
+ help='Uses a default kunitconfig.',
+ action='store_true')
+
cli_args = parser.parse_args(argv)
if cli_args.subcommand == 'run':
request = KunitRequest(cli_args.raw_output,
cli_args.timeout,
cli_args.jobs,
- cli_args.build_dir)
+ cli_args.build_dir,
+ cli_args.defconfig)
result = run_tests(linux, request)
if result.status != KunitStatus.SUCCESS:
sys.exit(1)
diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py
index 07c0abf2f47df..bf38768353313 100644
--- a/tools/testing/kunit/kunit_kernel.py
+++ b/tools/testing/kunit/kunit_kernel.py
@@ -14,6 +14,7 @@ import os
import kunit_config
KCONFIG_PATH = '.config'
+KUNITCONFIG_PATH = 'kunitconfig'
class ConfigError(Exception):
"""Represents an error trying to configure the Linux kernel."""
@@ -81,7 +82,7 @@ class LinuxSourceTree(object):
def __init__(self):
self._kconfig = kunit_config.Kconfig()
- self._kconfig.read_from_file('kunitconfig')
+ self._kconfig.read_from_file(KUNITCONFIG_PATH)
self._ops = LinuxSourceTreeOperations()
def clean(self):
--
2.22.0.410.gd8fdbe21b5-goog
^ permalink raw reply related
* [PATCH v9 15/18] Documentation: kunit: add documentation for KUnit
From: Brendan Higgins @ 2019-07-12 8:17 UTC (permalink / raw)
To: frowand.list, gregkh, jpoimboe, keescook, kieran.bingham, mcgrof,
peterz, robh, sboyd, shuah, tytso, yamada.masahiro
Cc: devicetree, dri-devel, kunit-dev, linux-doc, linux-fsdevel,
linux-kbuild, linux-kernel, linux-kselftest, linux-nvdimm,
linux-um, Alexander.Levin, Tim.Bird, amir73il, dan.carpenter,
daniel, jdike, joel, julia.lawall, khilman, knut.omang, logang,
mpe, pmladek, rdunlap, richard, rientjes, rostedt, wfg,
Brendan Higgins, Felix Guo, Jonathan Corbet
In-Reply-To: <20190712081744.87097-1-brendanhiggins@google.com>
Add documentation for KUnit, the Linux kernel unit testing framework.
- Add intro and usage guide for KUnit
- Add API reference
Signed-off-by: Felix Guo <felixguoxiuping@gmail.com>
Signed-off-by: Brendan Higgins <brendanhiggins@google.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
---
Documentation/dev-tools/index.rst | 1 +
Documentation/dev-tools/kunit/api/index.rst | 16 +
Documentation/dev-tools/kunit/api/test.rst | 14 +
Documentation/dev-tools/kunit/faq.rst | 62 +++
Documentation/dev-tools/kunit/index.rst | 79 +++
Documentation/dev-tools/kunit/start.rst | 180 ++++++
Documentation/dev-tools/kunit/usage.rst | 575 ++++++++++++++++++++
7 files changed, 927 insertions(+)
create mode 100644 Documentation/dev-tools/kunit/api/index.rst
create mode 100644 Documentation/dev-tools/kunit/api/test.rst
create mode 100644 Documentation/dev-tools/kunit/faq.rst
create mode 100644 Documentation/dev-tools/kunit/index.rst
create mode 100644 Documentation/dev-tools/kunit/start.rst
create mode 100644 Documentation/dev-tools/kunit/usage.rst
diff --git a/Documentation/dev-tools/index.rst b/Documentation/dev-tools/index.rst
index b0522a4dd1073..09dee10d25928 100644
--- a/Documentation/dev-tools/index.rst
+++ b/Documentation/dev-tools/index.rst
@@ -24,6 +24,7 @@ whole; patches welcome!
gdb-kernel-debugging
kgdb
kselftest
+ kunit/index
.. only:: subproject and html
diff --git a/Documentation/dev-tools/kunit/api/index.rst b/Documentation/dev-tools/kunit/api/index.rst
new file mode 100644
index 0000000000000..9b9bffe5d41a0
--- /dev/null
+++ b/Documentation/dev-tools/kunit/api/index.rst
@@ -0,0 +1,16 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=============
+API Reference
+=============
+.. toctree::
+
+ test
+
+This section documents the KUnit kernel testing API. It is divided into the
+following sections:
+
+================================= ==============================================
+:doc:`test` documents all of the standard testing API
+ excluding mocking or mocking related features.
+================================= ==============================================
diff --git a/Documentation/dev-tools/kunit/api/test.rst b/Documentation/dev-tools/kunit/api/test.rst
new file mode 100644
index 0000000000000..d0ce19b1e1185
--- /dev/null
+++ b/Documentation/dev-tools/kunit/api/test.rst
@@ -0,0 +1,14 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+========
+Test API
+========
+
+This file documents all of the standard testing API excluding mocking or mocking
+related features.
+
+.. kernel-doc:: include/kunit/test.h
+ :internal:
+
+.. kernel-doc:: include/kunit/kunit-stream.h
+ :internal:
diff --git a/Documentation/dev-tools/kunit/faq.rst b/Documentation/dev-tools/kunit/faq.rst
new file mode 100644
index 0000000000000..bf2095112d899
--- /dev/null
+++ b/Documentation/dev-tools/kunit/faq.rst
@@ -0,0 +1,62 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==========================
+Frequently Asked Questions
+==========================
+
+How is this different from Autotest, kselftest, etc?
+====================================================
+KUnit is a unit testing framework. Autotest, kselftest (and some others) are
+not.
+
+A `unit test <https://martinfowler.com/bliki/UnitTest.html>`_ is supposed to
+test a single unit of code in isolation, hence the name. A unit test should be
+the finest granularity of testing and as such should allow all possible code
+paths to be tested in the code under test; this is only possible if the code
+under test is very small and does not have any external dependencies outside of
+the test's control like hardware.
+
+There are no testing frameworks currently available for the kernel that do not
+require installing the kernel on a test machine or in a VM and all require
+tests to be written in userspace and run on the kernel under test; this is true
+for Autotest, kselftest, and some others, disqualifying any of them from being
+considered unit testing frameworks.
+
+Does KUnit support running on architectures other than UML?
+===========================================================
+
+Yes, well, mostly.
+
+For the most part, the KUnit core framework (what you use to write the tests)
+can compile to any architecture; it compiles like just another part of the
+kernel and runs when the kernel boots. However, there is some infrastructure,
+like the KUnit Wrapper (``tools/testing/kunit/kunit.py``) that does not support
+other architectures.
+
+In short, this means that, yes, you can run KUnit on other architectures, but
+it might require more work than using KUnit on UML.
+
+For more information, see :ref:`kunit-on-non-uml`.
+
+What is the difference between a unit test and these other kinds of tests?
+==========================================================================
+Most existing tests for the Linux kernel would be categorized as an integration
+test, or an end-to-end test.
+
+- A unit test is supposed to test a single unit of code in isolation, hence the
+ name. A unit test should be the finest granularity of testing and as such
+ should allow all possible code paths to be tested in the code under test; this
+ is only possible if the code under test is very small and does not have any
+ external dependencies outside of the test's control like hardware.
+- An integration test tests the interaction between a minimal set of components,
+ usually just two or three. For example, someone might write an integration
+ test to test the interaction between a driver and a piece of hardware, or to
+ test the interaction between the userspace libraries the kernel provides and
+ the kernel itself; however, one of these tests would probably not test the
+ entire kernel along with hardware interactions and interactions with the
+ userspace.
+- An end-to-end test usually tests the entire system from the perspective of the
+ code under test. For example, someone might write an end-to-end test for the
+ kernel by installing a production configuration of the kernel on production
+ hardware with a production userspace and then trying to exercise some behavior
+ that depends on interactions between the hardware, the kernel, and userspace.
diff --git a/Documentation/dev-tools/kunit/index.rst b/Documentation/dev-tools/kunit/index.rst
new file mode 100644
index 0000000000000..a317ab45bfe2d
--- /dev/null
+++ b/Documentation/dev-tools/kunit/index.rst
@@ -0,0 +1,79 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=========================================
+KUnit - Unit Testing for the Linux Kernel
+=========================================
+
+.. toctree::
+ :maxdepth: 2
+
+ start
+ usage
+ api/index
+ faq
+
+What is KUnit?
+==============
+
+KUnit is a lightweight unit testing and mocking framework for the Linux kernel.
+These tests are able to be run locally on a developer's workstation without a VM
+or special hardware.
+
+KUnit is heavily inspired by JUnit, Python's unittest.mock, and
+Googletest/Googlemock for C++. KUnit provides facilities for defining unit test
+cases, grouping related test cases into test suites, providing common
+infrastructure for running tests, and much more.
+
+Get started now: :doc:`start`
+
+Why KUnit?
+==========
+
+A unit test is supposed to test a single unit of code in isolation, hence the
+name. A unit test should be the finest granularity of testing and as such should
+allow all possible code paths to be tested in the code under test; this is only
+possible if the code under test is very small and does not have any external
+dependencies outside of the test's control like hardware.
+
+Outside of KUnit, there are no testing frameworks currently
+available for the kernel that do not require installing the kernel on a test
+machine or in a VM and all require tests to be written in userspace running on
+the kernel; this is true for Autotest, and kselftest, disqualifying
+any of them from being considered unit testing frameworks.
+
+KUnit addresses the problem of being able to run tests without needing a virtual
+machine or actual hardware with User Mode Linux. User Mode Linux is a Linux
+architecture, like ARM or x86; however, unlike other architectures it compiles
+to a standalone program that can be run like any other program directly inside
+of a host operating system; to be clear, it does not require any virtualization
+support; it is just a regular program.
+
+KUnit is fast. Excluding build time, from invocation to completion KUnit can run
+several dozen tests in only 10 to 20 seconds; this might not sound like a big
+deal to some people, but having such fast and easy to run tests fundamentally
+changes the way you go about testing and even writing code in the first place.
+Linus himself said in his `git talk at Google
+<https://gist.github.com/lorn/1272686/revisions#diff-53c65572127855f1b003db4064a94573R874>`_:
+
+ "... a lot of people seem to think that performance is about doing the
+ same thing, just doing it faster, and that is not true. That is not what
+ performance is all about. If you can do something really fast, really
+ well, people will start using it differently."
+
+In this context Linus was talking about branching and merging,
+but this point also applies to testing. If your tests are slow, unreliable, are
+difficult to write, and require a special setup or special hardware to run,
+then you wait a lot longer to write tests, and you wait a lot longer to run
+tests; this means that tests are likely to break, unlikely to test a lot of
+things, and are unlikely to be rerun once they pass. If your tests are really
+fast, you run them all the time, every time you make a change, and every time
+someone sends you some code. Why trust that someone ran all their tests
+correctly on every change when you can just run them yourself in less time than
+it takes to read his / her test log?
+
+How do I use it?
+================
+
+* :doc:`start` - for new users of KUnit
+* :doc:`usage` - for a more detailed explanation of KUnit features
+* :doc:`api/index` - for the list of KUnit APIs used for testing
diff --git a/Documentation/dev-tools/kunit/start.rst b/Documentation/dev-tools/kunit/start.rst
new file mode 100644
index 0000000000000..6dc229e46bb34
--- /dev/null
+++ b/Documentation/dev-tools/kunit/start.rst
@@ -0,0 +1,180 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===============
+Getting Started
+===============
+
+Installing dependencies
+=======================
+KUnit has the same dependencies as the Linux kernel. As long as you can build
+the kernel, you can run KUnit.
+
+KUnit Wrapper
+=============
+Included with KUnit is a simple Python wrapper that helps format the output to
+easily use and read KUnit output. It handles building and running the kernel, as
+well as formatting the output.
+
+The wrapper can be run with:
+
+.. code-block:: bash
+
+ ./tools/testing/kunit/kunit.py run
+
+Creating a kunitconfig
+======================
+The Python script is a thin wrapper around Kbuild as such, it needs to be
+configured with a ``kunitconfig`` file. This file essentially contains the
+regular Kernel config, with the specific test targets as well.
+
+.. code-block:: bash
+
+ git clone -b master https://kunit.googlesource.com/kunitconfig $PATH_TO_KUNITCONFIG_REPO
+ cd $PATH_TO_LINUX_REPO
+ ln -s $PATH_TO_KUNIT_CONFIG_REPO/kunitconfig kunitconfig
+
+You may want to add kunitconfig to your local gitignore.
+
+Verifying KUnit Works
+---------------------
+
+To make sure that everything is set up correctly, simply invoke the Python
+wrapper from your kernel repo:
+
+.. code-block:: bash
+
+ ./tools/testing/kunit/kunit.py
+
+.. note::
+ You may want to run ``make mrproper`` first.
+
+If everything worked correctly, you should see the following:
+
+.. code-block:: bash
+
+ Generating .config ...
+ Building KUnit Kernel ...
+ Starting KUnit Kernel ...
+
+followed by a list of tests that are run. All of them should be passing.
+
+.. note::
+ Because it is building a lot of sources for the first time, the ``Building
+ kunit kernel`` step may take a while.
+
+Writing your first test
+=======================
+
+In your kernel repo let's add some code that we can test. Create a file
+``drivers/misc/example.h`` with the contents:
+
+.. code-block:: c
+
+ int misc_example_add(int left, int right);
+
+create a file ``drivers/misc/example.c``:
+
+.. code-block:: c
+
+ #include <linux/errno.h>
+
+ #include "example.h"
+
+ int misc_example_add(int left, int right)
+ {
+ return left + right;
+ }
+
+Now add the following lines to ``drivers/misc/Kconfig``:
+
+.. code-block:: kconfig
+
+ config MISC_EXAMPLE
+ bool "My example"
+
+and the following lines to ``drivers/misc/Makefile``:
+
+.. code-block:: make
+
+ obj-$(CONFIG_MISC_EXAMPLE) += example.o
+
+Now we are ready to write the test. The test will be in
+``drivers/misc/example-test.c``:
+
+.. code-block:: c
+
+ #include <kunit/test.h>
+ #include "example.h"
+
+ /* Define the test cases. */
+
+ static void misc_example_add_test_basic(struct kunit *test)
+ {
+ KUNIT_EXPECT_EQ(test, 1, misc_example_add(1, 0));
+ KUNIT_EXPECT_EQ(test, 2, misc_example_add(1, 1));
+ KUNIT_EXPECT_EQ(test, 0, misc_example_add(-1, 1));
+ KUNIT_EXPECT_EQ(test, INT_MAX, misc_example_add(0, INT_MAX));
+ KUNIT_EXPECT_EQ(test, -1, misc_example_add(INT_MAX, INT_MIN));
+ }
+
+ static void misc_example_test_failure(struct kunit *test)
+ {
+ KUNIT_FAIL(test, "This test never passes.");
+ }
+
+ static struct kunit_case misc_example_test_cases[] = {
+ KUNIT_CASE(misc_example_add_test_basic),
+ KUNIT_CASE(misc_example_test_failure),
+ {}
+ };
+
+ static struct kunit_suite misc_example_test_suite = {
+ .name = "misc-example",
+ .test_cases = misc_example_test_cases,
+ };
+ kunit_test_suite(misc_example_test_suite);
+
+Now add the following to ``drivers/misc/Kconfig``:
+
+.. code-block:: kconfig
+
+ config MISC_EXAMPLE_TEST
+ bool "Test for my example"
+ depends on MISC_EXAMPLE && KUNIT
+
+and the following to ``drivers/misc/Makefile``:
+
+.. code-block:: make
+
+ obj-$(CONFIG_MISC_EXAMPLE_TEST) += example-test.o
+
+Now add it to your ``kunitconfig``:
+
+.. code-block:: none
+
+ CONFIG_MISC_EXAMPLE=y
+ CONFIG_MISC_EXAMPLE_TEST=y
+
+Now you can run the test:
+
+.. code-block:: bash
+
+ ./tools/testing/kunit/kunit.py
+
+You should see the following failure:
+
+.. code-block:: none
+
+ ...
+ [16:08:57] [PASSED] misc-example:misc_example_add_test_basic
+ [16:08:57] [FAILED] misc-example:misc_example_test_failure
+ [16:08:57] EXPECTATION FAILED at drivers/misc/example-test.c:17
+ [16:08:57] This test never passes.
+ ...
+
+Congrats! You just wrote your first KUnit test!
+
+Next Steps
+==========
+* Check out the :doc:`usage` page for a more
+ in-depth explanation of KUnit.
diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-tools/kunit/usage.rst
new file mode 100644
index 0000000000000..049886006dbce
--- /dev/null
+++ b/Documentation/dev-tools/kunit/usage.rst
@@ -0,0 +1,575 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===========
+Using KUnit
+===========
+
+The purpose of this document is to describe what KUnit is, how it works, how it
+is intended to be used, and all the concepts and terminology that are needed to
+understand it. This guide assumes a working knowledge of the Linux kernel and
+some basic knowledge of testing.
+
+For a high level introduction to KUnit, including setting up KUnit for your
+project, see :doc:`start`.
+
+Organization of this document
+=============================
+
+This document is organized into two main sections: Testing and Isolating
+Behavior. The first covers what a unit test is and how to use KUnit to write
+them. The second covers how to use KUnit to isolate code and make it possible
+to unit test code that was otherwise un-unit-testable.
+
+Testing
+=======
+
+What is KUnit?
+--------------
+
+"K" is short for "kernel" so "KUnit" is the "(Linux) Kernel Unit Testing
+Framework." KUnit is intended first and foremost for writing unit tests; it is
+general enough that it can be used to write integration tests; however, this is
+a secondary goal. KUnit has no ambition of being the only testing framework for
+the kernel; for example, it does not intend to be an end-to-end testing
+framework.
+
+What is Unit Testing?
+---------------------
+
+A `unit test <https://martinfowler.com/bliki/UnitTest.html>`_ is a test that
+tests code at the smallest possible scope, a *unit* of code. In the C
+programming language that's a function.
+
+Unit tests should be written for all the publicly exposed functions in a
+compilation unit; so that is all the functions that are exported in either a
+*class* (defined below) or all functions which are **not** static.
+
+Writing Tests
+-------------
+
+Test Cases
+~~~~~~~~~~
+
+The fundamental unit in KUnit is the test case. A test case is a function with
+the signature ``void (*)(struct kunit *test)``. It calls a function to be tested
+and then sets *expectations* for what should happen. For example:
+
+.. code-block:: c
+
+ void example_test_success(struct kunit *test)
+ {
+ }
+
+ void example_test_failure(struct kunit *test)
+ {
+ KUNIT_FAIL(test, "This test never passes.");
+ }
+
+In the above example ``example_test_success`` always passes because it does
+nothing; no expectations are set, so all expectations pass. On the other hand
+``example_test_failure`` always fails because it calls ``KUNIT_FAIL``, which is
+a special expectation that logs a message and causes the test case to fail.
+
+Expectations
+~~~~~~~~~~~~
+An *expectation* is a way to specify that you expect a piece of code to do
+something in a test. An expectation is called like a function. A test is made
+by setting expectations about the behavior of a piece of code under test; when
+one or more of the expectations fail, the test case fails and information about
+the failure is logged. For example:
+
+.. code-block:: c
+
+ void add_test_basic(struct kunit *test)
+ {
+ KUNIT_EXPECT_EQ(test, 1, add(1, 0));
+ KUNIT_EXPECT_EQ(test, 2, add(1, 1));
+ }
+
+In the above example ``add_test_basic`` makes a number of assertions about the
+behavior of a function called ``add``; the first parameter is always of type
+``struct kunit *``, which contains information about the current test context;
+the second parameter, in this case, is what the value is expected to be; the
+last value is what the value actually is. If ``add`` passes all of these
+expectations, the test case, ``add_test_basic`` will pass; if any one of these
+expectations fail, the test case will fail.
+
+It is important to understand that a test case *fails* when any expectation is
+violated; however, the test will continue running, potentially trying other
+expectations until the test case ends or is otherwise terminated. This is as
+opposed to *assertions* which are discussed later.
+
+To learn about more expectations supported by KUnit, see :doc:`api/test`.
+
+.. note::
+ A single test case should be pretty short, pretty easy to understand,
+ focused on a single behavior.
+
+For example, if we wanted to properly test the add function above, we would
+create additional tests cases which would each test a different property that an
+add function should have like this:
+
+.. code-block:: c
+
+ void add_test_basic(struct kunit *test)
+ {
+ KUNIT_EXPECT_EQ(test, 1, add(1, 0));
+ KUNIT_EXPECT_EQ(test, 2, add(1, 1));
+ }
+
+ void add_test_negative(struct kunit *test)
+ {
+ KUNIT_EXPECT_EQ(test, 0, add(-1, 1));
+ }
+
+ void add_test_max(struct kunit *test)
+ {
+ KUNIT_EXPECT_EQ(test, INT_MAX, add(0, INT_MAX));
+ KUNIT_EXPECT_EQ(test, -1, add(INT_MAX, INT_MIN));
+ }
+
+ void add_test_overflow(struct kunit *test)
+ {
+ KUNIT_EXPECT_EQ(test, INT_MIN, add(INT_MAX, 1));
+ }
+
+Notice how it is immediately obvious what all the properties that we are testing
+for are.
+
+Assertions
+~~~~~~~~~~
+
+KUnit also has the concept of an *assertion*. An assertion is just like an
+expectation except the assertion immediately terminates the test case if it is
+not satisfied.
+
+For example:
+
+.. code-block:: c
+
+ static void mock_test_do_expect_default_return(struct kunit *test)
+ {
+ struct mock_test_context *ctx = test->priv;
+ struct mock *mock = ctx->mock;
+ int param0 = 5, param1 = -5;
+ const char *two_param_types[] = {"int", "int"};
+ const void *two_params[] = {¶m0, ¶m1};
+ const void *ret;
+
+ ret = mock->do_expect(mock,
+ "test_printk", test_printk,
+ two_param_types, two_params,
+ ARRAY_SIZE(two_params));
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
+ KUNIT_EXPECT_EQ(test, -4, *((int *) ret));
+ }
+
+In this example, the method under test should return a pointer to a value, so
+if the pointer returned by the method is null or an errno, we don't want to
+bother continuing the test since the following expectation could crash the test
+case. `ASSERT_NOT_ERR_OR_NULL(...)` allows us to bail out of the test case if
+the appropriate conditions have not been satisfied to complete the test.
+
+Test Suites
+~~~~~~~~~~~
+
+Now obviously one unit test isn't very helpful; the power comes from having
+many test cases covering all of your behaviors. Consequently it is common to
+have many *similar* tests; in order to reduce duplication in these closely
+related tests most unit testing frameworks provide the concept of a *test
+suite*, in KUnit we call it a *test suite*; all it is is just a collection of
+test cases for a unit of code with a set up function that gets invoked before
+every test cases and then a tear down function that gets invoked after every
+test case completes.
+
+Example:
+
+.. code-block:: c
+
+ static struct kunit_case example_test_cases[] = {
+ KUNIT_CASE(example_test_foo),
+ KUNIT_CASE(example_test_bar),
+ KUNIT_CASE(example_test_baz),
+ {}
+ };
+
+ static struct kunit_suite example_test_suite = {
+ .name = "example",
+ .init = example_test_init,
+ .exit = example_test_exit,
+ .test_cases = example_test_cases,
+ };
+ kunit_test_suite(example_test_suite);
+
+In the above example the test suite, ``example_test_suite``, would run the test
+cases ``example_test_foo``, ``example_test_bar``, and ``example_test_baz``,
+each would have ``example_test_init`` called immediately before it and would
+have ``example_test_exit`` called immediately after it.
+``kunit_test_suite(example_test_suite)`` registers the test suite with the
+KUnit test framework.
+
+.. note::
+ A test case will only be run if it is associated with a test suite.
+
+For a more information on these types of things see the :doc:`api/test`.
+
+Isolating Behavior
+==================
+
+The most important aspect of unit testing that other forms of testing do not
+provide is the ability to limit the amount of code under test to a single unit.
+In practice, this is only possible by being able to control what code gets run
+when the unit under test calls a function and this is usually accomplished
+through some sort of indirection where a function is exposed as part of an API
+such that the definition of that function can be changed without affecting the
+rest of the code base. In the kernel this primarily comes from two constructs,
+classes, structs that contain function pointers that are provided by the
+implementer, and architecture specific functions which have definitions selected
+at compile time.
+
+Classes
+-------
+
+Classes are not a construct that is built into the C programming language;
+however, it is an easily derived concept. Accordingly, pretty much every project
+that does not use a standardized object oriented library (like GNOME's GObject)
+has their own slightly different way of doing object oriented programming; the
+Linux kernel is no exception.
+
+The central concept in kernel object oriented programming is the class. In the
+kernel, a *class* is a struct that contains function pointers. This creates a
+contract between *implementers* and *users* since it forces them to use the
+same function signature without having to call the function directly. In order
+for it to truly be a class, the function pointers must specify that a pointer
+to the class, known as a *class handle*, be one of the parameters; this makes
+it possible for the member functions (also known as *methods*) to have access
+to member variables (more commonly known as *fields*) allowing the same
+implementation to have multiple *instances*.
+
+Typically a class can be *overridden* by *child classes* by embedding the
+*parent class* in the child class. Then when a method provided by the child
+class is called, the child implementation knows that the pointer passed to it is
+of a parent contained within the child; because of this, the child can compute
+the pointer to itself because the pointer to the parent is always a fixed offset
+from the pointer to the child; this offset is the offset of the parent contained
+in the child struct. For example:
+
+.. code-block:: c
+
+ struct shape {
+ int (*area)(struct shape *this);
+ };
+
+ struct rectangle {
+ struct shape parent;
+ int length;
+ int width;
+ };
+
+ int rectangle_area(struct shape *this)
+ {
+ struct rectangle *self = container_of(this, struct shape, parent);
+
+ return self->length * self->width;
+ };
+
+ void rectangle_new(struct rectangle *self, int length, int width)
+ {
+ self->parent.area = rectangle_area;
+ self->length = length;
+ self->width = width;
+ }
+
+In this example (as in most kernel code) the operation of computing the pointer
+to the child from the pointer to the parent is done by ``container_of``.
+
+Faking Classes
+~~~~~~~~~~~~~~
+
+In order to unit test a piece of code that calls a method in a class, the
+behavior of the method must be controllable, otherwise the test ceases to be a
+unit test and becomes an integration test.
+
+A fake just provides an implementation of a piece of code that is different than
+what runs in a production instance, but behaves identically from the standpoint
+of the callers; this is usually done to replace a dependency that is hard to
+deal with, or is slow.
+
+A good example for this might be implementing a fake EEPROM that just stores the
+"contents" in an internal buffer. For example, let's assume we have a class that
+represents an EEPROM:
+
+.. code-block:: c
+
+ struct eeprom {
+ ssize_t (*read)(struct eeprom *this, size_t offset, char *buffer, size_t count);
+ ssize_t (*write)(struct eeprom *this, size_t offset, const char *buffer, size_t count);
+ };
+
+And we want to test some code that buffers writes to the EEPROM:
+
+.. code-block:: c
+
+ struct eeprom_buffer {
+ ssize_t (*write)(struct eeprom_buffer *this, const char *buffer, size_t count);
+ int flush(struct eeprom_buffer *this);
+ size_t flush_count; /* Flushes when buffer exceeds flush_count. */
+ };
+
+ struct eeprom_buffer *new_eeprom_buffer(struct eeprom *eeprom);
+ void destroy_eeprom_buffer(struct eeprom *eeprom);
+
+We can easily test this code by *faking out* the underlying EEPROM:
+
+.. code-block:: c
+
+ struct fake_eeprom {
+ struct eeprom parent;
+ char contents[FAKE_EEPROM_CONTENTS_SIZE];
+ };
+
+ ssize_t fake_eeprom_read(struct eeprom *parent, size_t offset, char *buffer, size_t count)
+ {
+ struct fake_eeprom *this = container_of(parent, struct fake_eeprom, parent);
+
+ count = min(count, FAKE_EEPROM_CONTENTS_SIZE - offset);
+ memcpy(buffer, this->contents + offset, count);
+
+ return count;
+ }
+
+ ssize_t fake_eeprom_write(struct eeprom *this, size_t offset, const char *buffer, size_t count)
+ {
+ struct fake_eeprom *this = container_of(parent, struct fake_eeprom, parent);
+
+ count = min(count, FAKE_EEPROM_CONTENTS_SIZE - offset);
+ memcpy(this->contents + offset, buffer, count);
+
+ return count;
+ }
+
+ void fake_eeprom_init(struct fake_eeprom *this)
+ {
+ this->parent.read = fake_eeprom_read;
+ this->parent.write = fake_eeprom_write;
+ memset(this->contents, 0, FAKE_EEPROM_CONTENTS_SIZE);
+ }
+
+We can now use it to test ``struct eeprom_buffer``:
+
+.. code-block:: c
+
+ struct eeprom_buffer_test {
+ struct fake_eeprom *fake_eeprom;
+ struct eeprom_buffer *eeprom_buffer;
+ };
+
+ static void eeprom_buffer_test_does_not_write_until_flush(struct kunit *test)
+ {
+ struct eeprom_buffer_test *ctx = test->priv;
+ struct eeprom_buffer *eeprom_buffer = ctx->eeprom_buffer;
+ struct fake_eeprom *fake_eeprom = ctx->fake_eeprom;
+ char buffer[] = {0xff};
+
+ eeprom_buffer->flush_count = SIZE_MAX;
+
+ eeprom_buffer->write(eeprom_buffer, buffer, 1);
+ KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0);
+
+ eeprom_buffer->write(eeprom_buffer, buffer, 1);
+ KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0);
+
+ eeprom_buffer->flush(eeprom_buffer);
+ KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0xff);
+ KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0xff);
+ }
+
+ static void eeprom_buffer_test_flushes_after_flush_count_met(struct kunit *test)
+ {
+ struct eeprom_buffer_test *ctx = test->priv;
+ struct eeprom_buffer *eeprom_buffer = ctx->eeprom_buffer;
+ struct fake_eeprom *fake_eeprom = ctx->fake_eeprom;
+ char buffer[] = {0xff};
+
+ eeprom_buffer->flush_count = 2;
+
+ eeprom_buffer->write(eeprom_buffer, buffer, 1);
+ KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0);
+
+ eeprom_buffer->write(eeprom_buffer, buffer, 1);
+ KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0xff);
+ KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0xff);
+ }
+
+ static void eeprom_buffer_test_flushes_increments_of_flush_count(struct kunit *test)
+ {
+ struct eeprom_buffer_test *ctx = test->priv;
+ struct eeprom_buffer *eeprom_buffer = ctx->eeprom_buffer;
+ struct fake_eeprom *fake_eeprom = ctx->fake_eeprom;
+ char buffer[] = {0xff, 0xff};
+
+ eeprom_buffer->flush_count = 2;
+
+ eeprom_buffer->write(eeprom_buffer, buffer, 1);
+ KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0);
+
+ eeprom_buffer->write(eeprom_buffer, buffer, 2);
+ KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0xff);
+ KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0xff);
+ /* Should have only flushed the first two bytes. */
+ KUNIT_EXPECT_EQ(test, fake_eeprom->contents[2], 0);
+ }
+
+ static int eeprom_buffer_test_init(struct kunit *test)
+ {
+ struct eeprom_buffer_test *ctx;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+ ctx->fake_eeprom = kunit_kzalloc(test, sizeof(*ctx->fake_eeprom), GFP_KERNEL);
+ ASSERT_NOT_ERR_OR_NULL(test, ctx->fake_eeprom);
+
+ ctx->eeprom_buffer = new_eeprom_buffer(&ctx->fake_eeprom->parent);
+ ASSERT_NOT_ERR_OR_NULL(test, ctx->eeprom_buffer);
+
+ test->priv = ctx;
+
+ return 0;
+ }
+
+ static void eeprom_buffer_test_exit(struct kunit *test)
+ {
+ struct eeprom_buffer_test *ctx = test->priv;
+
+ destroy_eeprom_buffer(ctx->eeprom_buffer);
+ }
+
+.. _kunit-on-non-uml:
+
+KUnit on non-UML architectures
+==============================
+
+By default KUnit uses UML as a way to provide dependencies for code under test.
+Under most circumstances KUnit's usage of UML should be treated as an
+implementation detail of how KUnit works under the hood. Nevertheless, there
+are instances where being able to run architecture specific code, or test
+against real hardware is desirable. For these reasons KUnit supports running on
+other architectures.
+
+Running existing KUnit tests on non-UML architectures
+-----------------------------------------------------
+
+There are some special considerations when running existing KUnit tests on
+non-UML architectures:
+
+* Hardware may not be deterministic, so a test that always passes or fails
+ when run under UML may not always do so on real hardware.
+* Hardware and VM environments may not be hermetic. KUnit tries its best to
+ provide a hermetic environment to run tests; however, it cannot manage state
+ that it doesn't know about outside of the kernel. Consequently, tests that
+ may be hermetic on UML may not be hermetic on other architectures.
+* Some features and tooling may not be supported outside of UML.
+* Hardware and VMs are slower than UML.
+
+None of these are reasons not to run your KUnit tests on real hardware; they are
+only things to be aware of when doing so.
+
+The biggest impediment will likely be that certain KUnit features and
+infrastructure may not support your target environment. For example, at this
+time the KUnit Wrapper (``tools/testing/kunit/kunit.py``) does not work outside
+of UML. Unfortunately, there is no way around this. Using UML (or even just a
+particular architecture) allows us to make a lot of assumptions that make it
+possible to do things which might otherwise be impossible.
+
+Nevertheless, all core KUnit framework features are fully supported on all
+architectures, and using them is straightforward: all you need to do is to take
+your kunitconfig, your Kconfig options for the tests you would like to run, and
+merge them into whatever config your are using for your platform. That's it!
+
+For example, let's say you have the following kunitconfig:
+
+.. code-block:: none
+
+ CONFIG_KUNIT=y
+ CONFIG_KUNIT_EXAMPLE_TEST=y
+
+If you wanted to run this test on an x86 VM, you might add the following config
+options to your ``.config``:
+
+.. code-block:: none
+
+ CONFIG_KUNIT=y
+ CONFIG_KUNIT_EXAMPLE_TEST=y
+ CONFIG_SERIAL_8250=y
+ CONFIG_SERIAL_8250_CONSOLE=y
+
+All these new options do is enable support for a common serial console needed
+for logging.
+
+Next, you could build a kernel with these tests as follows:
+
+
+.. code-block:: bash
+
+ make ARCH=x86 olddefconfig
+ make ARCH=x86
+
+Once you have built a kernel, you could run it on QEMU as follows:
+
+.. code-block:: bash
+
+ qemu-system-x86_64 -enable-kvm \
+ -m 1024 \
+ -kernel arch/x86_64/boot/bzImage \
+ -append 'console=ttyS0' \
+ --nographic
+
+Interspersed in the kernel logs you might see the following:
+
+.. code-block:: none
+
+ TAP version 14
+ # Subtest: example
+ 1..1
+ # example_simple_test: initializing
+ ok 1 - example_simple_test
+ ok 1 - example
+
+Congratulations, you just ran a KUnit test on the x86 architecture!
+
+Writing new tests for other architectures
+-----------------------------------------
+
+The first thing you must do is ask yourself whether it is necessary to write a
+KUnit test for a specific architecture, and then whether it is necessary to
+write that test for a particular piece of hardware. In general, writing a test
+that depends on having access to a particular piece of hardware or software (not
+included in the Linux source repo) should be avoided at all costs.
+
+Even if you only ever plan on running your KUnit test on your hardware
+configuration, other people may want to run your tests and may not have access
+to your hardware. If you write your test to run on UML, then anyone can run your
+tests without knowing anything about your particular setup, and you can still
+run your tests on your hardware setup just by compiling for your architecture.
+
+.. important::
+ Always prefer tests that run on UML to tests that only run under a particular
+ architecture, and always prefer tests that run under QEMU or another easy
+ (and monitarily free) to obtain software environment to a specific piece of
+ hardware.
+
+Nevertheless, there are still valid reasons to write an architecture or hardware
+specific test: for example, you might want to test some code that really belongs
+in ``arch/some-arch/*``. Even so, try your best to write the test so that it
+does not depend on physical hardware: if some of your test cases don't need the
+hardware, only require the hardware for tests that actually need it.
+
+Now that you have narrowed down exactly what bits are hardware specific, the
+actual procedure for writing and running the tests is pretty much the same as
+writing normal KUnit tests. One special caveat is that you have to reset
+hardware state in between test cases; if this is not possible, you may only be
+able to run one test case per invocation.
+
+.. TODO(brendanhiggins@google.com): Add an actual example of an architecture
+ dependent KUnit test.
--
2.22.0.410.gd8fdbe21b5-goog
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox