[PATCH v6 0/3] iommu/smmu-v3: Workaround for hisilicon 161010801 erratum(reserve HW MSI)
by Shameer Kolothum
On certain HiSilicon platforms (Hip06/Hip07) the GIC ITS and
PCIe RC deviates from the standard implementation and this breaks
PCIe MSI functionality when SMMU is enabled.
The HiSilicon erratum 161010801 describes this limitation of certain
HiSilicon platforms to support the SMMU mappings for MSI transactions.
On these platforms GICv3 ITS translator is presented with the deviceID
by extending the MSI payload data to 64 bits to include the deviceID.
Hence, the PCIe controller on this platforms has to differentiate the
MSI payload against other DMA payload and has to modify the MSI payload.
This basically makes it difficult for this platforms to have a SMMU
translation for MSI.
To implement this quirk, the following changes are incorporated:
1. Added a generic helper function to IORT code to retrieve and
reserve the HW ITS address regions.
2. Added quirk to SMMUv3 to reserve HW ITS address regions based
on IORT SMMUv3 model with the help of a generic iommu helper
function.
Thanks,
Shameer
Changelog:
v5 --> v6
Addressed comments from Robin and Lorenzo:
-No change to patch#1 .
-Reverted v5 patch#2 as this might break the platforms where this quirk
is not applicable. Provided a generic function in iommu code and
added back the quirk implementation in SMMU v3 driver(patch#3)
v4 --> v5
Addressed comments from Robin and Lorenzo:
-Added a comment to make it clear that, for now, only straightforward
HW topologies are handled while reserving ITS regions(patch #1).
v3 --> v4
Rebased on 4.13-rc1.
Addressed comments from Robin, Will and Lorenzo:
-As suggested by Robin, moved the ITS msi reservation into
iommu_dma_get_resv_regions().
-Added its_count != resv region failure case(patch #1).
v2 --> v3
Addressed comments from Lorenzo and Robin:
-Removed dev_is_pci() check in smmuV3 driver.
-Don't treat device not having an ITS mapping as an error in
iort helper function.
v1 --> v2
-patch 2/2: Invoke iort helper fn based on fwnode type(acpi).
RFCv2 -->PATCH
-Incorporated Lorenzo's review comments.
RFC v1 --> RFC v2
Based on Robin's review comments,
-Removed the generic erratum framework.
-Using IORT/MADT tables to retrieve the ITS base addr instead
of vendor specific CSRT table.
Shameer Kolothum (3):
ACPI/IORT: Add ITS address regions reservation helper
iommu/dma: Add a helper function to reserve HW MSI address regions for
IOMMU drivers
iommu/arm-smmu-v3:Enable ACPI based HiSilicon erratum 161010801
drivers/acpi/arm64/iort.c | 95 ++++++++++++++++++++++++++++++++++++++--
drivers/iommu/arm-smmu-v3.c | 27 +++++++++---
drivers/iommu/dma-iommu.c | 19 ++++++++
drivers/irqchip/irq-gic-v3-its.c | 3 +-
include/linux/acpi_iort.h | 7 ++-
include/linux/dma-iommu.h | 7 +++
6 files changed, 148 insertions(+), 10 deletions(-)
--
1.9.1
4 years, 9 months
ACPICA version 20170831 released
by Moore, Robert
31 August 2017. Summary of changes for version 20170831:
This release is available at https://acpica.org/downloads
1) ACPICA kernel-resident subsystem:
Implemented internal support for full 64-bit addresses that appear in all Generic Address Structure (GAS) structures. Previously, only the lower 32 bits were used. Affects the use of GAS structures in the FADT and other tables, as well as the GAS structures passed to the AcpiRead and AcpiWrite public external interfaces that are used by drivers. Lv Zheng.
Added header support for the PDTT ACPI table (Processor Debug Trigger Table). Full support in the iASL Data Table Compiler and disassembler is forthcoming.
2) iASL Compiler/Disassembler and Tools:
iASL/Disassembler: Fixed a problem with the PPTT ACPI table (Processor Properties Topology Table) where a flag bit was specified in the wrong bit position ("Line Size Valid", bit 6).
iASL: Implemented support for Octal integer constants as defined by the ASL language grammar, per the ACPI specification. Any integer constant that starts with a zero is an octal constant. For example,
Store (037777, Local0) /* Octal constant */
Store (0x3FFF, Local0) /* Hex equivalent */
Store (16383, Local0) /* Decimal equivalent */
iASL: Improved overflow detection for 64-bit string conversions during compilation of integer constants. "Overflow" in this case means a string that represents an integer that is too large to fit into a 64-bit value. Any 64-bit constants within a 32-bit DSDT or SSDT are still truncated to the low-order 32 bits with a warning, as previously implemented. Several new exceptions are defined that indicate a 64-bit overflow, as well as the base (radix) that was used during the attempted conversion. Examples:
Local0 = 0xAAAABBBBCCCCDDDDEEEEFFFF // AE_HEX_OVERFLOW
Local0 = 01111222233334444555566667777 // AE_OCTAL_OVERFLOW
Local0 = 11112222333344445555666677778888 // AE_DECIMAL_OVERFLOW
iASL: Added a warning for the case where a ResourceTemplate is declared with no ResourceDescriptor entries (coded as "ResourceTemplate(){}"). In this case, the resulting template is created with a single END_TAG descriptor, which is essentially useless.
iASL: Expanded the -vw option (ignore specific warnings/remarks) to include compilation error codes as well.
4 years, 10 months
[pm:bleeding-edge 184/195] drivers//acpi/processor_idle.c:854:3: error: implicit declaration of function 'cpuidle_poll_state_init'
by kbuild test robot
tree: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git bleeding-edge
head: 98745c58a5f77fbdf1d602b5241f4eca2072d4df
commit: ae26accf539b4fef8febb60d67d345fed00df834 [184/195] cpuidle: Make drivers initialize polling state
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 6.2.0
reproduce:
wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git checkout ae26accf539b4fef8febb60d67d345fed00df834
# save the attached .config to linux build tree
make.cross ARCH=ia64
All errors (new ones prefixed by >>):
drivers//acpi/processor_idle.c: In function 'acpi_processor_setup_cstates':
>> drivers//acpi/processor_idle.c:854:3: error: implicit declaration of function 'cpuidle_poll_state_init' [-Werror=implicit-function-declaration]
cpuidle_poll_state_init(drv);
^~~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
vim +/cpuidle_poll_state_init +854 drivers//acpi/processor_idle.c
842
843 static int acpi_processor_setup_cstates(struct acpi_processor *pr)
844 {
845 int i, count;
846 struct acpi_processor_cx *cx;
847 struct cpuidle_state *state;
848 struct cpuidle_driver *drv = &acpi_idle_driver;
849
850 if (max_cstate == 0)
851 max_cstate = 1;
852
853 if (IS_ENABLED(CONFIG_ARCH_HAS_CPU_RELAX)) {
> 854 cpuidle_poll_state_init(drv);
855 count = 1;
856 } else {
857 count = 0;
858 }
859
860 for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
861 cx = &pr->power.states[i];
862
863 if (!cx->valid)
864 continue;
865
866 state = &drv->states[count];
867 snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
868 strlcpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
869 state->exit_latency = cx->latency;
870 state->target_residency = cx->latency * latency_factor;
871 state->enter = acpi_idle_enter;
872
873 state->flags = 0;
874 if (cx->type == ACPI_STATE_C1 || cx->type == ACPI_STATE_C2) {
875 state->enter_dead = acpi_idle_play_dead;
876 drv->safe_state_index = count;
877 }
878 /*
879 * Halt-induced C1 is not good for ->enter_freeze, because it
880 * re-enables interrupts on exit. Moreover, C1 is generally not
881 * particularly interesting from the suspend-to-idle angle, so
882 * avoid C1 and the situations in which we may need to fall back
883 * to it altogether.
884 */
885 if (cx->type != ACPI_STATE_C1 && !acpi_idle_fallback_to_c1(pr))
886 state->enter_freeze = acpi_idle_enter_freeze;
887
888 count++;
889 if (count == CPUIDLE_STATE_MAX)
890 break;
891 }
892
893 drv->state_count = count;
894
895 if (!count)
896 return -EINVAL;
897
898 return 0;
899 }
900
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
4 years, 10 months
[PATCH] acpi: acpica: fix acpi operand cache leak in dsutils.c
by Seunghun Han
I found an ACPI cache leak in ACPI early termination and boot continuing case.
When early termination is occurred due to malicious ACPI table, Linux kernel
terminates ACPI function and continues to boot process. While kernel terminates
ACPI function, kmem_cache_destroy() reports Acpi-Operand cache leak.
Boot log of ACPI operand cache leak is as follows:
>[ 0.585957] ACPI: Added _OSI(Module Device)
>[ 0.587218] ACPI: Added _OSI(Processor Device)
>[ 0.588530] ACPI: Added _OSI(3.0 _SCP Extensions)
>[ 0.589790] ACPI: Added _OSI(Processor Aggregator Device)
>[ 0.591534] ACPI Error: Illegal I/O port address/length above 64K: C806E00000004002/0x2 (20170303/hwvalid-155)
>[ 0.594351] ACPI Exception: AE_LIMIT, Unable to initialize fixed events (20170303/evevent-88)
>[ 0.597858] ACPI: Unable to start the ACPI Interpreter
>[ 0.599162] ACPI Error: Could not remove SCI handler (20170303/evmisc-281)
>[ 0.601836] kmem_cache_destroy Acpi-Operand: Slab cache still has objects
>[ 0.603556] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.12.0-rc5 #26
>[ 0.605159] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
>[ 0.609177] Call Trace:
>[ 0.610063] ? dump_stack+0x5c/0x81
>[ 0.611118] ? kmem_cache_destroy+0x1aa/0x1c0
>[ 0.612632] ? acpi_sleep_proc_init+0x27/0x27
>[ 0.613906] ? acpi_os_delete_cache+0xa/0x10
>[ 0.617986] ? acpi_ut_delete_caches+0x3f/0x7b
>[ 0.619293] ? acpi_terminate+0xa/0x14
>[ 0.620394] ? acpi_init+0x2af/0x34f
>[ 0.621616] ? __class_create+0x4c/0x80
>[ 0.623412] ? video_setup+0x7f/0x7f
>[ 0.624585] ? acpi_sleep_proc_init+0x27/0x27
>[ 0.625861] ? do_one_initcall+0x4e/0x1a0
>[ 0.627513] ? kernel_init_freeable+0x19e/0x21f
>[ 0.628972] ? rest_init+0x80/0x80
>[ 0.630043] ? kernel_init+0xa/0x100
>[ 0.631084] ? ret_from_fork+0x25/0x30
>[ 0.633343] vgaarb: loaded
>[ 0.635036] EDAC MC: Ver: 3.0.0
>[ 0.638601] PCI: Probing PCI hardware
>[ 0.639833] PCI host bridge to bus 0000:00
>[ 0.641031] pci_bus 0000:00: root bus resource [io 0x0000-0xffff]
> ... Continue to boot and log is omitted ...
I analyzed this memory leak in detail and found acpi_ds_obj_stack_pop_and_
delete() function miscalculated the top of the stack. acpi_ds_obj_stack_push()
function uses walk_state->operand_index for start position of the top, but
acpi_ds_obj_stack_pop_and_delete() function considers index 0 for it.
Therefore, this causes acpi operand memory leak.
This cache leak causes a security threat because an old kernel (<= 4.9) shows
memory locations of kernel functions in stack dump. Some malicious users
could use this information to neutralize kernel ASLR.
I made a patch to fix ACPI operand cache leak.
Signed-off-by: Seunghun Han <kkamagui(a)gmail.com>
---
drivers/acpi/acpica/dsutils.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index 0dabd9b..2c8a060 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -705,6 +705,8 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state,
union acpi_parse_object *arguments[ACPI_OBJ_NUM_OPERANDS];
u32 arg_count = 0;
u32 index = walk_state->num_operands;
+ u32 prev_num_operands = walk_state->num_operands;
+ u32 new_num_operands;
u32 i;
ACPI_FUNCTION_TRACE_PTR(ds_create_operands, first_arg);
@@ -733,6 +735,7 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state,
/* Create the interpreter arguments, in reverse order */
+ new_num_operands = index;
index--;
for (i = 0; i < arg_count; i++) {
arg = arguments[index];
@@ -757,7 +760,11 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state,
* pop everything off of the operand stack and delete those
* objects
*/
- acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state);
+ walk_state->num_operands = i;
+ acpi_ds_obj_stack_pop_and_delete(new_num_operands, walk_state);
+
+ /* Restore operand count */
+ walk_state->num_operands = prev_num_operands;
ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %u", index));
return_ACPI_STATUS(status);
--
2.1.4
4 years, 10 months
Re: [Devel] [PATCH] actbl1.h: use tab instead of seven spaces as the indentation
by Zheng, Lv
Hi,
> From: linux-acpi-owner(a)vger.kernel.org [mailto:[email protected]] On Behalf Of Chao Fan
> Subject: [PATCH] actbl1.h: use tab instead of seven spaces as the indentation
>
> The indentation of these two lines is seven spaces, but not tab.
> So fix it.
>
> Signed-off-by: Chao Fan <fanc.fnst(a)cn.fujitsu.com>
> ---
> include/acpi/actbl1.h | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
> index b4ce55c008b0..d13e5b416a7e 100644
> --- a/include/acpi/actbl1.h
> +++ b/include/acpi/actbl1.h
> @@ -1223,9 +1223,9 @@ struct acpi_srat_mem_affinity {
> u16 reserved; /* Reserved, must be zero */
> u64 base_address;
> u64 length;
> - u32 reserved1;
> + u32 reserved1;
> u32 flags;
> - u64 reserved2; /* Reserved, must be zero */
> + u64 reserved2; /* Reserved, must be zero */
> };
>
> /* Flags */
> --
You needn't do this manually.
An indentation fix commit can be easily and automatically generated by ACPICA linuxize script - divergence.sh.
See Documentation/acpi/linuxized-acpica.txt for detailed information.
Thanks
Lv
4 years, 10 months
[PATCH] iasl: Add SMMUv3 device ID mapping index support
by Hanjun Guo
From: Hanjun Guo <hanjun.guo(a)linaro.org>
SMMUv3 device ID mapping index is used for SMMUv3
MSI, add its support for iasl.
Signed-off-by: Hanjun Guo <hanjun.guo(a)linaro.org>
---
source/common/dmtbinfo.c | 1 +
source/include/actbl2.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/source/common/dmtbinfo.c b/source/common/dmtbinfo.c
index 4b902b9..4a403e4 100644
--- a/source/common/dmtbinfo.c
+++ b/source/common/dmtbinfo.c
@@ -1850,6 +1850,7 @@ ACPI_DMTABLE_INFO AcpiDmTableInfoIort4[] =
{ACPI_DMT_UINT8, ACPI_IORT4_OFFSET (Pxm), "Proximity Domain", 0},
{ACPI_DMT_UINT8, ACPI_IORT4_OFFSET (Reserved1), "Reserved", 0},
{ACPI_DMT_UINT16, ACPI_IORT4_OFFSET (Reserved2), "Reserved", 0},
+ {ACPI_DMT_UINT32, ACPI_IORT4_OFFSET (DevIdMappingIndex), "DeviceID mapping index", 0},
ACPI_DMT_TERMINATOR
};
diff --git a/source/include/actbl2.h b/source/include/actbl2.h
index 18cfdd4..1a8c1a2 100644
--- a/source/include/actbl2.h
+++ b/source/include/actbl2.h
@@ -1047,6 +1047,7 @@ typedef struct acpi_iort_smmu_v3
UINT8 Pxm;
UINT8 Reserved1;
UINT16 Reserved2;
+ UINT32 DevIdMappingIndex;
} ACPI_IORT_SMMU_V3;
--
1.7.12.4
4 years, 10 months
[pm:bleeding-edge 136/148] drivers//acpi/spcr.c:205:2: note: in expansion of macro 'pr_info'
by kbuild test robot
tree: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git bleeding-edge
head: 8c649da5a7719ff87155d4c9e850f374a39856d4
commit: fd46b1aebee729fb984f74b7b8d81db210ec6355 [136/148] ACPI: SPCR: work around clock issue on xgene UART
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git checkout fd46b1aebee729fb984f74b7b8d81db210ec6355
# save the attached .config to linux build tree
make.cross ARCH=arm64
All error/warnings (new ones prefixed by >>):
drivers//acpi/spcr.c: In function 'parse_spcr':
>> drivers//acpi/spcr.c:191:2: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
if (xgene_8250_erratum_present(table))
^~
drivers//acpi/spcr.c:198:3: note: ...this statement, but the latter is misleadingly indented as if it is guarded by the 'if'
snprintf(opts, sizeof(opts), "%s,%s,0x%llx", uart, iotype,
^~~~~~~~
>> drivers//acpi/spcr.c:164:3: error: label 'done' used but not defined
goto done;
^~~~
drivers//acpi/spcr.c: At top level:
>> drivers//acpi/spcr.c:200:4: error: expected identifier or '(' before 'else'
} else {
^~~~
In file included from include/linux/printk.h:6:0,
from include/linux/kernel.h:13,
from include/linux/list.h:8,
from include/linux/resource_ext.h:17,
from include/linux/acpi.h:26,
from drivers//acpi/spcr.c:14:
>> include/linux/kern_levels.h:4:18: error: expected declaration specifiers or '...' before string constant
#define KERN_SOH "\001" /* ASCII Start Of Header */
^
include/linux/kern_levels.h:13:19: note: in expansion of macro 'KERN_SOH'
#define KERN_INFO KERN_SOH "6" /* informational */
^~~~~~~~
include/linux/printk.h:308:9: note: in expansion of macro 'KERN_INFO'
printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~
>> drivers//acpi/spcr.c:205:2: note: in expansion of macro 'pr_info'
pr_info("console: %s\n", opts);
^~~~~~~
In file included from include/linux/kernel.h:13:0,
from include/linux/list.h:8,
from include/linux/resource_ext.h:17,
from include/linux/acpi.h:26,
from drivers//acpi/spcr.c:14:
>> drivers//acpi/spcr.c:205:27: error: unknown type name 'opts'
pr_info("console: %s\n", opts);
^
include/linux/printk.h:308:34: note: in definition of macro 'pr_info'
printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~~~
>> drivers//acpi/spcr.c:207:2: error: expected identifier or '(' before 'if'
if (earlycon)
^~
>> drivers//acpi/spcr.c:210:2: warning: data definition has no type or storage class
err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
^~~
>> drivers//acpi/spcr.c:210:2: error: type defaults to 'int' in declaration of 'err' [-Werror=implicit-int]
>> drivers//acpi/spcr.c:210:30: error: 'uart' undeclared here (not in a function)
err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
^~~~
>> drivers//acpi/spcr.c:210:39: error: 'opts' undeclared here (not in a function)
err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
^~~~
>> drivers//acpi/spcr.c:212:5: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token
done:
^
>> drivers//acpi/spcr.c:214:2: error: expected identifier or '(' before 'return'
return err;
^~~~~~
>> drivers//acpi/spcr.c:215:1: error: expected identifier or '(' before '}' token
}
^
drivers//acpi/spcr.c: In function 'parse_spcr':
>> drivers//acpi/spcr.c:200:2: warning: control reaches end of non-void function [-Wreturn-type]
} else {
^
cc1: some warnings being treated as errors
--
drivers/acpi/spcr.c: In function 'parse_spcr':
drivers/acpi/spcr.c:191:2: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
if (xgene_8250_erratum_present(table))
^~
drivers/acpi/spcr.c:198:3: note: ...this statement, but the latter is misleadingly indented as if it is guarded by the 'if'
snprintf(opts, sizeof(opts), "%s,%s,0x%llx", uart, iotype,
^~~~~~~~
drivers/acpi/spcr.c:164:3: error: label 'done' used but not defined
goto done;
^~~~
drivers/acpi/spcr.c: At top level:
drivers/acpi/spcr.c:200:4: error: expected identifier or '(' before 'else'
} else {
^~~~
In file included from include/linux/printk.h:6:0,
from include/linux/kernel.h:13,
from include/linux/list.h:8,
from include/linux/resource_ext.h:17,
from include/linux/acpi.h:26,
from drivers/acpi/spcr.c:14:
>> include/linux/kern_levels.h:4:18: error: expected declaration specifiers or '...' before string constant
#define KERN_SOH "\001" /* ASCII Start Of Header */
^
include/linux/kern_levels.h:13:19: note: in expansion of macro 'KERN_SOH'
#define KERN_INFO KERN_SOH "6" /* informational */
^~~~~~~~
include/linux/printk.h:308:9: note: in expansion of macro 'KERN_INFO'
printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~
drivers/acpi/spcr.c:205:2: note: in expansion of macro 'pr_info'
pr_info("console: %s\n", opts);
^~~~~~~
In file included from include/linux/kernel.h:13:0,
from include/linux/list.h:8,
from include/linux/resource_ext.h:17,
from include/linux/acpi.h:26,
from drivers/acpi/spcr.c:14:
drivers/acpi/spcr.c:205:27: error: unknown type name 'opts'
pr_info("console: %s\n", opts);
^
include/linux/printk.h:308:34: note: in definition of macro 'pr_info'
printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~~~
drivers/acpi/spcr.c:207:2: error: expected identifier or '(' before 'if'
if (earlycon)
^~
drivers/acpi/spcr.c:210:2: warning: data definition has no type or storage class
err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
^~~
drivers/acpi/spcr.c:210:2: error: type defaults to 'int' in declaration of 'err' [-Werror=implicit-int]
drivers/acpi/spcr.c:210:30: error: 'uart' undeclared here (not in a function)
err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
^~~~
drivers/acpi/spcr.c:210:39: error: 'opts' undeclared here (not in a function)
err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
^~~~
drivers/acpi/spcr.c:212:5: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token
done:
^
drivers/acpi/spcr.c:214:2: error: expected identifier or '(' before 'return'
return err;
^~~~~~
drivers/acpi/spcr.c:215:1: error: expected identifier or '(' before '}' token
}
^
drivers/acpi/spcr.c: In function 'parse_spcr':
drivers/acpi/spcr.c:200:2: warning: control reaches end of non-void function [-Wreturn-type]
} else {
^
cc1: some warnings being treated as errors
vim +/pr_info +205 drivers//acpi/spcr.c
ad1696f6f Aleksey Makarov 2016-09-27 13
ad1696f6f Aleksey Makarov 2016-09-27 @14 #include <linux/acpi.h>
ad1696f6f Aleksey Makarov 2016-09-27 15 #include <linux/console.h>
ad1696f6f Aleksey Makarov 2016-09-27 16 #include <linux/kernel.h>
ad1696f6f Aleksey Makarov 2016-09-27 17 #include <linux/serial_core.h>
ad1696f6f Aleksey Makarov 2016-09-27 18
d8a4995bc Christopher Covington 2017-02-15 19 /*
37ef38f3f Timur Tabi 2017-07-27 20 * Erratum 44 for QDF2432v1 and QDF2400v1 SoCs describes the BUSY bit as
37ef38f3f Timur Tabi 2017-07-27 21 * occasionally getting stuck as 1. To avoid the potential for a hang, check
37ef38f3f Timur Tabi 2017-07-27 22 * TXFE == 0 instead of BUSY == 1. This may not be suitable for all UART
37ef38f3f Timur Tabi 2017-07-27 23 * implementations, so only do so if an affected platform is detected in
37ef38f3f Timur Tabi 2017-07-27 24 * parse_spcr().
37ef38f3f Timur Tabi 2017-07-27 25 */
37ef38f3f Timur Tabi 2017-07-27 26 bool qdf2400_e44_present;
37ef38f3f Timur Tabi 2017-07-27 27 EXPORT_SYMBOL(qdf2400_e44_present);
37ef38f3f Timur Tabi 2017-07-27 28
37ef38f3f Timur Tabi 2017-07-27 29 /*
d8a4995bc Christopher Covington 2017-02-15 30 * Some Qualcomm Datacenter Technologies SoCs have a defective UART BUSY bit.
d8a4995bc Christopher Covington 2017-02-15 31 * Detect them by examining the OEM fields in the SPCR header, similiar to PCI
d8a4995bc Christopher Covington 2017-02-15 32 * quirk detection in pci_mcfg.c.
d8a4995bc Christopher Covington 2017-02-15 33 */
d8a4995bc Christopher Covington 2017-02-15 34 static bool qdf2400_erratum_44_present(struct acpi_table_header *h)
d8a4995bc Christopher Covington 2017-02-15 35 {
d8a4995bc Christopher Covington 2017-02-15 36 if (memcmp(h->oem_id, "QCOM ", ACPI_OEM_ID_SIZE))
d8a4995bc Christopher Covington 2017-02-15 37 return false;
d8a4995bc Christopher Covington 2017-02-15 38
d8a4995bc Christopher Covington 2017-02-15 39 if (!memcmp(h->oem_table_id, "QDF2432 ", ACPI_OEM_TABLE_ID_SIZE))
d8a4995bc Christopher Covington 2017-02-15 40 return true;
d8a4995bc Christopher Covington 2017-02-15 41
d8a4995bc Christopher Covington 2017-02-15 42 if (!memcmp(h->oem_table_id, "QDF2400 ", ACPI_OEM_TABLE_ID_SIZE) &&
542ed7846 Timur Tabi 2017-02-28 43 h->oem_revision == 1)
d8a4995bc Christopher Covington 2017-02-15 44 return true;
d8a4995bc Christopher Covington 2017-02-15 45
d8a4995bc Christopher Covington 2017-02-15 46 return false;
d8a4995bc Christopher Covington 2017-02-15 47 }
d8a4995bc Christopher Covington 2017-02-15 48
79a648328 Loc Ho 2017-07-03 49 /*
79a648328 Loc Ho 2017-07-03 50 * APM X-Gene v1 and v2 UART hardware is an 16550 like device but has its
79a648328 Loc Ho 2017-07-03 51 * register aligned to 32-bit. In addition, the BIOS also encoded the
79a648328 Loc Ho 2017-07-03 52 * access width to be 8 bits. This function detects this errata condition.
79a648328 Loc Ho 2017-07-03 53 */
79a648328 Loc Ho 2017-07-03 54 static bool xgene_8250_erratum_present(struct acpi_table_spcr *tb)
79a648328 Loc Ho 2017-07-03 55 {
dee82bc1e Graeme Gregory 2017-08-04 56 bool xgene_8250 = false;
dee82bc1e Graeme Gregory 2017-08-04 57
79a648328 Loc Ho 2017-07-03 58 if (tb->interface_type != ACPI_DBG2_16550_COMPATIBLE)
79a648328 Loc Ho 2017-07-03 59 return false;
79a648328 Loc Ho 2017-07-03 60
dee82bc1e Graeme Gregory 2017-08-04 61 if (memcmp(tb->header.oem_id, "APMC0D", ACPI_OEM_ID_SIZE) &&
dee82bc1e Graeme Gregory 2017-08-04 62 memcmp(tb->header.oem_id, "HPE ", ACPI_OEM_ID_SIZE))
79a648328 Loc Ho 2017-07-03 63 return false;
79a648328 Loc Ho 2017-07-03 64
79a648328 Loc Ho 2017-07-03 65 if (!memcmp(tb->header.oem_table_id, "XGENESPC",
79a648328 Loc Ho 2017-07-03 66 ACPI_OEM_TABLE_ID_SIZE) && tb->header.oem_revision == 0)
dee82bc1e Graeme Gregory 2017-08-04 67 xgene_8250 = true;
79a648328 Loc Ho 2017-07-03 68
dee82bc1e Graeme Gregory 2017-08-04 69 if (!memcmp(tb->header.oem_table_id, "ProLiant",
dee82bc1e Graeme Gregory 2017-08-04 70 ACPI_OEM_TABLE_ID_SIZE) && tb->header.oem_revision == 1)
dee82bc1e Graeme Gregory 2017-08-04 71 xgene_8250 = true;
dee82bc1e Graeme Gregory 2017-08-04 72
dee82bc1e Graeme Gregory 2017-08-04 73 return xgene_8250;
79a648328 Loc Ho 2017-07-03 74 }
79a648328 Loc Ho 2017-07-03 75
ad1696f6f Aleksey Makarov 2016-09-27 76 /**
ad1696f6f Aleksey Makarov 2016-09-27 77 * parse_spcr() - parse ACPI SPCR table and add preferred console
ad1696f6f Aleksey Makarov 2016-09-27 78 *
ad1696f6f Aleksey Makarov 2016-09-27 79 * @earlycon: set up earlycon for the console specified by the table
ad1696f6f Aleksey Makarov 2016-09-27 80 *
ad1696f6f Aleksey Makarov 2016-09-27 81 * For the architectures with support for ACPI, CONFIG_ACPI_SPCR_TABLE may be
ad1696f6f Aleksey Makarov 2016-09-27 82 * defined to parse ACPI SPCR table. As a result of the parsing preferred
ad1696f6f Aleksey Makarov 2016-09-27 83 * console is registered and if @earlycon is true, earlycon is set up.
ad1696f6f Aleksey Makarov 2016-09-27 84 *
ad1696f6f Aleksey Makarov 2016-09-27 85 * When CONFIG_ACPI_SPCR_TABLE is defined, this function should be called
183b8021f Masahiro Yamada 2017-02-27 86 * from arch initialization code as soon as the DT/ACPI decision is made.
ad1696f6f Aleksey Makarov 2016-09-27 87 *
ad1696f6f Aleksey Makarov 2016-09-27 88 */
ad1696f6f Aleksey Makarov 2016-09-27 89 int __init parse_spcr(bool earlycon)
ad1696f6f Aleksey Makarov 2016-09-27 90 {
ad1696f6f Aleksey Makarov 2016-09-27 91 static char opts[64];
ad1696f6f Aleksey Makarov 2016-09-27 92 struct acpi_table_spcr *table;
ad1696f6f Aleksey Makarov 2016-09-27 93 acpi_status status;
ad1696f6f Aleksey Makarov 2016-09-27 94 char *uart;
ad1696f6f Aleksey Makarov 2016-09-27 95 char *iotype;
ad1696f6f Aleksey Makarov 2016-09-27 96 int baud_rate;
ad1696f6f Aleksey Makarov 2016-09-27 97 int err;
ad1696f6f Aleksey Makarov 2016-09-27 98
ad1696f6f Aleksey Makarov 2016-09-27 99 if (acpi_disabled)
ad1696f6f Aleksey Makarov 2016-09-27 100 return -ENODEV;
ad1696f6f Aleksey Makarov 2016-09-27 101
6b11d1d67 Lv Zheng 2016-12-14 102 status = acpi_get_table(ACPI_SIG_SPCR, 0,
6b11d1d67 Lv Zheng 2016-12-14 103 (struct acpi_table_header **)&table);
ad1696f6f Aleksey Makarov 2016-09-27 104
ad1696f6f Aleksey Makarov 2016-09-27 105 if (ACPI_FAILURE(status))
ad1696f6f Aleksey Makarov 2016-09-27 106 return -ENOENT;
ad1696f6f Aleksey Makarov 2016-09-27 107
ad1696f6f Aleksey Makarov 2016-09-27 108 if (table->header.revision < 2) {
ad1696f6f Aleksey Makarov 2016-09-27 109 err = -ENOENT;
ad1696f6f Aleksey Makarov 2016-09-27 110 pr_err("wrong table version\n");
ad1696f6f Aleksey Makarov 2016-09-27 111 goto done;
ad1696f6f Aleksey Makarov 2016-09-27 112 }
ad1696f6f Aleksey Makarov 2016-09-27 113
2bece4939 Loc Ho 2017-07-03 114 if (table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
2bece4939 Loc Ho 2017-07-03 115 switch (table->serial_port.access_width) {
2bece4939 Loc Ho 2017-07-03 116 default:
2bece4939 Loc Ho 2017-07-03 117 pr_err("Unexpected SPCR Access Width. Defaulting to byte size\n");
2bece4939 Loc Ho 2017-07-03 118 case ACPI_ACCESS_SIZE_BYTE:
2bece4939 Loc Ho 2017-07-03 119 iotype = "mmio";
2bece4939 Loc Ho 2017-07-03 120 break;
2bece4939 Loc Ho 2017-07-03 121 case ACPI_ACCESS_SIZE_WORD:
2bece4939 Loc Ho 2017-07-03 122 iotype = "mmio16";
2bece4939 Loc Ho 2017-07-03 123 break;
2bece4939 Loc Ho 2017-07-03 124 case ACPI_ACCESS_SIZE_DWORD:
2bece4939 Loc Ho 2017-07-03 125 iotype = "mmio32";
2bece4939 Loc Ho 2017-07-03 126 break;
2bece4939 Loc Ho 2017-07-03 127 }
2bece4939 Loc Ho 2017-07-03 128 } else
2bece4939 Loc Ho 2017-07-03 129 iotype = "io";
ad1696f6f Aleksey Makarov 2016-09-27 130
ad1696f6f Aleksey Makarov 2016-09-27 131 switch (table->interface_type) {
ad1696f6f Aleksey Makarov 2016-09-27 132 case ACPI_DBG2_ARM_SBSA_32BIT:
ad1696f6f Aleksey Makarov 2016-09-27 133 iotype = "mmio32";
ad1696f6f Aleksey Makarov 2016-09-27 134 /* fall through */
ad1696f6f Aleksey Makarov 2016-09-27 135 case ACPI_DBG2_ARM_PL011:
ad1696f6f Aleksey Makarov 2016-09-27 136 case ACPI_DBG2_ARM_SBSA_GENERIC:
ad1696f6f Aleksey Makarov 2016-09-27 137 case ACPI_DBG2_BCM2835:
ad1696f6f Aleksey Makarov 2016-09-27 138 uart = "pl011";
ad1696f6f Aleksey Makarov 2016-09-27 139 break;
ad1696f6f Aleksey Makarov 2016-09-27 140 case ACPI_DBG2_16550_COMPATIBLE:
ad1696f6f Aleksey Makarov 2016-09-27 141 case ACPI_DBG2_16550_SUBSET:
ad1696f6f Aleksey Makarov 2016-09-27 142 uart = "uart";
ad1696f6f Aleksey Makarov 2016-09-27 143 break;
ad1696f6f Aleksey Makarov 2016-09-27 144 default:
ad1696f6f Aleksey Makarov 2016-09-27 145 err = -ENOENT;
ad1696f6f Aleksey Makarov 2016-09-27 146 goto done;
ad1696f6f Aleksey Makarov 2016-09-27 147 }
ad1696f6f Aleksey Makarov 2016-09-27 148
ad1696f6f Aleksey Makarov 2016-09-27 149 switch (table->baud_rate) {
ad1696f6f Aleksey Makarov 2016-09-27 150 case 3:
ad1696f6f Aleksey Makarov 2016-09-27 151 baud_rate = 9600;
ad1696f6f Aleksey Makarov 2016-09-27 152 break;
ad1696f6f Aleksey Makarov 2016-09-27 153 case 4:
ad1696f6f Aleksey Makarov 2016-09-27 154 baud_rate = 19200;
ad1696f6f Aleksey Makarov 2016-09-27 155 break;
ad1696f6f Aleksey Makarov 2016-09-27 156 case 6:
ad1696f6f Aleksey Makarov 2016-09-27 157 baud_rate = 57600;
ad1696f6f Aleksey Makarov 2016-09-27 158 break;
ad1696f6f Aleksey Makarov 2016-09-27 159 case 7:
ad1696f6f Aleksey Makarov 2016-09-27 160 baud_rate = 115200;
ad1696f6f Aleksey Makarov 2016-09-27 161 break;
ad1696f6f Aleksey Makarov 2016-09-27 162 default:
ad1696f6f Aleksey Makarov 2016-09-27 163 err = -ENOENT;
ad1696f6f Aleksey Makarov 2016-09-27 @164 goto done;
ad1696f6f Aleksey Makarov 2016-09-27 165 }
ad1696f6f Aleksey Makarov 2016-09-27 166
37ef38f3f Timur Tabi 2017-07-27 167 /*
37ef38f3f Timur Tabi 2017-07-27 168 * If the E44 erratum is required, then we need to tell the pl011
37ef38f3f Timur Tabi 2017-07-27 169 * driver to implement the work-around.
37ef38f3f Timur Tabi 2017-07-27 170 *
37ef38f3f Timur Tabi 2017-07-27 171 * The global variable is used by the probe function when it
37ef38f3f Timur Tabi 2017-07-27 172 * creates the UARTs, whether or not they're used as a console.
37ef38f3f Timur Tabi 2017-07-27 173 *
37ef38f3f Timur Tabi 2017-07-27 174 * If the user specifies "traditional" earlycon, the qdf2400_e44
37ef38f3f Timur Tabi 2017-07-27 175 * console name matches the EARLYCON_DECLARE() statement, and
37ef38f3f Timur Tabi 2017-07-27 176 * SPCR is not used. Parameter "earlycon" is false.
37ef38f3f Timur Tabi 2017-07-27 177 *
37ef38f3f Timur Tabi 2017-07-27 178 * If the user specifies "SPCR" earlycon, then we need to update
37ef38f3f Timur Tabi 2017-07-27 179 * the console name so that it also says "qdf2400_e44". Parameter
37ef38f3f Timur Tabi 2017-07-27 180 * "earlycon" is true.
37ef38f3f Timur Tabi 2017-07-27 181 *
37ef38f3f Timur Tabi 2017-07-27 182 * For consistency, if we change the console name, then we do it
37ef38f3f Timur Tabi 2017-07-27 183 * for everyone, not just earlycon.
37ef38f3f Timur Tabi 2017-07-27 184 */
37ef38f3f Timur Tabi 2017-07-27 185 if (qdf2400_erratum_44_present(&table->header)) {
37ef38f3f Timur Tabi 2017-07-27 186 qdf2400_e44_present = true;
37ef38f3f Timur Tabi 2017-07-27 187 if (earlycon)
d8a4995bc Christopher Covington 2017-02-15 188 uart = "qdf2400_e44";
37ef38f3f Timur Tabi 2017-07-27 189 }
37ef38f3f Timur Tabi 2017-07-27 190
79a648328 Loc Ho 2017-07-03 @191 if (xgene_8250_erratum_present(table))
79a648328 Loc Ho 2017-07-03 192 iotype = "mmio32";
d8a4995bc Christopher Covington 2017-02-15 193
fd46b1aeb Graeme Gregory 2017-08-04 194 /* for xgene v1 and v2 we don't know the clock rate of the
fd46b1aeb Graeme Gregory 2017-08-04 195 * UART so don't attempt to change to the baud rate state
fd46b1aeb Graeme Gregory 2017-08-04 196 * in the table because driver cannot calculate the dividers
fd46b1aeb Graeme Gregory 2017-08-04 197 */
fd46b1aeb Graeme Gregory 2017-08-04 @198 snprintf(opts, sizeof(opts), "%s,%s,0x%llx", uart, iotype,
fd46b1aeb Graeme Gregory 2017-08-04 199 table->serial_port.address);
fd46b1aeb Graeme Gregory 2017-08-04 @200 } else {
ad1696f6f Aleksey Makarov 2016-09-27 201 snprintf(opts, sizeof(opts), "%s,%s,0x%llx,%d", uart, iotype,
ad1696f6f Aleksey Makarov 2016-09-27 202 table->serial_port.address, baud_rate);
fd46b1aeb Graeme Gregory 2017-08-04 203 }
ad1696f6f Aleksey Makarov 2016-09-27 204
ad1696f6f Aleksey Makarov 2016-09-27 @205 pr_info("console: %s\n", opts);
ad1696f6f Aleksey Makarov 2016-09-27 206
ad1696f6f Aleksey Makarov 2016-09-27 @207 if (earlycon)
ad1696f6f Aleksey Makarov 2016-09-27 208 setup_earlycon(opts);
ad1696f6f Aleksey Makarov 2016-09-27 209
ad1696f6f Aleksey Makarov 2016-09-27 @210 err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
ad1696f6f Aleksey Makarov 2016-09-27 211
ad1696f6f Aleksey Makarov 2016-09-27 @212 done:
6b11d1d67 Lv Zheng 2016-12-14 213 acpi_put_table((struct acpi_table_header *)table);
ad1696f6f Aleksey Makarov 2016-09-27 @214 return err;
ad1696f6f Aleksey Makarov 2016-09-27 @215 }
:::::: The code at line 205 was first introduced by commit
:::::: ad1696f6f09daacfdf2bf04bc83cd8f48d80e34a ACPI: parse SPCR and enable matching console
:::::: TO: Aleksey Makarov <aleksey.makarov(a)linaro.org>
:::::: CC: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
4 years, 10 months
[pm:testing 6/14] drivers//acpi/spcr.c:168:1: error: version control conflict marker in file
by kbuild test robot
tree: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git testing
head: c394fc6acab189ab34001d7b994e5b3c7fae66c3
commit: f69ba1326ac33b30659e1b64911391a37ae8a13f [6/14] Merge branch 'acpi-spcr' into linux-next
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git checkout f69ba1326ac33b30659e1b64911391a37ae8a13f
# save the attached .config to linux build tree
make.cross ARCH=arm64
All errors (new ones prefixed by >>):
drivers//acpi/spcr.c: In function 'parse_spcr':
>> drivers//acpi/spcr.c:168:1: error: version control conflict marker in file
<<<<<<< HEAD
^~~~~~~
drivers//acpi/spcr.c:198:1: error: version control conflict marker in file
>>>>>>> acpi-spcr
^~~~~~~
At top level:
drivers//acpi/spcr.c:34:13: warning: 'qdf2400_erratum_44_present' defined but not used [-Wunused-function]
static bool qdf2400_erratum_44_present(struct acpi_table_header *h)
^~~~~~~~~~~~~~~~~~~~~~~~~~
vim +168 drivers//acpi/spcr.c
75
76 /**
77 * parse_spcr() - parse ACPI SPCR table and add preferred console
78 *
79 * @earlycon: set up earlycon for the console specified by the table
80 *
81 * For the architectures with support for ACPI, CONFIG_ACPI_SPCR_TABLE may be
82 * defined to parse ACPI SPCR table. As a result of the parsing preferred
83 * console is registered and if @earlycon is true, earlycon is set up.
84 *
85 * When CONFIG_ACPI_SPCR_TABLE is defined, this function should be called
86 * from arch initialization code as soon as the DT/ACPI decision is made.
87 *
88 */
89 int __init parse_spcr(bool earlycon)
90 {
91 static char opts[64];
92 struct acpi_table_spcr *table;
93 acpi_status status;
94 char *uart;
95 char *iotype;
96 int baud_rate;
97 int err;
98
99 if (acpi_disabled)
100 return -ENODEV;
101
102 status = acpi_get_table(ACPI_SIG_SPCR, 0,
103 (struct acpi_table_header **)&table);
104
105 if (ACPI_FAILURE(status))
106 return -ENOENT;
107
108 if (table->header.revision < 2) {
109 err = -ENOENT;
110 pr_err("wrong table version\n");
111 goto done;
112 }
113
114 if (table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
115 switch (ACPI_ACCESS_BIT_WIDTH((
116 table->serial_port.access_width))) {
117 default:
118 pr_err("Unexpected SPCR Access Width. Defaulting to byte size\n");
119 case 8:
120 iotype = "mmio";
121 break;
122 case 16:
123 iotype = "mmio16";
124 break;
125 case 32:
126 iotype = "mmio32";
127 break;
128 }
129 } else
130 iotype = "io";
131
132 switch (table->interface_type) {
133 case ACPI_DBG2_ARM_SBSA_32BIT:
134 iotype = "mmio32";
135 /* fall through */
136 case ACPI_DBG2_ARM_PL011:
137 case ACPI_DBG2_ARM_SBSA_GENERIC:
138 case ACPI_DBG2_BCM2835:
139 uart = "pl011";
140 break;
141 case ACPI_DBG2_16550_COMPATIBLE:
142 case ACPI_DBG2_16550_SUBSET:
143 uart = "uart";
144 break;
145 default:
146 err = -ENOENT;
147 goto done;
148 }
149
150 switch (table->baud_rate) {
151 case 3:
152 baud_rate = 9600;
153 break;
154 case 4:
155 baud_rate = 19200;
156 break;
157 case 6:
158 baud_rate = 57600;
159 break;
160 case 7:
161 baud_rate = 115200;
162 break;
163 default:
164 err = -ENOENT;
165 goto done;
166 }
167
> 168 <<<<<<< HEAD
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
4 years, 10 months
[PATCH 0/2] ACPICA: Events: Fix GPE enabling issues related to edge-triggered GPEs
by Lv Zheng
There are 2 issues related to the enabling of GPEs:
1. Currently, our code clears GPE before enabling it. In case of edge
triggered GPEs, doing this risks GPE losses.
2. For edge-triggered GPEs, enabling it is not sufficiently to trigger an
already triggered GPE, we need to poll the GPE once it is enabled.
This patchset fixes these 2 problems.
Lv Zheng (2):
ACPICA: Events: Stop unconditionally clearing ACPI IRQs during
suspend/resume
ACPICA: Events: Dispatch GPEs after enabling for the first time
drivers/acpi/acpica/evgpe.c | 7 -------
drivers/acpi/acpica/evxfgpe.c | 22 ++++++++++++++++++++++
drivers/acpi/acpica/hwgpe.c | 1 -
drivers/acpi/acpica/hwsleep.c | 11 ++---------
drivers/acpi/acpica/hwxfsleep.c | 2 +-
5 files changed, 25 insertions(+), 18 deletions(-)
--
2.7.4
4 years, 10 months