* [RESEND PATCH v2 1/3] reset: oxnas: Add OX820 support
From: Philipp Zabel @ 2016-10-20 10:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161005152710.2898-2-narmstrong@baylibre.com>
Am Mittwoch, den 05.10.2016, 17:27 +0200 schrieb Neil Armstrong:
> In order to support the Oxford Semiconductor OX820 SoC, add a new
> compatible string.
>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
> drivers/reset/reset-oxnas.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/reset/reset-oxnas.c b/drivers/reset/reset-oxnas.c
> index 9449805..0d9036d 100644
> --- a/drivers/reset/reset-oxnas.c
> +++ b/drivers/reset/reset-oxnas.c
> @@ -80,6 +80,7 @@ static const struct reset_control_ops oxnas_reset_ops = {
>
> static const struct of_device_id oxnas_reset_dt_ids[] = {
> { .compatible = "oxsemi,ox810se-reset", },
> + { .compatible = "oxsemi,ox820-reset", },
> { /* sentinel */ },
> };
> MODULE_DEVICE_TABLE(of, oxnas_reset_dt_ids);
Applied all three, thanks.
regards
Philipp
^ permalink raw reply
* [PATCH v3 0/11] Add R8A7743/SK-RZG1M board support
From: Geert Uytterhoeven @ 2016-10-20 9:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161020092459.GM4612@verge.net.au>
Hi Simon,
On Thu, Oct 20, 2016 at 11:24 AM, Simon Horman <horms@verge.net.au> wrote:
> On Wed, Oct 12, 2016 at 11:29:56AM +0300, Sergei Shtylyov wrote:
>> On 10/12/2016 11:09 AM, Simon Horman wrote:
>> >>> Here's the set of 11 patches against Simon Horman's 'renesas.git' repo's
>> >>>'renesas-devel-20161003-v4.8' tag. I'm adding the device tree support for
>> >>>the R8A7743-based SK-RZG1M board. The SoC is close to R8A7791 and the board
>> >>>seems identical to the R8A7791/Porter board. The device tree patches depend on
>> >>>the R8A7743 CPG/MSSR driver series just posted in order to compile and work.
>> >>
>> >> Forgot to mention that this version causes a regression with the sh_eth
>> >>driver (well, actually with phylib): since IRQC now gets a deferred probing,
>> >>PHY IRQ doesn't work anymore -- phylib falls back to polling.
>> >
>> >Is there a resolution to that problem?
>>
>> Geert has posted his IRQC driver patch recently. Not sure if it was
>> intended for merging but it solves the issue.
>
> Ok. I think it is ok to merge support for a new board even if there are
> problems as its not regressing (can't break something that previously
> didn't exist imho). But of course it would be best if things did work.
>
> Geert, do you have any comments on the relevance of your IRQC driver patch?
That patch is relevant, until the MDIO framework is fixed.
It will start to matter more when migrating more (R-Car Gen2) SoCs to the new
CPG/MSSR driver.
It would be good to give that patch some testing on more R-Car Gen2 boards
with NFS root (difficult for me with remote access and network latencies).
After that I can submit it to the irqchip maintainers, as I don't believe MDIO
will be fixed soonish...
Thanks for testing ;-)
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH v2 3/6] ARM: at91: Add armv7m support
From: Arnd Bergmann @ 2016-10-20 9:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161020094135.18221-4-alexandre.belloni@free-electrons.com>
On Thursday, October 20, 2016 11:41:32 AM CEST Alexandre Belloni wrote:
> +
> +static void __init samx7_dt_device_init(void)
> +{
> + struct soc_device *soc;
> + struct device *soc_dev = NULL;
> +
> + soc = at91_soc_init(samx7_socs);
> + if (soc)
> + soc_dev = soc_device_to_device(soc);
> +
> + of_platform_populate(NULL, of_default_bus_match_table, NULL, soc_dev);
> +}
This was initially the idea for the soc_device, but we've stopped
using it as the parent for the on-chip devices a while ago.
Just register the device for identification here, and use
of_platform_default_populate with a NULL parent as most others do.
We should also investigate whether we can convert the three other
at91 variants to do the same without breaking expectations in user space.
Arnd
^ permalink raw reply
* [PATCH V6 00/10] dmaengine: qcom_hidma: add MSI interrupt support
From: Vinod Koul @ 2016-10-20 9:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476899512-20431-1-git-send-email-okaya@codeaurora.org>
On Wed, Oct 19, 2016 at 01:51:42PM -0400, Sinan Kaya wrote:
> The new version of the HW supports MSI interrupts instead of wired
> interrupts. The MSI interrupts are especially useful for the guest machine
> execution. The wired interrupts usually trap to the hypervisor and then are
> relayed to the actual interrupt.
>
> The MSI interrupts can be directly fed into the interrupt controller.
>
> Adding a new OF compat string (qcom,hidma-1.1) and ACPI string (QCOM8062)
> to distinguish newer HW from the older ones.
>
> v6:
> * rebase 4.9 kernel
Why???
I already told you that I have applied 6 in the last version, please dont
send me stuff which is already applied :(
--
~Vinod
^ permalink raw reply
* [PATCH v2 6/6] ARM: at91: debug: add samx7 support
From: Alexandre Belloni @ 2016-10-20 9:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161020094135.18221-1-alexandre.belloni@free-electrons.com>
From: Szemz? Andr?s <sza@esh.hu>
Add support for low level debugging on Atmel samx7.
Signed-off-by: Szemz? Andr?s <sza@esh.hu>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
arch/arm/Kconfig.debug | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index d83f7c369e51..219e65c85289 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -145,6 +145,15 @@ choice
Say Y here if you want kernel low-level debugging support
on the USART3 port of sama5d4.
+ config DEBUG_AT91_SAMX7_USART1
+ bool "Kernel low-level debugging via SAMX7 USART1"
+ select DEBUG_AT91_UART
+ depends on SOC_SAMX7
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the USART1 port on SAMX7 based
+ machines.
+
config DEBUG_BCM2835
bool "Kernel low-level debugging on BCM2835 PL011 UART"
depends on ARCH_BCM2835 && ARCH_MULTI_V6
@@ -1481,6 +1490,7 @@ config DEBUG_UART_PHYS
default 0x3f201000 if DEBUG_BCM2836
default 0x3e000000 if DEBUG_BCM_KONA_UART
default 0x4000e400 if DEBUG_LL_UART_EFM32
+ default 0x40028000 if DEBUG_AT91_SAMX7_USART1
default 0x40081000 if DEBUG_LPC18XX_UART0
default 0x40090000 if DEBUG_LPC32XX
default 0x40100000 if DEBUG_PXA_UART1
--
2.9.3
^ permalink raw reply related
* [PATCH v2 5/6] ARM: dts: at91: add samx7 dtsi
From: Alexandre Belloni @ 2016-10-20 9:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161020094135.18221-1-alexandre.belloni@free-electrons.com>
From: Szemz? Andr?s <sza@esh.hu>
Add device tree support for Atmel samx7 SoCs family.
Signed-off-by: Szemz? Andr?s <sza@esh.hu>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
arch/arm/boot/dts/samx7.dtsi | 1128 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1128 insertions(+)
create mode 100644 arch/arm/boot/dts/samx7.dtsi
diff --git a/arch/arm/boot/dts/samx7.dtsi b/arch/arm/boot/dts/samx7.dtsi
new file mode 100644
index 000000000000..a4b36586d108
--- /dev/null
+++ b/arch/arm/boot/dts/samx7.dtsi
@@ -0,0 +1,1128 @@
+/*
+ * samx7.dtsi - Device Tree Include file for SAMx7 family SoCs
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "armv7-m.dtsi"
+#include <dt-bindings/pinctrl/at91.h>
+#include <dt-bindings/dma/at91.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/clock/at91.h>
+#include <dt-bindings/pwm/pwm.h>
+
+/ {
+ model = "Atmel SAMx7 family SoC";
+ compatible = "atmel,samx7";
+
+ aliases {
+ serial0 = &usart0;
+ serial1 = &usart1;
+ serial2 = &usart2;
+ serial3 = &uart0;
+ serial4 = &uart1;
+ serial5 = &uart2;
+ serial6 = &uart3;
+ serial7 = &uart4;
+ gpio0 = &pioA;
+ gpio1 = &pioB;
+ gpio2 = &pioC;
+ gpio3 = &pioD;
+ gpio4 = &pioE;
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+ tcb0 = &tcb0;
+ tcb1 = &tcb1;
+ tcb2 = &tcb2;
+ tcb3 = &tcb3;
+ pwm0 = &pwm0;
+ pwm1 = &pwm1;
+ };
+
+ clocks {
+
+ clk_slck: clk-slck {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ };
+
+ clk_mck: clk-mck {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ };
+ };
+
+ soc {
+
+ pmc: pmc at 0x400e0600 {
+ compatible = "atmel,at91sam9x5-pmc", "syscon";
+ reg = <0x400e0600 0x200>;
+ interrupts = <5>;
+ interrupt-controller;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+ periphck {
+ compatible = "atmel,at91sam9x5-clk-peripheral";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&clk_mck>;
+
+ uart0_clk: uart0_clk {
+ #clock-cells = <0>;
+ reg = <7>;
+ };
+
+ uart1_clk: uart1_clk {
+ #clock-cells = <0>;
+ reg = <8>;
+ };
+
+ smc_clk: smc_clk {
+ #clock-cells = <0>;
+ reg = <9>;
+ };
+
+ pioA_clk: pioA_clk {
+ #clock-cells = <0>;
+ reg = <10>;
+ };
+
+ pioB_clk: pioB_clk {
+ #clock-cells = <0>;
+ reg = <11>;
+ };
+
+ pioC_clk: pioC_clk {
+ #clock-cells = <0>;
+ reg = <12>;
+ };
+
+ usart0_clk: usart0_clk {
+ #clock-cells = <0>;
+ reg = <13>;
+ };
+
+ usart1_clk: usart1_clk {
+ #clock-cells = <0>;
+ reg = <14>;
+ };
+
+ usart2_clk: usart2_clk {
+ #clock-cells = <0>;
+ reg = <15>;
+ };
+
+ pioD_clk: pioD_clk {
+ #clock-cells = <0>;
+ reg = <16>;
+ };
+
+ pioE_clk: pioE_clk {
+ #clock-cells = <0>;
+ reg = <17>;
+ };
+
+ mci_clk: mci_clk {
+ #clock-cells = <0>;
+ reg = <18>;
+ };
+
+ twi0_clk: twi0_clk {
+ #clock-cells = <0>;
+ reg = <19>;
+ };
+
+ twi1_clk: twi1_clk {
+ #clock-cells = <0>;
+ reg = <20>;
+ };
+
+ spi0_clk: spi0_clk {
+ #clock-cells = <0>;
+ reg = <21>;
+ };
+
+ ssc_clk: ssc_clk {
+ #clock-cells = <0>;
+ reg = <22>;
+ };
+
+ tcb0_clk: tcb0_clk {
+ #clock-cells = <0>;
+ reg = <23>;
+ };
+
+ tcb1_clk: tcb1_clk {
+ #clock-cells = <0>;
+ reg = <24>;
+ };
+
+ tcb2_clk: tcb2_clk {
+ #clock-cells = <0>;
+ reg = <25>;
+ };
+
+ tcb3_clk: tcb3_clk {
+ #clock-cells = <0>;
+ reg = <26>;
+ };
+
+ tcb4_clk: tcb4_clk {
+ #clock-cells = <0>;
+ reg = <27>;
+ };
+
+ tcb5_clk: tcb5_clk {
+ #clock-cells = <0>;
+ reg = <28>;
+ };
+
+ afec0_clk: afec0_clk {
+ #clock-cells = <0>;
+ reg = <29>;
+ };
+
+ dacc_clk: dacc_clk {
+ #clock-cells = <0>;
+ reg = <30>;
+ };
+
+ pwm0_clk: pwm0_clk {
+ #clock-cells = <0>;
+ reg = <31>;
+ };
+
+ icm_clk: cim_clk {
+ #clock-cells = <0>;
+ reg = <32>;
+ };
+
+ acc_clk: acc_clk {
+ #clock-cells = <0>;
+ reg = <33>;
+ };
+
+ usbhs_clk: usbhs_clk {
+ #clock-cells = <0>;
+ reg = <34>;
+ };
+
+ can0_clk: can0_clk {
+ #clock-cells = <0>;
+ reg = <35>;
+ };
+
+ can1_clk: can1_clk {
+ #clock-cells = <0>;
+ reg = <37>;
+ };
+
+ macb_clk: macb_clk {
+ #clock-cells = <0>;
+ reg = <39>;
+ };
+
+ afec1_clk: afec1_clk {
+ #clock-cells = <0>;
+ reg = <40>;
+ };
+
+ twi2_clk: twi2_clk {
+ #clock-cells = <0>;
+ reg = <41>;
+ };
+
+ spi1_clk: spi1_clk {
+ #clock-cells = <0>;
+ reg = <42>;
+ };
+
+ qspi_clk: qspi_clk {
+ #clock-cells = <0>;
+ reg = <43>;
+ };
+
+ uart2_clk: uart2_clk {
+ #clock-cells = <0>;
+ reg = <44>;
+ };
+
+ uart3_clk: uart3_clk {
+ #clock-cells = <0>;
+ reg = <45>;
+ };
+
+ uart4_clk: uart4_clk {
+ #clock-cells = <0>;
+ reg = <46>;
+ };
+
+ tcb6_clk: tcb6_clk {
+ #clock-cells = <0>;
+ reg = <47>;
+ };
+
+ tcb7_clk: tcb7_clk {
+ #clock-cells = <0>;
+ reg = <48>;
+ };
+
+ tcb8_clk: tcb8_clk {
+ #clock-cells = <0>;
+ reg = <49>;
+ };
+
+ tcb9_clk: tcb9_clk {
+ #clock-cells = <0>;
+ reg = <50>;
+ };
+
+ tcb10_clk: tcb10_clk {
+ #clock-cells = <0>;
+ reg = <51>;
+ };
+
+ tcb11_clk: tcb11_clk {
+ #clock-cells = <0>;
+ reg = <52>;
+ };
+
+ aes_clk: aes_clk {
+ #clock-cells = <0>;
+ reg = <56>;
+ };
+
+ trng_clk: trng_clk {
+ #clock-cells = <0>;
+ reg = <57>;
+ };
+
+ dma_clk: dma_clk {
+ #clock-cells = <0>;
+ reg = <58>;
+ };
+
+ isi_clk: isi_clk {
+ #clock-cells = <0>;
+ reg = <59>;
+ };
+
+ pwm1_clk: pwm1_clk {
+ #clock-cells = <0>;
+ reg = <60>;
+ };
+
+ i2sc0_clk: i2sc0_clk {
+ #clock-cells = <0>;
+ reg = <69>;
+ };
+
+ i2sc1_clk: i2sc1_clk {
+ #clock-cells = <0>;
+ reg = <70>;
+ };
+ };
+ };
+
+ pinctrl at 0x400e0e00 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "atmel,sama5d3-pinctrl", "atmel,at91sam9x5-pinctrl", "simple-bus";
+ ranges = <0x400e0e00 0x400e0e00 0xa00>;
+
+ pioA: gpio at 0x400e0e00 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0x400e0e00 0x200>;
+ interrupts = <10>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&pioA_clk>;
+ };
+
+ pioB: gpio at 0x400e1000 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0x400e1000 0x200>;
+ interrupts = <11>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&pioB_clk>;
+ };
+
+ pioC: gpio at 0x400e1200 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0x400e1200 0x200>;
+ interrupts = <12>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&pioC_clk>;
+ };
+
+ pioD: gpio at 0x400e1400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0x400e1400 0x200>;
+ interrupts = <16>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&pioD_clk>;
+ };
+
+ pioE: gpio at 0x400e1600 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0x400e1600 0x200>;
+ interrupts = <17>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&pioE_clk>;
+ };
+
+ macb {
+ pinctrl_macb_rmii: macb_rmii-0 {
+ atmel,pins =
+ <AT91_PIOD 0 AT91_PERIPH_A AT91_PINCTRL_NONE
+ AT91_PIOD 1 AT91_PERIPH_A AT91_PINCTRL_NONE
+ AT91_PIOD 2 AT91_PERIPH_A AT91_PINCTRL_NONE
+ AT91_PIOD 3 AT91_PERIPH_A AT91_PINCTRL_NONE
+ AT91_PIOD 4 AT91_PERIPH_A AT91_PINCTRL_NONE
+ AT91_PIOD 5 AT91_PERIPH_A AT91_PINCTRL_NONE
+ AT91_PIOD 6 AT91_PERIPH_A AT91_PINCTRL_NONE
+ AT91_PIOD 7 AT91_PERIPH_A AT91_PINCTRL_NONE
+ AT91_PIOD 8 AT91_PERIPH_A AT91_PINCTRL_NONE
+ AT91_PIOD 9 AT91_PERIPH_A AT91_PINCTRL_NONE
+ >;
+ };
+ };
+
+ mmc {
+ pinctrl_mmc_clk_cmd_dat0: mmc_clk_cmd_dat0 {
+ atmel,pins =
+ <AT91_PIOA 25 AT91_PERIPH_D AT91_PINCTRL_NONE /* MCI_CK */
+ AT91_PIOA 28 AT91_PERIPH_C AT91_PINCTRL_PULL_UP /* MCI_CDA */
+ AT91_PIOA 30 AT91_PERIPH_C AT91_PINCTRL_PULL_UP /* MCI_DB0 */
+ >;
+ };
+ pinctrl_mmc_dat1_3: mmc_dat1_3 {
+ atmel,pins =
+ <AT91_PIOA 31 AT91_PERIPH_C AT91_PINCTRL_PULL_UP /* MCI_DB1 */
+ AT91_PIOA 26 AT91_PERIPH_C AT91_PINCTRL_PULL_UP /* MCI_DB2 */
+ AT91_PIOA 27 AT91_PERIPH_C AT91_PINCTRL_PULL_UP /* MCI_DB3 */
+ >;
+ };
+ };
+
+ i2c0 {
+ pinctrl_i2c0: i2c0-0 {
+ atmel,pins =
+ <AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE /* I2C0 data */
+ AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE>; /* I2C0 clock */
+ };
+ };
+
+ i2c1 {
+ pinctrl_i2c1: i2c1-0 {
+ atmel,pins =
+ <AT91_PIOB 4 AT91_PERIPH_A AT91_PINCTRL_NONE /* I2C1 data */
+ AT91_PIOB 5 AT91_PERIPH_A AT91_PINCTRL_NONE>; /* I2C1 clock */
+ };
+ };
+
+ i2c2 {
+ pinctrl_i2c2: i2c2-0 {
+ atmel,pins =
+ <AT91_PIOD 27 AT91_PERIPH_C AT91_PINCTRL_NONE /* I2C2 data */
+ AT91_PIOD 28 AT91_PERIPH_C AT91_PINCTRL_NONE>; /* I2C2 clock */
+ };
+ };
+
+ qspi {
+ pinctrl_qspi: qspi-0 {
+ atmel,pins =
+ <AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE /* QSCK */
+ AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE /* QCS */
+ AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE /* QIO0 */
+ AT91_PIOA 12 AT91_PERIPH_A AT91_PINCTRL_NONE /* QIO1 */
+ AT91_PIOA 17 AT91_PERIPH_A AT91_PINCTRL_NONE /* QIO2 */
+ AT91_PIOD 31 AT91_PERIPH_A AT91_PINCTRL_NONE /* QIO3 */
+ >;
+ };
+ };
+
+ usart0 {
+ pinctrl_usart0: usart0-0 {
+ atmel,pins =
+ <AT91_PIOB 0 AT91_PERIPH_C AT91_PINCTRL_NONE /* RXD */
+ AT91_PIOB 1 AT91_PERIPH_C AT91_PINCTRL_PULL_UP /* TXD */
+ >;
+ };
+
+ pinctrl_usart0_rts: usart0_rts-0 {
+ atmel,pins = <AT91_PIOB 3 AT91_PERIPH_C AT91_PINCTRL_NONE>;
+ };
+
+ pinctrl_usart0_cts: usart0_cts-0 {
+ atmel,pins = <AT91_PIOB 2 AT91_PERIPH_C AT91_PINCTRL_NONE>;
+ };
+ };
+
+ usart1 {
+ pinctrl_usart1: usart1-0 {
+ atmel,pins =
+ <AT91_PIOA 21 AT91_PERIPH_A AT91_PINCTRL_NONE /* RXD */
+ AT91_PIOB 4 AT91_PERIPH_D AT91_PINCTRL_PULL_UP /* TXD */
+ >;
+ };
+
+ pinctrl_usart1_rts: usart1_rts-0 {
+ atmel,pins = <AT91_PIOA 24 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+
+ pinctrl_usart1_cts: usart1_cts-0 {
+ atmel,pins = <AT91_PIOA 25 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+ };
+
+ usart2 {
+ pinctrl_usart2: usart2-0 {
+ atmel,pins =
+ <AT91_PIOD 15 AT91_PERIPH_B AT91_PINCTRL_NONE /* RXD */
+ AT91_PIOD 16 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* TXD */
+ >;
+ };
+
+ pinctrl_usart2_rts: usart2_rts-0 {
+ atmel,pins = <AT91_PIOD 18 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+
+ pinctrl_usart2_cts: usart2_cts-0 {
+ atmel,pins = <AT91_PIOD 19 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ };
+
+ spi0 {
+ pinctrl_spi0: spi0-0 {
+ atmel,pins =
+ <AT91_PIOD 20 AT91_PERIPH_B AT91_PINCTRL_NONE /* SPI0_MISO */
+ AT91_PIOD 21 AT91_PERIPH_B AT91_PINCTRL_NONE /* SPI0_MOSI */
+ AT91_PIOD 22 AT91_PERIPH_B AT91_PINCTRL_NONE /* SPI0_SPCK */
+ >;
+ };
+ };
+
+ spi1 {
+ pinctrl_spi1: spi1-0 {
+ atmel,pins =
+ <AT91_PIOC 26 AT91_PERIPH_C AT91_PINCTRL_NONE /* SPI1_MISO */
+ AT91_PIOC 27 AT91_PERIPH_C AT91_PINCTRL_NONE /* SPI1_MOSI */
+ AT91_PIOC 24 AT91_PERIPH_C AT91_PINCTRL_NONE /* SPI1_SPCK */
+ >;
+ };
+ };
+
+ can0 {
+ pinctrl_can0_rx_tx: can0_rx_tx {
+ atmel,pins =
+ <AT91_PIOB 3 AT91_PERIPH_A AT91_PINCTRL_NONE /* RX */
+ AT91_PIOB 2 AT91_PERIPH_A AT91_PINCTRL_NONE>; /* TX */
+ };
+ };
+
+ can1 {
+ pinctrl_can1_rx_tx: can1_rx_tx {
+ atmel,pins =
+ <AT91_PIOC 12 AT91_PERIPH_C AT91_PINCTRL_NONE /* RX */
+ AT91_PIOC 14 AT91_PERIPH_C AT91_PINCTRL_NONE>; /* TX */
+ };
+ };
+
+ pwm0 {
+ pinctrl_pwm0_pwmh0_0: pwm0_pwmh0-0 {
+ atmel,pins =
+ <AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh0_1: pwm0_pwmh0-1 {
+ atmel,pins =
+ <AT91_PIOA 11 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh0_2: pwm0_pwmh0-2 {
+ atmel,pins =
+ <AT91_PIOA 23 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh0_3: pwm0_pwmh0-3 {
+ atmel,pins =
+ <AT91_PIOB 0 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh0_4: pwm0_pwmh0-4 {
+ atmel,pins =
+ <AT91_PIOD 11 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh0_5: pwm0_pwmh0-5 {
+ atmel,pins =
+ <AT91_PIOD 20 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+
+ pinctrl_pwm0_pwmh1_0: pwm0_pwmh1-0 {
+ atmel,pins =
+ <AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh1_1: pwm0_pwmh1-1 {
+ atmel,pins =
+ <AT91_PIOA 12 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh1_2: pwm0_pwmh1-2 {
+ atmel,pins =
+ <AT91_PIOA 24 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh1_3: pwm0_pwmh1-3 {
+ atmel,pins =
+ <AT91_PIOB 1 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh1_4: pwm0_pwmh1-4 {
+ atmel,pins =
+ <AT91_PIOD 21 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+
+ pinctrl_pwm0_pwmh2_0: pwm0_pwmh2-0 {
+ atmel,pins =
+ <AT91_PIOA 13 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh2_1: pwm0_pwmh2-1 {
+ atmel,pins =
+ <AT91_PIOA 25 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh2_2: pwm0_pwmh2-2 {
+ atmel,pins =
+ <AT91_PIOB 4 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh2_3: pwm0_pwmh2-3 {
+ atmel,pins =
+ <AT91_PIOC 19 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh2_4: pwm0_pwmh2-4 {
+ atmel,pins =
+ <AT91_PIOD 22 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+
+ pinctrl_pwm0_pwmh3_0: pwm0_pwmh3-0 {
+ atmel,pins =
+ <AT91_PIOA 7 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh3_1: pwm0_pwmh3-1 {
+ atmel,pins =
+ <AT91_PIOA 14 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh3_2: pwm0_pwmh3-2 {
+ atmel,pins =
+ <AT91_PIOA 17 AT91_PERIPH_C AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh3_3: pwm0_pwmh3-3 {
+ atmel,pins =
+ <AT91_PIOC 13 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh3_4: pwm0_pwmh3-4 {
+ atmel,pins =
+ <AT91_PIOC 21 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwmh3_5: pwm0_pwmh3-5 {
+ atmel,pins =
+ <AT91_PIOD 23 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+ };
+
+ pwm1 {
+ pinctrl_pwm1_pwmh0_0: pwm1_pwmh0-0 {
+ atmel,pins =
+ <AT91_PIOA 12 AT91_PERIPH_C AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm1_pwmh0_1: pwm1_pwmh0-1 {
+ atmel,pins =
+ <AT91_PIOD 1 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+
+ pinctrl_pwm1_pwmh1_0: pwm1_pwmh1-0 {
+ atmel,pins =
+ <AT91_PIOA 14 AT91_PERIPH_C AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm1_pwmh1_1: pwm1_pwmh1-1 {
+ atmel,pins =
+ <AT91_PIOD 3 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+
+ pinctrl_pwm1_pwmh2_0: pwm1_pwmh2-0 {
+ atmel,pins =
+ <AT91_PIOA 31 AT91_PERIPH_D AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm1_pwmh2_1: pwm1_pwmh2-1 {
+ atmel,pins =
+ <AT91_PIOD 5 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+
+ pinctrl_pwm1_pwmh3_0: pwm1_pwmh3-0 {
+ atmel,pins =
+ <AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm1_pwmh3_1: pwm1_pwmh3-1 {
+ atmel,pins =
+ <AT91_PIOD 7 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ };
+
+ ssc {
+ pinctrl_ssc_tx: ssc_tx {
+ atmel,pins =
+ <AT91_PIOB 1 AT91_PERIPH_D AT91_PINCTRL_NONE /* TK */
+ AT91_PIOB 0 AT91_PERIPH_D AT91_PINCTRL_NONE /* TF */
+ AT91_PIOD 26 AT91_PERIPH_B AT91_PINCTRL_NONE>; /* TD */
+ };
+
+ pinctrl_ssc_rx: ssc_rx {
+ atmel,pins =
+ <AT91_PIOA 22 AT91_PERIPH_A AT91_PINCTRL_NONE /* RK */
+ AT91_PIOD 24 AT91_PERIPH_B AT91_PINCTRL_NONE /* RF */
+ AT91_PIOA 10 AT91_PERIPH_C AT91_PINCTRL_NONE>; /* RD */
+ };
+ };
+ };
+
+ chipid: chipid at 0x400e0940 {
+ compatible = "atmel,sama5d2-chipid";
+ reg = <0x400e0940 0xc0>;
+ };
+
+ rstc at 400e1800 {
+ compatible = "atmel,samx7-rstc";
+ reg = <0x400e1800 0x10>;
+ clocks = <&clk_slck>;
+ };
+
+ ssc: ssc at 40004000 {
+ compatible = "atmel,at91sam9g45-ssc";
+ reg = <0x40004000 0x4000>;
+ interrupts = <22>;
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(32))>,
+ <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(33))>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ssc_tx &pinctrl_ssc_rx>;
+ clocks = <&ssc_clk>;
+ clock-names = "pclk";
+ status = "disabled";
+ };
+
+ pwm0: pwm at 40020000 {
+ compatible = "atmel,sama5d3-pwm";
+ reg = <0x40020000 0x4000>;
+ interrupts = <31>;
+ #pwm-cells = <3>;
+ clocks = <&pwm0_clk>;
+ status = "disabled";
+ };
+
+ pwm1: pwm at 4005c000 {
+ compatible = "atmel,sama5d3-pwm";
+ reg = <0x4005c000 0x4000>;
+ interrupts = <60>;
+ #pwm-cells = <3>;
+ clocks = <&pwm1_clk>;
+ status = "disabled";
+ };
+
+ watchdog at 400e1850 {
+ compatible = "atmel,at91sam9260-wdt";
+ reg = <0x400e1850 0x10>;
+ interrupts = <4>;
+ clocks = <&clk_slck>;
+ atmel,watchdog-type = "hardware";
+ atmel,reset-type = "all";
+ atmel,dbg-halt;
+ status = "disabled";
+ };
+
+ tcb0: timer at 4000c000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0x4000c000 0x4000>;
+ interrupts = <23 24 25>;
+ clocks = <&tcb0_clk>, <&tcb1_clk>, <&tcb2_clk>, <&clk_slck>;
+ clock-names = "t0_clk", "t1_clk", "t2_clk", "slow_clk";
+ status = "disabled";
+ };
+
+ tcb1: timer at 40010000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0x40010000 0x4000>;
+ interrupts = <26 27 28>;
+ clocks = <&tcb3_clk>, <&tcb4_clk>, <&tcb5_clk>, <&clk_slck>;
+ clock-names = "t0_clk", "t1_clk", "t2_clk", "slow_clk";
+ status = "disabled";
+ };
+
+ tcb2: timer at 40014000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0x40014000 0x4000>;
+ interrupts = <47 48 49>;
+ clocks = <&tcb6_clk>, <&tcb7_clk>, <&tcb8_clk>, <&clk_slck>;
+ clock-names = "t0_clk", "t1_clk", "t2_clk", "slow_clk";
+ status = "disabled";
+ };
+
+ tcb3: timer at 40054000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0x40054000 0x4000>;
+ interrupts = <50 51 52>;
+ clocks = <&tcb9_clk>, <&tcb10_clk>, <&tcb11_clk>, <&clk_slck>;
+ clock-names = "t0_clk", "t1_clk", "t2_clk", "slow_clk";
+ status = "disabled";
+ };
+
+ dma: dma-controller at 40078000 {
+ compatible = "atmel,sama5d4-dma";
+ reg = <0x40078000 0x4000>;
+ interrupts = <58>;
+ #dma-cells = <1>;
+ clocks = <&dma_clk>;
+ clock-names = "dma_clk";
+ status = "disabled";
+ };
+
+ qspi: qspi at 4007c000 {
+ compatible = "atmel,sama5d2-qspi";
+ reg = <0x4007c000 0x4000>, <0x80000000 0x20000000>;
+ reg-names = "qspi_base", "qspi_mmap";
+ interrupts = <43>;
+ clocks = <&qspi_clk>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_qspi>;
+ status = "disabled";
+ };
+
+ aes at 4006c000 {
+ compatible = "atmel,at91sam9g46-aes";
+ reg = <0x4006c000 0x4000>;
+ interrupts = <56>;
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(37))>,
+ <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(38))>;
+ dma-names = "tx", "rx";
+ clocks = <&aes_clk>;
+ clock-names = "aes_clk";
+ status = "disabled";
+ };
+
+ i2c0: i2c at 40018000 {
+ compatible = "atmel,sama5d2-i2c";
+ reg = <0x40018000 0x4000>;
+ interrupts = <19>;
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(14))>,
+ <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(15))>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&twi0_clk>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c at 4001c000 {
+ compatible = "atmel,sama5d2-i2c";
+ reg = <0x4001c000 0x4000>;
+ interrupts = <20>;
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(16))>,
+ <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(17))>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&twi1_clk>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "disabled";
+ };
+
+ i2c2: i2c at 40060000 {
+ compatible = "atmel,sama5d2-i2c";
+ reg = <0x40060000 0x4000>;
+ interrupts = <41>;
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(18))>,
+ <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(19))>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&twi2_clk>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "disabled";
+ };
+
+ mmc0: mmc at 40000000 {
+ compatible = "atmel,hsmci";
+ reg = <0x40000000 0x4000>;
+ interrupts = <18>;
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(0))>;
+ dma-names = "rxtx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mmc_clk_cmd_dat0 &pinctrl_mmc_dat1_3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&mci_clk>;
+ clock-names = "mci_clk";
+ status = "disabled";
+ };
+
+ spi0: spi at 40008000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0x40008000 0x4000>;
+ interrupts = <21>;
+ atmel,fifo-size = <0>;
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(1))>,
+ <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(2))>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi0>;
+ clocks = <&spi0_clk>;
+ clock-names = "spi_clk";
+ status = "disabled";
+ };
+
+ trng at 4007000 {
+ compatible = "atmel,at91sam9g45-trng";
+ reg = <0x40070000 0x4000>;
+ interrupts = <57>;
+ clocks = <&trng_clk>;
+ status = "disabled";
+ };
+
+ rtc at 400e1860 {
+ compatible = "atmel,at91rm9200-rtc";
+ reg = <0x400e1860 0x30>;
+ interrupts = <2>;
+ clocks = <&clk_slck>;
+ status = "disabled";
+ };
+
+ usart0: serial at 40024000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0x40024000 0x4000>;
+ interrupts = <13>;
+ clocks = <&usart0_clk>;
+ clock-names = "usart";
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(7))>,
+ <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(8))>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart0>;
+ status = "disabled";
+ };
+
+ usart1: serial at 40028000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0x40028000 0x4000>;
+ interrupts = <14>;
+ clocks = <&usart1_clk>;
+ clock-names = "usart";
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(9))>,
+ <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(10))>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
+ status = "disabled";
+ };
+
+ usart2: serial at 4002c000 {
+ compatible = "atmel,same70-usart";
+ reg = <0x4002c000 0x4000>;
+ interrupts = <15>;
+ clocks = <&usart2_clk>;
+ clock-names = "usart";
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(11))>,
+ <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(12))>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart2>;
+ status = "disabled";
+ };
+
+ uart0: serial at 400e0800 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0x400e0800 0x140>;
+ interrupts = <7>;
+ clocks = <&uart0_clk>;
+ clock-names = "usart";
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(20))>,
+ <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(21))>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ uart1: serial at 400e0a00 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0x400e0a00 0x200>;
+ interrupts = <8>;
+ clocks = <&uart1_clk>;
+ clock-names = "usart";
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(22))>,
+ <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(23))>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ uart2: serial at 400e1a00 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0x400e1a00 0x200>;
+ interrupts = <44>;
+ clocks = <&uart2_clk>;
+ clock-names = "usart";
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(24))>,
+ <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(25))>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ uart3: serial at 400e1c00 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0x400e1c00 0x200>;
+ interrupts = <45>;
+ clocks = <&uart3_clk>;
+ clock-names = "usart";
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(26))>,
+ <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(27))>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ uart4: serial at 400e1e00 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0x400e1e00 0x200>;
+ interrupts = <46>;
+ clocks = <&uart4_clk>;
+ clock-names = "usart";
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ dmas = <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(28))>,
+ <&dma
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(29))>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+ };
+};
--
2.9.3
^ permalink raw reply related
* [PATCH v2 4/6] ARM: at91: handle CONFIG_PM for armv7m configurations
From: Alexandre Belloni @ 2016-10-20 9:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161020094135.18221-1-alexandre.belloni@free-electrons.com>
There is currently no PM support for samx7 but the symbol can still be
selected. This avoids compilation issues.
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
arch/arm/mach-at91/Kconfig | 6 ++++++
arch/arm/mach-at91/Makefile | 3 +--
arch/arm/mach-at91/samx7.c | 9 +++++++++
3 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index bade64e0cb49..34fa561aa853 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -59,6 +59,7 @@ config SOC_AT91RM9200
bool "AT91RM9200"
depends on ARCH_MULTI_V4T
select ATMEL_AIC_IRQ
+ select ATMEL_PM if PM
select ATMEL_ST
select CPU_ARM920T
select HAVE_AT91_USB_CLK
@@ -72,6 +73,7 @@ config SOC_AT91SAM9
bool "AT91SAM9"
depends on ARCH_MULTI_V5
select ATMEL_AIC_IRQ
+ select ATMEL_PM if PM
select ATMEL_SDRAMC
select CPU_ARM926T
select HAVE_AT91_SMD
@@ -130,9 +132,13 @@ config SOC_SAM_V7
config SOC_SAMA5
bool
select ATMEL_AIC5_IRQ
+ select ATMEL_PM if PM
select ATMEL_SDRAMC
select MEMORY
select SOC_SAM_V7
select SRAM if PM
+config ATMEL_PM
+ bool
+
endif
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 84956a18d604..116691714bb8 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -10,8 +10,7 @@ obj-$(CONFIG_SOC_SAMA5) += sama5.o
obj-$(CONFIG_SOC_SAMX7) += samx7.o
# Power Management
-obj-$(CONFIG_PM) += pm.o
-obj-$(CONFIG_PM) += pm_suspend.o
+obj-$(CONFIG_ATMEL_PM) += pm.o pm_suspend.o
ifeq ($(CONFIG_CPU_V7),y)
AFLAGS_pm_suspend.o := -march=armv7-a
diff --git a/arch/arm/mach-at91/samx7.c b/arch/arm/mach-at91/samx7.c
index bd33bc56278e..5bd76cb5076c 100644
--- a/arch/arm/mach-at91/samx7.c
+++ b/arch/arm/mach-at91/samx7.c
@@ -16,6 +16,15 @@
#include "generic.h"
#include "soc.h"
+#ifdef CONFIG_PM
+/* This function has to be defined for various drivers that are using it */
+int at91_suspend_entering_slow_clock(void)
+{
+ return 0;
+}
+EXPORT_SYMBOL(at91_suspend_entering_slow_clock);
+#endif
+
static const struct at91_soc samx7_socs[] = {
AT91_SOC(SAME70Q21_CIDR_MATCH, SAME70Q21_EXID_MATCH,
"same70q21", "samx7"),
--
2.9.3
^ permalink raw reply related
* [PATCH v2 3/6] ARM: at91: Add armv7m support
From: Alexandre Belloni @ 2016-10-20 9:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161020094135.18221-1-alexandre.belloni@free-electrons.com>
From: Szemz? Andr?s <sza@esh.hu>
Add Atmel SAME70/SAMS70/SAMV71 SoC support and detection.
Signed-off-by: Szemz? Andr?s <sza@esh.hu>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
arch/arm/mach-at91/Kconfig | 9 +++++-
arch/arm/mach-at91/Makefile | 1 +
arch/arm/mach-at91/Makefile.boot | 3 ++
arch/arm/mach-at91/samx7.c | 62 ++++++++++++++++++++++++++++++++++++++++
arch/arm/mach-at91/soc.h | 21 ++++++++++++++
5 files changed, 95 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/mach-at91/Makefile.boot
create mode 100644 arch/arm/mach-at91/samx7.c
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 841e924143f9..bade64e0cb49 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -1,12 +1,19 @@
menuconfig ARCH_AT91
bool "Atmel SoCs"
- depends on ARCH_MULTI_V4T || ARCH_MULTI_V5 || ARCH_MULTI_V7
+ depends on ARCH_MULTI_V4T || ARCH_MULTI_V5 || ARCH_MULTI_V7 || ARM_SINGLE_ARMV7M
select COMMON_CLK_AT91
select GPIOLIB
select PINCTRL
select SOC_BUS
if ARCH_AT91
+config SOC_SAMX7
+ bool "SAM Cortex-M7 family" if ARM_SINGLE_ARMV7M
+ select COMMON_CLK_AT91
+ select PINCTRL_AT91
+ help
+ Select this if you are using one of Atmel's SAMx7 family SoC.
+
config SOC_SAMA5D2
bool "SAMA5D2 family"
depends on ARCH_MULTI_V7
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index c5bbf8bb8c0f..84956a18d604 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -7,6 +7,7 @@ obj-y := soc.o
obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o
obj-$(CONFIG_SOC_AT91SAM9) += at91sam9.o
obj-$(CONFIG_SOC_SAMA5) += sama5.o
+obj-$(CONFIG_SOC_SAMX7) += samx7.o
# Power Management
obj-$(CONFIG_PM) += pm.o
diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
new file mode 100644
index 000000000000..eacfc3f5c33e
--- /dev/null
+++ b/arch/arm/mach-at91/Makefile.boot
@@ -0,0 +1,3 @@
+# Empty file waiting for deletion once Makefile.boot isn't needed any more.
+# Patch waits for application at
+# http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7889/1 .
diff --git a/arch/arm/mach-at91/samx7.c b/arch/arm/mach-at91/samx7.c
new file mode 100644
index 000000000000..bd33bc56278e
--- /dev/null
+++ b/arch/arm/mach-at91/samx7.c
@@ -0,0 +1,62 @@
+/*
+ * Setup code for SAMx7
+ *
+ * Copyright (C) 2013 Atmel,
+ * 2016 Andras Szemzo <szemzo.andras@gmail.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/system_misc.h>
+#include "generic.h"
+#include "soc.h"
+
+static const struct at91_soc samx7_socs[] = {
+ AT91_SOC(SAME70Q21_CIDR_MATCH, SAME70Q21_EXID_MATCH,
+ "same70q21", "samx7"),
+ AT91_SOC(SAME70Q20_CIDR_MATCH, SAME70Q20_EXID_MATCH,
+ "same70q20", "samx7"),
+ AT91_SOC(SAME70Q19_CIDR_MATCH, SAME70Q19_EXID_MATCH,
+ "same70q19", "samx7"),
+ AT91_SOC(SAMS70Q21_CIDR_MATCH, SAMS70Q21_EXID_MATCH,
+ "sams70q21", "samx7"),
+ AT91_SOC(SAMS70Q20_CIDR_MATCH, SAMS70Q20_EXID_MATCH,
+ "sams70q20", "samx7"),
+ AT91_SOC(SAMS70Q19_CIDR_MATCH, SAMS70Q19_EXID_MATCH,
+ "sams70q19", "samx7"),
+ AT91_SOC(SAMV71Q21_CIDR_MATCH, SAMV71Q21_EXID_MATCH,
+ "samv71q21", "samx7"),
+ AT91_SOC(SAMV71Q20_CIDR_MATCH, SAMV71Q20_EXID_MATCH,
+ "samv71q20", "samx7"),
+ AT91_SOC(SAMV71Q19_CIDR_MATCH, SAMV71Q19_EXID_MATCH,
+ "samv71q19", "samx7"),
+ { /* sentinel */ },
+};
+
+static void __init samx7_dt_device_init(void)
+{
+ struct soc_device *soc;
+ struct device *soc_dev = NULL;
+
+ soc = at91_soc_init(samx7_socs);
+ if (soc)
+ soc_dev = soc_device_to_device(soc);
+
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, soc_dev);
+}
+
+static const char *const samx7_dt_board_compat[] __initconst = {
+ "atmel,samx7",
+ NULL
+};
+
+DT_MACHINE_START(samx7_dt, "Atmel SAMx7")
+ .init_machine = samx7_dt_device_init,
+ .dt_compat = samx7_dt_board_compat,
+MACHINE_END
+
diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
index 228efded5085..0f97e9c5da7e 100644
--- a/arch/arm/mach-at91/soc.h
+++ b/arch/arm/mach-at91/soc.h
@@ -88,4 +88,25 @@ at91_soc_init(const struct at91_soc *socs);
#define SAMA5D43_EXID_MATCH 0x00000003
#define SAMA5D44_EXID_MATCH 0x00000004
+#define SAME70Q21_CIDR_MATCH 0x21020e00
+#define SAME70Q21_EXID_MATCH 0x00000002
+#define SAME70Q20_CIDR_MATCH 0x21020c00
+#define SAME70Q20_EXID_MATCH 0x00000002
+#define SAME70Q19_CIDR_MATCH 0x210d0a00
+#define SAME70Q19_EXID_MATCH 0x00000002
+
+#define SAMS70Q21_CIDR_MATCH 0x21120e00
+#define SAMS70Q21_EXID_MATCH 0x00000002
+#define SAMS70Q20_CIDR_MATCH 0x21120c00
+#define SAMS70Q20_EXID_MATCH 0x00000002
+#define SAMS70Q19_CIDR_MATCH 0x211d0a00
+#define SAMS70Q19_EXID_MATCH 0x00000002
+
+#define SAMV71Q21_CIDR_MATCH 0x21220e00
+#define SAMV71Q21_EXID_MATCH 0x00000002
+#define SAMV71Q20_CIDR_MATCH 0x21220c00
+#define SAMV71Q20_EXID_MATCH 0x00000002
+#define SAMV71Q19_CIDR_MATCH 0x212d0a00
+#define SAMV71Q19_EXID_MATCH 0x00000002
+
#endif /* __AT91_SOC_H */
--
2.9.3
^ permalink raw reply related
* [PATCH v2 2/6] ARM: at91: Document samx7 compatibles
From: Alexandre Belloni @ 2016-10-20 9:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161020094135.18221-1-alexandre.belloni@free-electrons.com>
Introduce necessary compatibles to describe the samx7 family
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
.../devicetree/bindings/arm/atmel-at91.txt | 30 ++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt
index e1f5ad855f14..baf9607c5f14 100644
--- a/Documentation/devicetree/bindings/arm/atmel-at91.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt
@@ -41,6 +41,36 @@ compatible: must be one of:
- "atmel,sama5d43"
- "atmel,sama5d44"
+ * "atmel,samx7" for MCUs using a Cortex-M7, shall be extended with the specific
+ SoC family:
+ o "atmel,sams70" shall be extended with the specific MCU compatible:
+ - "atmel,sams70j19"
+ - "atmel,sams70j20"
+ - "atmel,sams70j21"
+ - "atmel,sams70n19"
+ - "atmel,sams70n20"
+ - "atmel,sams70n21"
+ - "atmel,sams70q19"
+ - "atmel,sams70q20"
+ - "atmel,sams70q21"
+ o "atmel,samv70" shall be extended with the specific MCU compatible:
+ - "atmel,samv70j19"
+ - "atmel,samv70j20"
+ - "atmel,samv70n19"
+ - "atmel,samv70n20"
+ - "atmel,samv70q19"
+ - "atmel,samv70q20"
+ o "atmel,samv71" shall be extended with the specific MCU compatible:
+ - "atmel,samv71j19"
+ - "atmel,samv71j20"
+ - "atmel,samv71j21"
+ - "atmel,samv71n19"
+ - "atmel,samv71n20"
+ - "atmel,samv71n21"
+ - "atmel,samv71q19"
+ - "atmel,samv71q20"
+ - "atmel,samv71q21"
+
Chipid required properties:
- compatible: Should be "atmel,sama5d2-chipid"
- reg : Should contain registers location and length
--
2.9.3
^ permalink raw reply related
* [PATCH v2 1/6] ARM: at91: Documentation: add samx7 families
From: Alexandre Belloni @ 2016-10-20 9:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161020094135.18221-1-alexandre.belloni@free-electrons.com>
The Atmel sams70, samv70 and samv71 are Cortex-M7 based MCUs that can run
Linux (without MMU).
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
Documentation/arm/Atmel/README | 44 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 41 insertions(+), 3 deletions(-)
diff --git a/Documentation/arm/Atmel/README b/Documentation/arm/Atmel/README
index 6ca78f818dbf..e403697ee9fc 100644
--- a/Documentation/arm/Atmel/README
+++ b/Documentation/arm/Atmel/README
@@ -14,9 +14,9 @@ official Atmel product name. Anyway, files, directories, git trees,
git branches/tags and email subject always contain this "at91" sub-string.
-AT91 SoCs
----------
-Documentation and detailled datasheet for each product are available on
+SMART SoCs
+----------
+Documentation and detailed datasheet for each product are available on
the Atmel website: http://www.atmel.com.
Flavors:
@@ -101,6 +101,44 @@ the Atmel website: http://www.atmel.com.
+ Datasheet
http://www.atmel.com/Images/Atmel-11267-32-bit-Cortex-A5-Microcontroller-SAMA5D2_Datasheet.pdf
+SMART MCUs
+----------
+ * ARM Cortex-M7 MCUs
+ - sams70 family
+ - sams70j19
+ - sams70j20
+ - sams70j21
+ - sams70n19
+ - sams70n20
+ - sams70n21
+ - sams70q19
+ - sams70q20
+ - sams70q21
+ + Datasheet
+ http://www.atmel.com/Images/Atmel-11242-32-bit-Cortex-M7-Microcontroller-SAM-S70Q-SAM-S70N-SAM-S70J_Datasheet.pdf
+
+ - samv70 family
+ - samv70j19
+ - samv70j20
+ - samv70n19
+ - samv70n20
+ - samv70q19
+ - samv70q20
+ + Datasheet
+ http://www.atmel.com/Images/Atmel-11297-32-bit-Cortex-M7-Microcontroller-SAM-V70Q-SAM-V70N-SAM-V70J_Datasheet.pdf
+
+ - samv71 family
+ - samv71j19
+ - samv71j20
+ - samv71j21
+ - samv71n19
+ - samv71n20
+ - samv71n21
+ - samv71q19
+ - samv71q20
+ - samv71q21
+ + Datasheet
+ http://www.atmel.com/Images/Atmel-44003-32-bit-Cortex-M7-Microcontroller-SAM-V71Q-SAM-V71N-SAM-V71J_Datasheet.pdf
Linux kernel information
------------------------
--
2.9.3
^ permalink raw reply related
* [PATCH v2 0/6] ARM: at91: initial samx7 support
From: Alexandre Belloni @ 2016-10-20 9:41 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This series adds initial support for Atmel armv7m SoCs.
Changes in v2:
- fixed checkpatch issues
- Added documentation
- removed Ethernet from the dtsi until the driver change is taken
Alexandre Belloni (3):
ARM: at91: Documentation: add samx7 families
ARM: at91: Document samx7 compatibles
ARM: at91: handle CONFIG_PM for armv7m configurations
Szemz? Andr?s (3):
ARM: at91: Add armv7m support
ARM: dts: at91: add samx7 dtsi
ARM: at91: debug: add samx7 support
Documentation/arm/Atmel/README | 44 +-
.../devicetree/bindings/arm/atmel-at91.txt | 30 +
arch/arm/Kconfig.debug | 10 +
arch/arm/boot/dts/samx7.dtsi | 1128 ++++++++++++++++++++
arch/arm/mach-at91/Kconfig | 15 +-
arch/arm/mach-at91/Makefile | 4 +-
arch/arm/mach-at91/Makefile.boot | 3 +
arch/arm/mach-at91/samx7.c | 71 ++
arch/arm/mach-at91/soc.h | 21 +
9 files changed, 1320 insertions(+), 6 deletions(-)
create mode 100644 arch/arm/boot/dts/samx7.dtsi
create mode 100644 arch/arm/mach-at91/Makefile.boot
create mode 100644 arch/arm/mach-at91/samx7.c
--
2.9.3
^ permalink raw reply
* [PATCH v2] modversions: treat symbol CRCs as 32 bit quantities on 64 bit archs
From: Ard Biesheuvel @ 2016-10-20 9:37 UTC (permalink / raw)
To: linux-arm-kernel
The symbol CRCs are emitted as ELF symbols, which allows us to easily
populate the kcrctab sections by relying on the linker to associate
each kcrctab slot with the correct value.
This has two downsides:
- given that the CRCs are treated as pointers, we waste 4 bytes for
each CRC on 64 bit architectures,
- on architectures that support runtime relocation, a relocation entry is
emitted for each CRC value, which may take up 24 bytes of __init space
(on ELF64 systems)
This comes down to a x8 overhead in [uncompressed] kernel size. In addition,
each relocation has to be reverted before the CRC value can be used.
Switching to explicit 32 bit values on 64 bit architectures fixes both
issues, since 32 bit values are not treated as relocatable quantities on
ELF64 systems, even if the value ultimately resolves to a linker supplied
value.
So redefine all CRC fields and variables as u32, and redefine the
__CRC_SYMBOL() macro for 64 bit builds to emit the CRC reference using
inline assembler (which is necessary since 64-bit C code cannot use
32-bit types to hold memory addresses, even if they are ultimately
resolved using values that do no exceed 0xffffffff).
Also remove the special handling for PPC64, this should no longer be
required.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
v2: drop the change to struct modversion_info: it affects the layout of the
__versions section, which is consumed by userland tools as well, so it is
effectively ABI
On an arm64 defconfig build with CONFIG_RELOCATABLE=y, this patch reduces
the CRC footprint by 24 KB for .rodata, and by 217 KB for .init
Before:
[ 9] __kcrctab PROGBITS ffff000008b992a8 00b292a8
0000000000009440 0000000000000000 A 0 0 8
[10] __kcrctab_gpl PROGBITS ffff000008ba26e8 00b326e8
0000000000008d40 0000000000000000 A 0 0 8
...
[22] .rela RELA ffff000008c96e20 00c26e20
00000000001cc758 0000000000000018 A 0 0 8
After:
[ 9] __kcrctab PROGBITS ffff000008b728a8 00b028a8
0000000000004a20 0000000000000000 A 0 0 1
[10] __kcrctab_gpl PROGBITS ffff000008b772c8 00b072c8
00000000000046a0 0000000000000000 A 0 0 1
...
[22] .rela RELA ffff000008c66e20 00bf6e20
00000000001962d8 0000000000000018 A 0 0 8
arch/powerpc/include/asm/module.h | 4 --
arch/powerpc/kernel/module_64.c | 8 ----
include/linux/export.h | 8 ++++
include/linux/module.h | 14 +++----
kernel/module.c | 39 +++++++-------------
5 files changed, 29 insertions(+), 44 deletions(-)
diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h
index cd4ffd86765f..94a7f7aa3ae8 100644
--- a/arch/powerpc/include/asm/module.h
+++ b/arch/powerpc/include/asm/module.h
@@ -94,9 +94,5 @@ struct exception_table_entry;
void sort_ex_table(struct exception_table_entry *start,
struct exception_table_entry *finish);
-#if defined(CONFIG_MODVERSIONS) && defined(CONFIG_PPC64)
-#define ARCH_RELOCATES_KCRCTAB
-#define reloc_start PHYSICAL_START
-#endif
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_MODULE_H */
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
index 183368e008cf..be9b2d5ff846 100644
--- a/arch/powerpc/kernel/module_64.c
+++ b/arch/powerpc/kernel/module_64.c
@@ -286,14 +286,6 @@ static void dedotify_versions(struct modversion_info *vers,
for (end = (void *)vers + size; vers < end; vers++)
if (vers->name[0] == '.') {
memmove(vers->name, vers->name+1, strlen(vers->name));
-#ifdef ARCH_RELOCATES_KCRCTAB
- /* The TOC symbol has no CRC computed. To avoid CRC
- * check failing, we must force it to the expected
- * value (see CRC check in module.c).
- */
- if (!strcmp(vers->name, "TOC."))
- vers->crc = -(unsigned long)reloc_start;
-#endif
}
}
diff --git a/include/linux/export.h b/include/linux/export.h
index 2a0f61fbc731..fa51ab2ad190 100644
--- a/include/linux/export.h
+++ b/include/linux/export.h
@@ -41,6 +41,7 @@ extern struct module __this_module;
#if defined(__KERNEL__) && !defined(__GENKSYMS__)
#ifdef CONFIG_MODVERSIONS
+#ifndef CONFIG_64BIT
/* Mark the CRC weak since genksyms apparently decides not to
* generate a checksums for some symbols */
#define __CRC_SYMBOL(sym, sec) \
@@ -50,6 +51,13 @@ extern struct module __this_module;
__attribute__((section("___kcrctab" sec "+" #sym), used)) \
= (unsigned long) &__crc_##sym;
#else
+#define __CRC_SYMBOL(sym, sec) \
+ asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \
+ " .weak " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \
+ " .word " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \
+ " .previous \n");
+#endif
+#else
#define __CRC_SYMBOL(sym, sec)
#endif
diff --git a/include/linux/module.h b/include/linux/module.h
index 0c3207d26ac0..e0067673f5e5 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -346,7 +346,7 @@ struct module {
/* Exported symbols */
const struct kernel_symbol *syms;
- const unsigned long *crcs;
+ const u32 *crcs;
unsigned int num_syms;
/* Kernel parameters. */
@@ -359,18 +359,18 @@ struct module {
/* GPL-only exported symbols. */
unsigned int num_gpl_syms;
const struct kernel_symbol *gpl_syms;
- const unsigned long *gpl_crcs;
+ const u32 *gpl_crcs;
#ifdef CONFIG_UNUSED_SYMBOLS
/* unused exported symbols. */
const struct kernel_symbol *unused_syms;
- const unsigned long *unused_crcs;
+ const u32 *unused_crcs;
unsigned int num_unused_syms;
/* GPL-only, unused exported symbols. */
unsigned int num_unused_gpl_syms;
const struct kernel_symbol *unused_gpl_syms;
- const unsigned long *unused_gpl_crcs;
+ const u32 *unused_gpl_crcs;
#endif
#ifdef CONFIG_MODULE_SIG
@@ -382,7 +382,7 @@ struct module {
/* symbols that will be GPL-only in the near future. */
const struct kernel_symbol *gpl_future_syms;
- const unsigned long *gpl_future_crcs;
+ const u32 *gpl_future_crcs;
unsigned int num_gpl_future_syms;
/* Exception table */
@@ -523,7 +523,7 @@ struct module *find_module(const char *name);
struct symsearch {
const struct kernel_symbol *start, *stop;
- const unsigned long *crcs;
+ const u32 *crcs;
enum {
NOT_GPL_ONLY,
GPL_ONLY,
@@ -539,7 +539,7 @@ struct symsearch {
*/
const struct kernel_symbol *find_symbol(const char *name,
struct module **owner,
- const unsigned long **crc,
+ const u32 **crc,
bool gplok,
bool warn);
diff --git a/kernel/module.c b/kernel/module.c
index f57dd63186e6..90ecdad07e1a 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -386,16 +386,16 @@ extern const struct kernel_symbol __start___ksymtab_gpl[];
extern const struct kernel_symbol __stop___ksymtab_gpl[];
extern const struct kernel_symbol __start___ksymtab_gpl_future[];
extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
-extern const unsigned long __start___kcrctab[];
-extern const unsigned long __start___kcrctab_gpl[];
-extern const unsigned long __start___kcrctab_gpl_future[];
+extern const u32 __start___kcrctab[];
+extern const u32 __start___kcrctab_gpl[];
+extern const u32 __start___kcrctab_gpl_future[];
#ifdef CONFIG_UNUSED_SYMBOLS
extern const struct kernel_symbol __start___ksymtab_unused[];
extern const struct kernel_symbol __stop___ksymtab_unused[];
extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
-extern const unsigned long __start___kcrctab_unused[];
-extern const unsigned long __start___kcrctab_unused_gpl[];
+extern const u32 __start___kcrctab_unused[];
+extern const u32 __start___kcrctab_unused_gpl[];
#endif
#ifndef CONFIG_MODVERSIONS
@@ -494,7 +494,7 @@ struct find_symbol_arg {
/* Output */
struct module *owner;
- const unsigned long *crc;
+ const u32 *crc;
const struct kernel_symbol *sym;
};
@@ -560,7 +560,7 @@ static bool find_symbol_in_section(const struct symsearch *syms,
* (optional) module which owns it. Needs preempt disabled or module_mutex. */
const struct kernel_symbol *find_symbol(const char *name,
struct module **owner,
- const unsigned long **crc,
+ const u32 **crc,
bool gplok,
bool warn)
{
@@ -1257,22 +1257,11 @@ static int try_to_force_load(struct module *mod, const char *reason)
}
#ifdef CONFIG_MODVERSIONS
-/* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */
-static unsigned long maybe_relocated(unsigned long crc,
- const struct module *crc_owner)
-{
-#ifdef ARCH_RELOCATES_KCRCTAB
- if (crc_owner == NULL)
- return crc - (unsigned long)reloc_start;
-#endif
- return crc;
-}
-
static int check_version(Elf_Shdr *sechdrs,
unsigned int versindex,
const char *symname,
struct module *mod,
- const unsigned long *crc,
+ const u32 *crc,
const struct module *crc_owner)
{
unsigned int i, num_versions;
@@ -1294,10 +1283,10 @@ static int check_version(Elf_Shdr *sechdrs,
if (strcmp(versions[i].name, symname) != 0)
continue;
- if (versions[i].crc == maybe_relocated(*crc, crc_owner))
+ if (versions[i].crc == *crc)
return 1;
- pr_debug("Found checksum %lX vs module %lX\n",
- maybe_relocated(*crc, crc_owner), versions[i].crc);
+ pr_debug("Found checksum %X vs module %lX\n",
+ *crc, versions[i].crc);
goto bad_version;
}
@@ -1314,7 +1303,7 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
unsigned int versindex,
struct module *mod)
{
- const unsigned long *crc;
+ const u32 *crc;
/*
* Since this should be found in kernel (which can't be removed), no
@@ -1347,7 +1336,7 @@ static inline int check_version(Elf_Shdr *sechdrs,
unsigned int versindex,
const char *symname,
struct module *mod,
- const unsigned long *crc,
+ const u32 *crc,
const struct module *crc_owner)
{
return 1;
@@ -1375,7 +1364,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
{
struct module *owner;
const struct kernel_symbol *sym;
- const unsigned long *crc;
+ const u32 *crc;
int err;
/*
--
2.7.4
^ permalink raw reply related
* [PATCH v3 5/5] arm64: perf: Cavium ThunderX OCX TLK uncore support
From: Jan Glauber @ 2016-10-20 9:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476955841-27898-1-git-send-email-jglauber@cavium.com>
Support for the OCX transmit link counters.
Signed-off-by: Jan Glauber <jglauber@cavium.com>
---
drivers/perf/uncore/Makefile | 3 +-
drivers/perf/uncore/uncore_cavium.c | 1 +
drivers/perf/uncore/uncore_cavium.h | 1 +
drivers/perf/uncore/uncore_cavium_ocx_tlk.c | 344 ++++++++++++++++++++++++++++
4 files changed, 348 insertions(+), 1 deletion(-)
create mode 100644 drivers/perf/uncore/uncore_cavium_ocx_tlk.c
diff --git a/drivers/perf/uncore/Makefile b/drivers/perf/uncore/Makefile
index ef04a2b9..7e2e8e5 100644
--- a/drivers/perf/uncore/Makefile
+++ b/drivers/perf/uncore/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_UNCORE_PMU_CAVIUM) += uncore_cavium.o \
uncore_cavium_l2c_tad.o \
uncore_cavium_l2c_cbc.o \
- uncore_cavium_lmc.o
+ uncore_cavium_lmc.o \
+ uncore_cavium_ocx_tlk.o
diff --git a/drivers/perf/uncore/uncore_cavium.c b/drivers/perf/uncore/uncore_cavium.c
index fd9e49e..46ced45 100644
--- a/drivers/perf/uncore/uncore_cavium.c
+++ b/drivers/perf/uncore/uncore_cavium.c
@@ -349,6 +349,7 @@ static int __init thunder_uncore_init(void)
thunder_uncore_l2c_tad_setup();
thunder_uncore_l2c_cbc_setup();
thunder_uncore_lmc_setup();
+ thunder_uncore_ocx_tlk_setup();
return 0;
}
late_initcall(thunder_uncore_init);
diff --git a/drivers/perf/uncore/uncore_cavium.h b/drivers/perf/uncore/uncore_cavium.h
index 3897586..43ab426 100644
--- a/drivers/perf/uncore/uncore_cavium.h
+++ b/drivers/perf/uncore/uncore_cavium.h
@@ -72,3 +72,4 @@ ssize_t thunder_events_sysfs_show(struct device *dev,
int thunder_uncore_l2c_tad_setup(void);
int thunder_uncore_l2c_cbc_setup(void);
int thunder_uncore_lmc_setup(void);
+int thunder_uncore_ocx_tlk_setup(void);
diff --git a/drivers/perf/uncore/uncore_cavium_ocx_tlk.c b/drivers/perf/uncore/uncore_cavium_ocx_tlk.c
new file mode 100644
index 0000000..b50cd67
--- /dev/null
+++ b/drivers/perf/uncore/uncore_cavium_ocx_tlk.c
@@ -0,0 +1,344 @@
+/*
+ * Cavium Thunder uncore PMU support,
+ * CCPI interface controller (OCX) Transmit link (TLK) counters.
+ *
+ * Copyright 2016 Cavium Inc.
+ * Author: Jan Glauber <jan.glauber@cavium.com>
+ */
+
+#include <linux/perf_event.h>
+#include <linux/slab.h>
+
+#include "uncore_cavium.h"
+
+struct thunder_uncore *thunder_uncore_ocx_tlk;
+
+#define OCX_TLK_NR_UNITS 3
+#define OCX_TLK_UNIT_OFFSET 0x2000
+#define OCX_TLK_STAT_CTL 0x10040
+#define OCX_TLK_STAT_OFFSET 0x10400
+
+#define OCX_TLK_STAT_ENABLE_BIT BIT_ULL(0)
+#define OCX_TLK_STAT_RESET_BIT BIT_ULL(1)
+
+/* OCX TLK event list */
+#define OCX_TLK_EVENT_STAT_IDLE_CNT 0x00
+#define OCX_TLK_EVENT_STAT_DATA_CNT 0x08
+#define OCX_TLK_EVENT_STAT_SYNC_CNT 0x10
+#define OCX_TLK_EVENT_STAT_RETRY_CNT 0x18
+#define OCX_TLK_EVENT_STAT_ERR_CNT 0x20
+#define OCX_TLK_EVENT_STAT_MAT0_CNT 0x40
+#define OCX_TLK_EVENT_STAT_MAT1_CNT 0x48
+#define OCX_TLK_EVENT_STAT_MAT2_CNT 0x50
+#define OCX_TLK_EVENT_STAT_MAT3_CNT 0x58
+#define OCX_TLK_EVENT_STAT_VC0_CMD 0x80
+#define OCX_TLK_EVENT_STAT_VC1_CMD 0x88
+#define OCX_TLK_EVENT_STAT_VC2_CMD 0x90
+#define OCX_TLK_EVENT_STAT_VC3_CMD 0x98
+#define OCX_TLK_EVENT_STAT_VC4_CMD 0xa0
+#define OCX_TLK_EVENT_STAT_VC5_CMD 0xa8
+#define OCX_TLK_EVENT_STAT_VC0_PKT 0x100
+#define OCX_TLK_EVENT_STAT_VC1_PKT 0x108
+#define OCX_TLK_EVENT_STAT_VC2_PKT 0x110
+#define OCX_TLK_EVENT_STAT_VC3_PKT 0x118
+#define OCX_TLK_EVENT_STAT_VC4_PKT 0x120
+#define OCX_TLK_EVENT_STAT_VC5_PKT 0x128
+#define OCX_TLK_EVENT_STAT_VC6_PKT 0x130
+#define OCX_TLK_EVENT_STAT_VC7_PKT 0x138
+#define OCX_TLK_EVENT_STAT_VC8_PKT 0x140
+#define OCX_TLK_EVENT_STAT_VC9_PKT 0x148
+#define OCX_TLK_EVENT_STAT_VC10_PKT 0x150
+#define OCX_TLK_EVENT_STAT_VC11_PKT 0x158
+#define OCX_TLK_EVENT_STAT_VC12_PKT 0x160
+#define OCX_TLK_EVENT_STAT_VC13_PKT 0x168
+#define OCX_TLK_EVENT_STAT_VC0_CON 0x180
+#define OCX_TLK_EVENT_STAT_VC1_CON 0x188
+#define OCX_TLK_EVENT_STAT_VC2_CON 0x190
+#define OCX_TLK_EVENT_STAT_VC3_CON 0x198
+#define OCX_TLK_EVENT_STAT_VC4_CON 0x1a0
+#define OCX_TLK_EVENT_STAT_VC5_CON 0x1a8
+#define OCX_TLK_EVENT_STAT_VC6_CON 0x1b0
+#define OCX_TLK_EVENT_STAT_VC7_CON 0x1b8
+#define OCX_TLK_EVENT_STAT_VC8_CON 0x1c0
+#define OCX_TLK_EVENT_STAT_VC9_CON 0x1c8
+#define OCX_TLK_EVENT_STAT_VC10_CON 0x1d0
+#define OCX_TLK_EVENT_STAT_VC11_CON 0x1d8
+#define OCX_TLK_EVENT_STAT_VC12_CON 0x1e0
+#define OCX_TLK_EVENT_STAT_VC13_CON 0x1e8
+
+static int ocx_tlk_events[] = {
+ OCX_TLK_EVENT_STAT_IDLE_CNT,
+ OCX_TLK_EVENT_STAT_DATA_CNT,
+ OCX_TLK_EVENT_STAT_SYNC_CNT,
+ OCX_TLK_EVENT_STAT_RETRY_CNT,
+ OCX_TLK_EVENT_STAT_ERR_CNT,
+ OCX_TLK_EVENT_STAT_MAT0_CNT,
+ OCX_TLK_EVENT_STAT_MAT1_CNT,
+ OCX_TLK_EVENT_STAT_MAT2_CNT,
+ OCX_TLK_EVENT_STAT_MAT3_CNT,
+ OCX_TLK_EVENT_STAT_VC0_CMD,
+ OCX_TLK_EVENT_STAT_VC1_CMD,
+ OCX_TLK_EVENT_STAT_VC2_CMD,
+ OCX_TLK_EVENT_STAT_VC3_CMD,
+ OCX_TLK_EVENT_STAT_VC4_CMD,
+ OCX_TLK_EVENT_STAT_VC5_CMD,
+ OCX_TLK_EVENT_STAT_VC0_PKT,
+ OCX_TLK_EVENT_STAT_VC1_PKT,
+ OCX_TLK_EVENT_STAT_VC2_PKT,
+ OCX_TLK_EVENT_STAT_VC3_PKT,
+ OCX_TLK_EVENT_STAT_VC4_PKT,
+ OCX_TLK_EVENT_STAT_VC5_PKT,
+ OCX_TLK_EVENT_STAT_VC6_PKT,
+ OCX_TLK_EVENT_STAT_VC7_PKT,
+ OCX_TLK_EVENT_STAT_VC8_PKT,
+ OCX_TLK_EVENT_STAT_VC9_PKT,
+ OCX_TLK_EVENT_STAT_VC10_PKT,
+ OCX_TLK_EVENT_STAT_VC11_PKT,
+ OCX_TLK_EVENT_STAT_VC12_PKT,
+ OCX_TLK_EVENT_STAT_VC13_PKT,
+ OCX_TLK_EVENT_STAT_VC0_CON,
+ OCX_TLK_EVENT_STAT_VC1_CON,
+ OCX_TLK_EVENT_STAT_VC2_CON,
+ OCX_TLK_EVENT_STAT_VC3_CON,
+ OCX_TLK_EVENT_STAT_VC4_CON,
+ OCX_TLK_EVENT_STAT_VC5_CON,
+ OCX_TLK_EVENT_STAT_VC6_CON,
+ OCX_TLK_EVENT_STAT_VC7_CON,
+ OCX_TLK_EVENT_STAT_VC8_CON,
+ OCX_TLK_EVENT_STAT_VC9_CON,
+ OCX_TLK_EVENT_STAT_VC10_CON,
+ OCX_TLK_EVENT_STAT_VC11_CON,
+ OCX_TLK_EVENT_STAT_VC12_CON,
+ OCX_TLK_EVENT_STAT_VC13_CON,
+};
+
+/*
+ * The OCX devices have a single device per node, therefore picking the
+ * first device from the list is correct.
+ */
+static inline void __iomem *map_offset(struct thunder_uncore_node *node,
+ unsigned long addr, int offset, int nr)
+{
+ struct thunder_uncore_unit *unit;
+
+ unit = list_first_entry(&node->unit_list, struct thunder_uncore_unit,
+ entry);
+ return (void __iomem *)(addr + unit->map + nr * offset);
+}
+
+static void __iomem *map_offset_ocx_tlk(struct thunder_uncore_node *node,
+ unsigned long addr, int nr)
+{
+ return (void __iomem *)map_offset(node, addr, nr, OCX_TLK_UNIT_OFFSET);
+}
+
+/*
+ * The OCX TLK counters can only be enabled/disabled as a set so we do
+ * this in pmu_enable/disable instead of start/stop.
+ */
+static void thunder_uncore_pmu_enable_ocx_tlk(struct pmu *pmu)
+{
+ struct thunder_uncore *uncore =
+ container_of(pmu, struct thunder_uncore, pmu);
+ int node = 0, i;
+
+ while (uncore->nodes[node++]) {
+ for (i = 0; i < OCX_TLK_NR_UNITS; i++) {
+ /* reset all TLK counters to zero */
+ writeb(OCX_TLK_STAT_RESET_BIT,
+ map_offset_ocx_tlk(uncore->nodes[node],
+ OCX_TLK_STAT_CTL, i));
+ /* enable all TLK counters */
+ writeb(OCX_TLK_STAT_ENABLE_BIT,
+ map_offset_ocx_tlk(uncore->nodes[node],
+ OCX_TLK_STAT_CTL, i));
+ }
+ }
+}
+
+/*
+ * The OCX TLK counters can only be enabled/disabled as a set so we do
+ * this in pmu_enable/disable instead of start/stop.
+ */
+static void thunder_uncore_pmu_disable_ocx_tlk(struct pmu *pmu)
+{
+ struct thunder_uncore *uncore =
+ container_of(pmu, struct thunder_uncore, pmu);
+ int node = 0, i;
+
+ while (uncore->nodes[node++]) {
+ for (i = 0; i < OCX_TLK_NR_UNITS; i++) {
+ /* disable all TLK counters */
+ writeb(0, map_offset_ocx_tlk(uncore->nodes[node],
+ OCX_TLK_STAT_CTL, i));
+ }
+ }
+}
+
+/*
+ * Summarize counters across all TLK's. Different from the other uncore
+ * PMUs because all TLK's are on one PCI device.
+ */
+static void thunder_uncore_read_ocx_tlk(struct perf_event *event)
+{
+ struct thunder_uncore *uncore = to_uncore(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunder_uncore_node *node;
+ u64 new = 0;
+ int i;
+
+ /* read counter values from all units */
+ node = get_node(hwc->config, uncore);
+ for (i = 0; i < OCX_TLK_NR_UNITS; i++)
+ new += readq(map_offset_ocx_tlk(node, hwc->event_base, i));
+
+ local64_add(new, &hwc->prev_count);
+ local64_add(new, &event->count);
+}
+
+static void thunder_uncore_start_ocx_tlk(struct perf_event *event, int flags)
+{
+ struct thunder_uncore *uncore = to_uncore(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunder_uncore_node *node;
+ u64 new = 0;
+ int i;
+
+ /* read counter values from all units on the node */
+ node = get_node(hwc->config, uncore);
+ for (i = 0; i < OCX_TLK_NR_UNITS; i++)
+ new += readq(map_offset_ocx_tlk(node, hwc->event_base, i));
+ local64_set(&hwc->prev_count, new);
+
+ hwc->state = 0;
+ perf_event_update_userpage(event);
+}
+
+static int thunder_uncore_add_ocx_tlk(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ return thunder_uncore_add(event, flags,
+ OCX_TLK_STAT_CTL,
+ OCX_TLK_STAT_OFFSET + ocx_tlk_events[get_id(hwc->config)]);
+}
+
+PMU_FORMAT_ATTR(event, "config:0-5");
+
+static struct attribute *thunder_ocx_tlk_format_attr[] = {
+ &format_attr_event.attr,
+ &format_attr_node.attr,
+ NULL,
+};
+
+static struct attribute_group thunder_ocx_tlk_format_group = {
+ .name = "format",
+ .attrs = thunder_ocx_tlk_format_attr,
+};
+
+static struct attribute *thunder_ocx_tlk_events_attr[] = {
+ UC_EVENT_ENTRY(idle_cnt, 0),
+ UC_EVENT_ENTRY(data_cnt, 1),
+ UC_EVENT_ENTRY(sync_cnt, 2),
+ UC_EVENT_ENTRY(retry_cnt, 3),
+ UC_EVENT_ENTRY(err_cnt, 4),
+ UC_EVENT_ENTRY(mat0_cnt, 5),
+ UC_EVENT_ENTRY(mat1_cnt, 6),
+ UC_EVENT_ENTRY(mat2_cnt, 7),
+ UC_EVENT_ENTRY(mat3_cnt, 8),
+ UC_EVENT_ENTRY(vc0_cmd, 9),
+ UC_EVENT_ENTRY(vc1_cmd, 10),
+ UC_EVENT_ENTRY(vc2_cmd, 11),
+ UC_EVENT_ENTRY(vc3_cmd, 12),
+ UC_EVENT_ENTRY(vc4_cmd, 13),
+ UC_EVENT_ENTRY(vc5_cmd, 14),
+ UC_EVENT_ENTRY(vc0_pkt, 15),
+ UC_EVENT_ENTRY(vc1_pkt, 16),
+ UC_EVENT_ENTRY(vc2_pkt, 17),
+ UC_EVENT_ENTRY(vc3_pkt, 18),
+ UC_EVENT_ENTRY(vc4_pkt, 19),
+ UC_EVENT_ENTRY(vc5_pkt, 20),
+ UC_EVENT_ENTRY(vc6_pkt, 21),
+ UC_EVENT_ENTRY(vc7_pkt, 22),
+ UC_EVENT_ENTRY(vc8_pkt, 23),
+ UC_EVENT_ENTRY(vc9_pkt, 24),
+ UC_EVENT_ENTRY(vc10_pkt, 25),
+ UC_EVENT_ENTRY(vc11_pkt, 26),
+ UC_EVENT_ENTRY(vc12_pkt, 27),
+ UC_EVENT_ENTRY(vc13_pkt, 28),
+ UC_EVENT_ENTRY(vc0_con, 29),
+ UC_EVENT_ENTRY(vc1_con, 30),
+ UC_EVENT_ENTRY(vc2_con, 31),
+ UC_EVENT_ENTRY(vc3_con, 32),
+ UC_EVENT_ENTRY(vc4_con, 33),
+ UC_EVENT_ENTRY(vc5_con, 34),
+ UC_EVENT_ENTRY(vc6_con, 35),
+ UC_EVENT_ENTRY(vc7_con, 36),
+ UC_EVENT_ENTRY(vc8_con, 37),
+ UC_EVENT_ENTRY(vc9_con, 38),
+ UC_EVENT_ENTRY(vc10_con, 39),
+ UC_EVENT_ENTRY(vc11_con, 40),
+ UC_EVENT_ENTRY(vc12_con, 41),
+ UC_EVENT_ENTRY(vc13_con, 42),
+ NULL,
+};
+
+static struct attribute_group thunder_ocx_tlk_events_group = {
+ .name = "events",
+ .attrs = thunder_ocx_tlk_events_attr,
+};
+
+static const struct attribute_group *thunder_ocx_tlk_attr_groups[] = {
+ &thunder_uncore_attr_group,
+ &thunder_ocx_tlk_format_group,
+ &thunder_ocx_tlk_events_group,
+ NULL,
+};
+
+struct pmu thunder_ocx_tlk_pmu = {
+ .name = "thunder_ocx_tlk",
+ .task_ctx_nr = perf_sw_context,
+ .pmu_enable = thunder_uncore_pmu_enable_ocx_tlk,
+ .pmu_disable = thunder_uncore_pmu_disable_ocx_tlk,
+ .event_init = thunder_uncore_event_init,
+ .add = thunder_uncore_add_ocx_tlk,
+ .del = thunder_uncore_del,
+ .start = thunder_uncore_start_ocx_tlk,
+ .stop = thunder_uncore_stop,
+ .read = thunder_uncore_read_ocx_tlk,
+ .attr_groups = thunder_ocx_tlk_attr_groups,
+};
+
+static bool event_valid(u64 config)
+{
+ if (config < ARRAY_SIZE(ocx_tlk_events))
+ return true;
+
+ return false;
+}
+
+int __init thunder_uncore_ocx_tlk_setup(void)
+{
+ int ret;
+
+ thunder_uncore_ocx_tlk = kzalloc(sizeof(*thunder_uncore_ocx_tlk),
+ GFP_KERNEL);
+ if (!thunder_uncore_ocx_tlk) {
+ ret = -ENOMEM;
+ goto fail_nomem;
+ }
+
+ ret = thunder_uncore_setup(thunder_uncore_ocx_tlk, 0xa013,
+ &thunder_ocx_tlk_pmu,
+ ARRAY_SIZE(ocx_tlk_events));
+ if (ret)
+ goto fail;
+
+ thunder_uncore_ocx_tlk->event_valid = event_valid;
+ return 0;
+
+fail:
+ kfree(thunder_uncore_ocx_tlk);
+fail_nomem:
+ return ret;
+}
--
1.9.1
^ permalink raw reply related
* [PATCH v3 4/5] arm64: perf: Cavium ThunderX LMC uncore support
From: Jan Glauber @ 2016-10-20 9:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476955841-27898-1-git-send-email-jglauber@cavium.com>
Support counters on the DRAM controllers.
Signed-off-by: Jan Glauber <jglauber@cavium.com>
---
drivers/perf/uncore/Makefile | 3 +-
drivers/perf/uncore/uncore_cavium.c | 1 +
drivers/perf/uncore/uncore_cavium.h | 1 +
drivers/perf/uncore/uncore_cavium_lmc.c | 118 ++++++++++++++++++++++++++++++++
4 files changed, 122 insertions(+), 1 deletion(-)
create mode 100644 drivers/perf/uncore/uncore_cavium_lmc.c
diff --git a/drivers/perf/uncore/Makefile b/drivers/perf/uncore/Makefile
index d5ef3db..ef04a2b9 100644
--- a/drivers/perf/uncore/Makefile
+++ b/drivers/perf/uncore/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_UNCORE_PMU_CAVIUM) += uncore_cavium.o \
uncore_cavium_l2c_tad.o \
- uncore_cavium_l2c_cbc.o
+ uncore_cavium_l2c_cbc.o \
+ uncore_cavium_lmc.o
diff --git a/drivers/perf/uncore/uncore_cavium.c b/drivers/perf/uncore/uncore_cavium.c
index 051f0fa..fd9e49e 100644
--- a/drivers/perf/uncore/uncore_cavium.c
+++ b/drivers/perf/uncore/uncore_cavium.c
@@ -348,6 +348,7 @@ static int __init thunder_uncore_init(void)
thunder_uncore_l2c_tad_setup();
thunder_uncore_l2c_cbc_setup();
+ thunder_uncore_lmc_setup();
return 0;
}
late_initcall(thunder_uncore_init);
diff --git a/drivers/perf/uncore/uncore_cavium.h b/drivers/perf/uncore/uncore_cavium.h
index 91d674a..3897586 100644
--- a/drivers/perf/uncore/uncore_cavium.h
+++ b/drivers/perf/uncore/uncore_cavium.h
@@ -71,3 +71,4 @@ ssize_t thunder_events_sysfs_show(struct device *dev,
char *page);
int thunder_uncore_l2c_tad_setup(void);
int thunder_uncore_l2c_cbc_setup(void);
+int thunder_uncore_lmc_setup(void);
diff --git a/drivers/perf/uncore/uncore_cavium_lmc.c b/drivers/perf/uncore/uncore_cavium_lmc.c
new file mode 100644
index 0000000..c7df89b
--- /dev/null
+++ b/drivers/perf/uncore/uncore_cavium_lmc.c
@@ -0,0 +1,118 @@
+/*
+ * Cavium Thunder uncore PMU support, Local memory controller (LMC) counters.
+ *
+ * Copyright 2016 Cavium Inc.
+ * Author: Jan Glauber <jan.glauber@cavium.com>
+ */
+
+#include <linux/perf_event.h>
+#include <linux/slab.h>
+
+#include "uncore_cavium.h"
+
+struct thunder_uncore *thunder_uncore_lmc;
+
+#define LMC_CONFIG_OFFSET 0x188
+#define LMC_CONFIG_RESET_BIT BIT_ULL(17)
+
+/* LMC event list */
+#define LMC_EVENT_IFB_CNT 0x1d0
+#define LMC_EVENT_OPS_CNT 0x1d8
+#define LMC_EVENT_DCLK_CNT 0x1e0
+#define LMC_EVENT_BANK_CONFLICT1 0x360
+#define LMC_EVENT_BANK_CONFLICT2 0x368
+
+/* map counter numbers to register offsets */
+static int lmc_events[] = {
+ LMC_EVENT_IFB_CNT,
+ LMC_EVENT_OPS_CNT,
+ LMC_EVENT_DCLK_CNT,
+ LMC_EVENT_BANK_CONFLICT1,
+ LMC_EVENT_BANK_CONFLICT2,
+};
+
+static int thunder_uncore_add_lmc(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ return thunder_uncore_add(event, flags,
+ LMC_CONFIG_OFFSET,
+ lmc_events[get_id(hwc->config)]);
+}
+
+PMU_FORMAT_ATTR(event, "config:0-2");
+
+static struct attribute *thunder_lmc_format_attr[] = {
+ &format_attr_event.attr,
+ &format_attr_node.attr,
+ NULL,
+};
+
+static struct attribute_group thunder_lmc_format_group = {
+ .name = "format",
+ .attrs = thunder_lmc_format_attr,
+};
+
+static struct attribute *thunder_lmc_events_attr[] = {
+ UC_EVENT_ENTRY(ifb_cnt, 0),
+ UC_EVENT_ENTRY(ops_cnt, 1),
+ UC_EVENT_ENTRY(dclk_cnt, 2),
+ UC_EVENT_ENTRY(bank_conflict1, 3),
+ UC_EVENT_ENTRY(bank_conflict2, 4),
+ NULL,
+};
+
+static struct attribute_group thunder_lmc_events_group = {
+ .name = "events",
+ .attrs = thunder_lmc_events_attr,
+};
+
+static const struct attribute_group *thunder_lmc_attr_groups[] = {
+ &thunder_uncore_attr_group,
+ &thunder_lmc_format_group,
+ &thunder_lmc_events_group,
+ NULL,
+};
+
+struct pmu thunder_lmc_pmu = {
+ .name = "thunder_lmc",
+ .task_ctx_nr = perf_sw_context,
+ .event_init = thunder_uncore_event_init,
+ .add = thunder_uncore_add_lmc,
+ .del = thunder_uncore_del,
+ .start = thunder_uncore_start,
+ .stop = thunder_uncore_stop,
+ .read = thunder_uncore_read,
+ .attr_groups = thunder_lmc_attr_groups,
+};
+
+static bool event_valid(u64 config)
+{
+ if (config < ARRAY_SIZE(lmc_events))
+ return true;
+
+ return false;
+}
+
+int __init thunder_uncore_lmc_setup(void)
+{
+ int ret = -ENOMEM;
+
+ thunder_uncore_lmc = kzalloc(sizeof(*thunder_uncore_lmc), GFP_KERNEL);
+ if (!thunder_uncore_lmc)
+ goto fail_nomem;
+
+ ret = thunder_uncore_setup(thunder_uncore_lmc, 0xa022,
+ &thunder_lmc_pmu,
+ ARRAY_SIZE(lmc_events));
+ if (ret)
+ goto fail;
+
+ thunder_uncore_lmc->event_valid = event_valid;
+ return 0;
+
+fail:
+ kfree(thunder_uncore_lmc);
+fail_nomem:
+ return ret;
+}
--
1.9.1
^ permalink raw reply related
* [PATCH v3 3/5] arm64: perf: Cavium ThunderX L2C CBC uncore support
From: Jan Glauber @ 2016-10-20 9:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476955841-27898-1-git-send-email-jglauber@cavium.com>
Support counters of the L2 cache crossbar connect.
Signed-off-by: Jan Glauber <jglauber@cavium.com>
---
drivers/perf/uncore/Makefile | 3 +-
drivers/perf/uncore/uncore_cavium.c | 1 +
drivers/perf/uncore/uncore_cavium.h | 1 +
drivers/perf/uncore/uncore_cavium_l2c_cbc.c | 148 ++++++++++++++++++++++++++++
4 files changed, 152 insertions(+), 1 deletion(-)
create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_cbc.c
diff --git a/drivers/perf/uncore/Makefile b/drivers/perf/uncore/Makefile
index 90850a2..d5ef3db 100644
--- a/drivers/perf/uncore/Makefile
+++ b/drivers/perf/uncore/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_UNCORE_PMU_CAVIUM) += uncore_cavium.o \
- uncore_cavium_l2c_tad.o
+ uncore_cavium_l2c_tad.o \
+ uncore_cavium_l2c_cbc.o
diff --git a/drivers/perf/uncore/uncore_cavium.c b/drivers/perf/uncore/uncore_cavium.c
index 15e1aec..051f0fa 100644
--- a/drivers/perf/uncore/uncore_cavium.c
+++ b/drivers/perf/uncore/uncore_cavium.c
@@ -347,6 +347,7 @@ static int __init thunder_uncore_init(void)
return ret;
thunder_uncore_l2c_tad_setup();
+ thunder_uncore_l2c_cbc_setup();
return 0;
}
late_initcall(thunder_uncore_init);
diff --git a/drivers/perf/uncore/uncore_cavium.h b/drivers/perf/uncore/uncore_cavium.h
index 70a8214..91d674a 100644
--- a/drivers/perf/uncore/uncore_cavium.h
+++ b/drivers/perf/uncore/uncore_cavium.h
@@ -70,3 +70,4 @@ ssize_t thunder_events_sysfs_show(struct device *dev,
struct device_attribute *attr,
char *page);
int thunder_uncore_l2c_tad_setup(void);
+int thunder_uncore_l2c_cbc_setup(void);
diff --git a/drivers/perf/uncore/uncore_cavium_l2c_cbc.c b/drivers/perf/uncore/uncore_cavium_l2c_cbc.c
new file mode 100644
index 0000000..4d6c2c4
--- /dev/null
+++ b/drivers/perf/uncore/uncore_cavium_l2c_cbc.c
@@ -0,0 +1,148 @@
+/*
+ * Cavium Thunder uncore PMU support, L2 Cache,
+ * Crossbar connect (CBC) counters.
+ *
+ * Copyright 2016 Cavium Inc.
+ * Author: Jan Glauber <jan.glauber@cavium.com>
+ */
+
+#include <linux/perf_event.h>
+#include <linux/slab.h>
+
+#include "uncore_cavium.h"
+
+struct thunder_uncore *thunder_uncore_l2c_cbc;
+
+/* L2C CBC event list */
+#define L2C_CBC_EVENT_XMC0 0x00
+#define L2C_CBC_EVENT_XMD0 0x08
+#define L2C_CBC_EVENT_RSC0 0x10
+#define L2C_CBC_EVENT_RSD0 0x18
+#define L2C_CBC_EVENT_INV0 0x20
+#define L2C_CBC_EVENT_IOC0 0x28
+#define L2C_CBC_EVENT_IOR0 0x30
+#define L2C_CBC_EVENT_XMC1 0x40
+#define L2C_CBC_EVENT_XMD1 0x48
+#define L2C_CBC_EVENT_RSC1 0x50
+#define L2C_CBC_EVENT_RSD1 0x58
+#define L2C_CBC_EVENT_INV1 0x60
+#define L2C_CBC_EVENT_XMC2 0x80
+#define L2C_CBC_EVENT_XMD2 0x88
+#define L2C_CBC_EVENT_RSC2 0x90
+#define L2C_CBC_EVENT_RSD2 0x98
+
+static int l2c_cbc_events[] = {
+ L2C_CBC_EVENT_XMC0,
+ L2C_CBC_EVENT_XMD0,
+ L2C_CBC_EVENT_RSC0,
+ L2C_CBC_EVENT_RSD0,
+ L2C_CBC_EVENT_INV0,
+ L2C_CBC_EVENT_IOC0,
+ L2C_CBC_EVENT_IOR0,
+ L2C_CBC_EVENT_XMC1,
+ L2C_CBC_EVENT_XMD1,
+ L2C_CBC_EVENT_RSC1,
+ L2C_CBC_EVENT_RSD1,
+ L2C_CBC_EVENT_INV1,
+ L2C_CBC_EVENT_XMC2,
+ L2C_CBC_EVENT_XMD2,
+ L2C_CBC_EVENT_RSC2,
+ L2C_CBC_EVENT_RSD2,
+};
+
+static int thunder_uncore_add_l2c_cbc(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ return thunder_uncore_add(event, flags, 0,
+ l2c_cbc_events[get_id(hwc->config)]);
+}
+
+PMU_FORMAT_ATTR(event, "config:0-4");
+
+static struct attribute *thunder_l2c_cbc_format_attr[] = {
+ &format_attr_event.attr,
+ &format_attr_node.attr,
+ NULL,
+};
+
+static struct attribute_group thunder_l2c_cbc_format_group = {
+ .name = "format",
+ .attrs = thunder_l2c_cbc_format_attr,
+};
+
+static struct attribute *thunder_l2c_cbc_events_attr[] = {
+ UC_EVENT_ENTRY(xmc0, 0),
+ UC_EVENT_ENTRY(xmd0, 1),
+ UC_EVENT_ENTRY(rsc0, 2),
+ UC_EVENT_ENTRY(rsd0, 3),
+ UC_EVENT_ENTRY(inv0, 4),
+ UC_EVENT_ENTRY(ioc0, 5),
+ UC_EVENT_ENTRY(ior0, 6),
+ UC_EVENT_ENTRY(xmc1, 7),
+ UC_EVENT_ENTRY(xmd1, 8),
+ UC_EVENT_ENTRY(rsc1, 9),
+ UC_EVENT_ENTRY(rsd1, 10),
+ UC_EVENT_ENTRY(inv1, 11),
+ UC_EVENT_ENTRY(xmc2, 12),
+ UC_EVENT_ENTRY(xmd2, 13),
+ UC_EVENT_ENTRY(rsc2, 14),
+ UC_EVENT_ENTRY(rsd2, 15),
+ NULL,
+};
+
+static struct attribute_group thunder_l2c_cbc_events_group = {
+ .name = "events",
+ .attrs = thunder_l2c_cbc_events_attr,
+};
+
+static const struct attribute_group *thunder_l2c_cbc_attr_groups[] = {
+ &thunder_uncore_attr_group,
+ &thunder_l2c_cbc_format_group,
+ &thunder_l2c_cbc_events_group,
+ NULL,
+};
+
+struct pmu thunder_l2c_cbc_pmu = {
+ .name = "thunder_l2c_cbc",
+ .task_ctx_nr = perf_sw_context,
+ .event_init = thunder_uncore_event_init,
+ .add = thunder_uncore_add_l2c_cbc,
+ .del = thunder_uncore_del,
+ .start = thunder_uncore_start,
+ .stop = thunder_uncore_stop,
+ .read = thunder_uncore_read,
+ .attr_groups = thunder_l2c_cbc_attr_groups,
+};
+
+static bool event_valid(u64 config)
+{
+ if (config < ARRAY_SIZE(l2c_cbc_events))
+ return true;
+
+ return false;
+}
+
+int __init thunder_uncore_l2c_cbc_setup(void)
+{
+ int ret = -ENOMEM;
+
+ thunder_uncore_l2c_cbc = kzalloc(sizeof(*thunder_uncore_l2c_cbc),
+ GFP_KERNEL);
+ if (!thunder_uncore_l2c_cbc)
+ goto fail_nomem;
+
+ ret = thunder_uncore_setup(thunder_uncore_l2c_cbc, 0xa02f,
+ &thunder_l2c_cbc_pmu,
+ ARRAY_SIZE(l2c_cbc_events));
+ if (ret)
+ goto fail;
+
+ thunder_uncore_l2c_cbc->event_valid = event_valid;
+ return 0;
+
+fail:
+ kfree(thunder_uncore_l2c_cbc);
+fail_nomem:
+ return ret;
+}
--
1.9.1
^ permalink raw reply related
* [PATCH v3 2/5] arm64: perf: Cavium ThunderX L2C TAD uncore support
From: Jan Glauber @ 2016-10-20 9:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476955841-27898-1-git-send-email-jglauber@cavium.com>
Support counters of the L2 Cache tag and data units.
Signed-off-by: Jan Glauber <jglauber@cavium.com>
---
drivers/perf/uncore/Makefile | 3 +-
drivers/perf/uncore/uncore_cavium.c | 1 +
drivers/perf/uncore/uncore_cavium.h | 1 +
drivers/perf/uncore/uncore_cavium_l2c_tad.c | 379 ++++++++++++++++++++++++++++
4 files changed, 383 insertions(+), 1 deletion(-)
create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_tad.c
diff --git a/drivers/perf/uncore/Makefile b/drivers/perf/uncore/Makefile
index 6130e18..90850a2 100644
--- a/drivers/perf/uncore/Makefile
+++ b/drivers/perf/uncore/Makefile
@@ -1 +1,2 @@
-obj-$(CONFIG_UNCORE_PMU_CAVIUM) += uncore_cavium.o
+obj-$(CONFIG_UNCORE_PMU_CAVIUM) += uncore_cavium.o \
+ uncore_cavium_l2c_tad.o
diff --git a/drivers/perf/uncore/uncore_cavium.c b/drivers/perf/uncore/uncore_cavium.c
index a7b4277..15e1aec 100644
--- a/drivers/perf/uncore/uncore_cavium.c
+++ b/drivers/perf/uncore/uncore_cavium.c
@@ -346,6 +346,7 @@ static int __init thunder_uncore_init(void)
if (ret)
return ret;
+ thunder_uncore_l2c_tad_setup();
return 0;
}
late_initcall(thunder_uncore_init);
diff --git a/drivers/perf/uncore/uncore_cavium.h b/drivers/perf/uncore/uncore_cavium.h
index b5d64b5..70a8214 100644
--- a/drivers/perf/uncore/uncore_cavium.h
+++ b/drivers/perf/uncore/uncore_cavium.h
@@ -69,3 +69,4 @@ int thunder_uncore_setup(struct thunder_uncore *uncore, int id,
ssize_t thunder_events_sysfs_show(struct device *dev,
struct device_attribute *attr,
char *page);
+int thunder_uncore_l2c_tad_setup(void);
diff --git a/drivers/perf/uncore/uncore_cavium_l2c_tad.c b/drivers/perf/uncore/uncore_cavium_l2c_tad.c
new file mode 100644
index 0000000..2de37b2
--- /dev/null
+++ b/drivers/perf/uncore/uncore_cavium_l2c_tad.c
@@ -0,0 +1,379 @@
+/*
+ * Cavium Thunder uncore PMU support,
+ * L2 Cache tag-and-data-units (L2C TAD) counters.
+ *
+ * Copyright 2016 Cavium Inc.
+ * Author: Jan Glauber <jan.glauber@cavium.com>
+ */
+
+#include <linux/perf_event.h>
+#include <linux/slab.h>
+
+#include "uncore_cavium.h"
+
+struct thunder_uncore *thunder_uncore_l2c_tad;
+
+#define L2C_TAD_NR_COUNTERS 4
+#define L2C_TAD_PRF_OFFSET 0x10000
+#define L2C_TAD_PFC_OFFSET 0x10100
+
+/*
+ * Counters are selected via L2C_TAD(x)_PRF:
+ *
+ * 63 32
+ * +---------------------------------------+
+ * | Reserved |
+ * +---------------------------------------+
+ * | CNT3SEL | CNT2SEL | CNT1SEL | CNT0SEL |
+ * +---------------------------------------+
+ * 31 24 16 8 0
+ *
+ * config_base contains the offset of the selected CNTxSEL in the mapped BAR.
+ *
+ * Counters are read via L2C_TAD(x)_PFC(0..3).
+ * event_base contains the associated address to read the counter.
+ */
+
+/* L2C TAD event list */
+#define L2C_TAD_EVENTS_DISABLED 0x00
+#define L2C_TAD_EVENT_L2T_HIT 0x01
+#define L2C_TAD_EVENT_L2T_MISS 0x02
+#define L2C_TAD_EVENT_L2T_NOALLOC 0x03
+#define L2C_TAD_EVENT_L2_VIC 0x04
+#define L2C_TAD_EVENT_SC_FAIL 0x05
+#define L2C_TAD_EVENT_SC_PASS 0x06
+#define L2C_TAD_EVENT_LFB_OCC 0x07
+#define L2C_TAD_EVENT_WAIT_LFB 0x08
+#define L2C_TAD_EVENT_WAIT_VAB 0x09
+#define L2C_TAD_EVENT_OPEN_CCPI 0x0a
+#define L2C_TAD_EVENT_LOOKUP 0x40
+#define L2C_TAD_EVENT_LOOKUP_XMC_LCL 0x41
+#define L2C_TAD_EVENT_LOOKUP_XMC_RMT 0x42
+#define L2C_TAD_EVENT_LOOKUP_MIB 0x43
+#define L2C_TAD_EVENT_LOOKUP_ALL 0x44
+#define L2C_TAD_EVENT_TAG_ALC_HIT 0x48
+#define L2C_TAD_EVENT_TAG_ALC_MISS 0x49
+#define L2C_TAD_EVENT_TAG_ALC_NALC 0x4a
+#define L2C_TAD_EVENT_TAG_NALC_HIT 0x4b
+#define L2C_TAD_EVENT_TAG_NALC_MISS 0x4c
+#define L2C_TAD_EVENT_LMC_WR 0x4e
+#define L2C_TAD_EVENT_LMC_SBLKDTY 0x4f
+#define L2C_TAD_EVENT_TAG_ALC_RTG_HIT 0x50
+#define L2C_TAD_EVENT_TAG_ALC_RTG_HITE 0x51
+#define L2C_TAD_EVENT_TAG_ALC_RTG_HITS 0x52
+#define L2C_TAD_EVENT_TAG_ALC_RTG_MISS 0x53
+#define L2C_TAD_EVENT_TAG_NALC_RTG_HIT 0x54
+#define L2C_TAD_EVENT_TAG_NALC_RTG_MISS 0x55
+#define L2C_TAD_EVENT_TAG_NALC_RTG_HITE 0x56
+#define L2C_TAD_EVENT_TAG_NALC_RTG_HITS 0x57
+#define L2C_TAD_EVENT_TAG_ALC_LCL_EVICT 0x58
+#define L2C_TAD_EVENT_TAG_ALC_LCL_CLNVIC 0x59
+#define L2C_TAD_EVENT_TAG_ALC_LCL_DTYVIC 0x5a
+#define L2C_TAD_EVENT_TAG_ALC_RMT_EVICT 0x5b
+#define L2C_TAD_EVENT_TAG_ALC_RMT_VIC 0x5c
+#define L2C_TAD_EVENT_RTG_ALC 0x5d
+#define L2C_TAD_EVENT_RTG_ALC_HIT 0x5e
+#define L2C_TAD_EVENT_RTG_ALC_HITWB 0x5f
+#define L2C_TAD_EVENT_STC_TOTAL 0x60
+#define L2C_TAD_EVENT_STC_TOTAL_FAIL 0x61
+#define L2C_TAD_EVENT_STC_RMT 0x62
+#define L2C_TAD_EVENT_STC_RMT_FAIL 0x63
+#define L2C_TAD_EVENT_STC_LCL 0x64
+#define L2C_TAD_EVENT_STC_LCL_FAIL 0x65
+#define L2C_TAD_EVENT_OCI_RTG_WAIT 0x68
+#define L2C_TAD_EVENT_OCI_FWD_CYC_HIT 0x69
+#define L2C_TAD_EVENT_OCI_FWD_RACE 0x6a
+#define L2C_TAD_EVENT_OCI_HAKS 0x6b
+#define L2C_TAD_EVENT_OCI_FLDX_TAG_E_NODAT 0x6c
+#define L2C_TAD_EVENT_OCI_FLDX_TAG_E_DAT 0x6d
+#define L2C_TAD_EVENT_OCI_RLDD 0x6e
+#define L2C_TAD_EVENT_OCI_RLDD_PEMD 0x6f
+#define L2C_TAD_EVENT_OCI_RRQ_DAT_CNT 0x70
+#define L2C_TAD_EVENT_OCI_RRQ_DAT_DMASK 0x71
+#define L2C_TAD_EVENT_OCI_RSP_DAT_CNT 0x72
+#define L2C_TAD_EVENT_OCI_RSP_DAT_DMASK 0x73
+#define L2C_TAD_EVENT_OCI_RSP_DAT_VICD_CNT 0x74
+#define L2C_TAD_EVENT_OCI_RSP_DAT_VICD_DMASK 0x75
+#define L2C_TAD_EVENT_OCI_RTG_ALC_EVICT 0x76
+#define L2C_TAD_EVENT_OCI_RTG_ALC_VIC 0x77
+#define L2C_TAD_EVENT_QD0_IDX 0x80
+#define L2C_TAD_EVENT_QD0_RDAT 0x81
+#define L2C_TAD_EVENT_QD0_BNKS 0x82
+#define L2C_TAD_EVENT_QD0_WDAT 0x83
+#define L2C_TAD_EVENT_QD1_IDX 0x90
+#define L2C_TAD_EVENT_QD1_RDAT 0x91
+#define L2C_TAD_EVENT_QD1_BNKS 0x92
+#define L2C_TAD_EVENT_QD1_WDAT 0x93
+#define L2C_TAD_EVENT_QD2_IDX 0xa0
+#define L2C_TAD_EVENT_QD2_RDAT 0xa1
+#define L2C_TAD_EVENT_QD2_BNKS 0xa2
+#define L2C_TAD_EVENT_QD2_WDAT 0xa3
+#define L2C_TAD_EVENT_QD3_IDX 0xb0
+#define L2C_TAD_EVENT_QD3_RDAT 0xb1
+#define L2C_TAD_EVENT_QD3_BNKS 0xb2
+#define L2C_TAD_EVENT_QD3_WDAT 0xb3
+#define L2C_TAD_EVENT_QD4_IDX 0xc0
+#define L2C_TAD_EVENT_QD4_RDAT 0xc1
+#define L2C_TAD_EVENT_QD4_BNKS 0xc2
+#define L2C_TAD_EVENT_QD4_WDAT 0xc3
+#define L2C_TAD_EVENT_QD5_IDX 0xd0
+#define L2C_TAD_EVENT_QD5_RDAT 0xd1
+#define L2C_TAD_EVENT_QD5_BNKS 0xd2
+#define L2C_TAD_EVENT_QD5_WDAT 0xd3
+#define L2C_TAD_EVENT_QD6_IDX 0xe0
+#define L2C_TAD_EVENT_QD6_RDAT 0xe1
+#define L2C_TAD_EVENT_QD6_BNKS 0xe2
+#define L2C_TAD_EVENT_QD6_WDAT 0xe3
+#define L2C_TAD_EVENT_QD7_IDX 0xf0
+#define L2C_TAD_EVENT_QD7_RDAT 0xf1
+#define L2C_TAD_EVENT_QD7_BNKS 0xf2
+#define L2C_TAD_EVENT_QD7_WDAT 0xf3
+
+static void thunder_uncore_start_l2c_tad(struct perf_event *event, int flags)
+{
+ struct thunder_uncore *uncore = to_uncore(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunder_uncore_node *node;
+ struct thunder_uncore_unit *unit;
+ int id;
+
+ node = get_node(hwc->config, uncore);
+ id = get_id(hwc->config);
+
+ /* reset counter values to zero */
+ if (flags & PERF_EF_RELOAD)
+ list_for_each_entry(unit, &node->unit_list, entry)
+ writeq(0, hwc->event_base + unit->map);
+
+ /* start counters on all units on the node */
+ list_for_each_entry(unit, &node->unit_list, entry)
+ writeb(id, hwc->config_base + unit->map);
+
+ hwc->state = 0;
+ perf_event_update_userpage(event);
+}
+
+static void thunder_uncore_stop_l2c_tad(struct perf_event *event, int flags)
+{
+ struct thunder_uncore *uncore = to_uncore(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunder_uncore_node *node;
+ struct thunder_uncore_unit *unit;
+
+ node = get_node(hwc->config, uncore);
+
+ /* disable counters for all units on the node */
+ list_for_each_entry(unit, &node->unit_list, entry)
+ writeb(L2C_TAD_EVENTS_DISABLED, hwc->config_base + unit->map);
+ hwc->state |= PERF_HES_STOPPED;
+
+ if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+ thunder_uncore_read(event);
+ hwc->state |= PERF_HES_UPTODATE;
+ }
+}
+
+static int thunder_uncore_add_l2c_tad(struct perf_event *event, int flags)
+{
+ struct thunder_uncore *uncore = to_uncore(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunder_uncore_node *node;
+ int i;
+
+ node = get_node(hwc->config, uncore);
+
+ /* take the first available counter */
+ for (i = 0; i < node->num_counters; i++) {
+ if (!cmpxchg(&node->events[i], NULL, event)) {
+ hwc->idx = i;
+ break;
+ }
+ }
+
+ if (hwc->idx == -1)
+ return -EBUSY;
+
+ /* see comment at beginning of file */
+ hwc->config_base = L2C_TAD_PRF_OFFSET + hwc->idx;
+ hwc->event_base = L2C_TAD_PFC_OFFSET + hwc->idx * sizeof(u64);
+
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+ if (flags & PERF_EF_START)
+ thunder_uncore_start(event, PERF_EF_RELOAD);
+ return 0;
+}
+
+PMU_FORMAT_ATTR(event, "config:0-7");
+
+static struct attribute *thunder_l2c_tad_format_attr[] = {
+ &format_attr_event.attr,
+ &format_attr_node.attr,
+ NULL,
+};
+
+static struct attribute_group thunder_l2c_tad_format_group = {
+ .name = "format",
+ .attrs = thunder_l2c_tad_format_attr,
+};
+
+static struct attribute *thunder_l2c_tad_events_attr[] = {
+ UC_EVENT_ENTRY(l2t_hit, L2C_TAD_EVENT_L2T_HIT),
+ UC_EVENT_ENTRY(l2t_miss, L2C_TAD_EVENT_L2T_MISS),
+ UC_EVENT_ENTRY(l2t_noalloc, L2C_TAD_EVENT_L2T_NOALLOC),
+ UC_EVENT_ENTRY(l2_vic, L2C_TAD_EVENT_L2_VIC),
+ UC_EVENT_ENTRY(sc_fail, L2C_TAD_EVENT_SC_FAIL),
+ UC_EVENT_ENTRY(sc_pass, L2C_TAD_EVENT_SC_PASS),
+ UC_EVENT_ENTRY(lfb_occ, L2C_TAD_EVENT_LFB_OCC),
+ UC_EVENT_ENTRY(wait_lfb, L2C_TAD_EVENT_WAIT_LFB),
+ UC_EVENT_ENTRY(wait_vab, L2C_TAD_EVENT_WAIT_VAB),
+ UC_EVENT_ENTRY(open_ccpi, L2C_TAD_EVENT_OPEN_CCPI),
+ UC_EVENT_ENTRY(lookup, L2C_TAD_EVENT_LOOKUP),
+ UC_EVENT_ENTRY(lookup_xmc_lcl, L2C_TAD_EVENT_LOOKUP_XMC_LCL),
+ UC_EVENT_ENTRY(lookup_xmc_rmt, L2C_TAD_EVENT_LOOKUP_XMC_RMT),
+ UC_EVENT_ENTRY(lookup_mib, L2C_TAD_EVENT_LOOKUP_MIB),
+ UC_EVENT_ENTRY(lookup_all, L2C_TAD_EVENT_LOOKUP_ALL),
+ UC_EVENT_ENTRY(tag_alc_hit, L2C_TAD_EVENT_TAG_ALC_HIT),
+ UC_EVENT_ENTRY(tag_alc_miss, L2C_TAD_EVENT_TAG_ALC_MISS),
+ UC_EVENT_ENTRY(tag_alc_nalc, L2C_TAD_EVENT_TAG_ALC_NALC),
+ UC_EVENT_ENTRY(tag_nalc_hit, L2C_TAD_EVENT_TAG_NALC_HIT),
+ UC_EVENT_ENTRY(tag_nalc_miss, L2C_TAD_EVENT_TAG_NALC_MISS),
+ UC_EVENT_ENTRY(lmc_wr, L2C_TAD_EVENT_LMC_WR),
+ UC_EVENT_ENTRY(lmc_sblkdty, L2C_TAD_EVENT_LMC_SBLKDTY),
+ UC_EVENT_ENTRY(tag_alc_rtg_hit, L2C_TAD_EVENT_TAG_ALC_RTG_HIT),
+ UC_EVENT_ENTRY(tag_alc_rtg_hite, L2C_TAD_EVENT_TAG_ALC_RTG_HITE),
+ UC_EVENT_ENTRY(tag_alc_rtg_hits, L2C_TAD_EVENT_TAG_ALC_RTG_HITS),
+ UC_EVENT_ENTRY(tag_alc_rtg_miss, L2C_TAD_EVENT_TAG_ALC_RTG_MISS),
+ UC_EVENT_ENTRY(tag_alc_nalc_rtg_hit, L2C_TAD_EVENT_TAG_NALC_RTG_HIT),
+ UC_EVENT_ENTRY(tag_nalc_rtg_miss, L2C_TAD_EVENT_TAG_NALC_RTG_MISS),
+ UC_EVENT_ENTRY(tag_nalc_rtg_hite, L2C_TAD_EVENT_TAG_NALC_RTG_HITE),
+ UC_EVENT_ENTRY(tag_nalc_rtg_hits, L2C_TAD_EVENT_TAG_NALC_RTG_HITS),
+ UC_EVENT_ENTRY(tag_alc_lcl_evict, L2C_TAD_EVENT_TAG_ALC_LCL_EVICT),
+ UC_EVENT_ENTRY(tag_alc_lcl_clnvic, L2C_TAD_EVENT_TAG_ALC_LCL_CLNVIC),
+ UC_EVENT_ENTRY(tag_alc_lcl_dtyvic, L2C_TAD_EVENT_TAG_ALC_LCL_DTYVIC),
+ UC_EVENT_ENTRY(tag_alc_rmt_evict, L2C_TAD_EVENT_TAG_ALC_RMT_EVICT),
+ UC_EVENT_ENTRY(tag_alc_rmt_vic, L2C_TAD_EVENT_TAG_ALC_RMT_VIC),
+ UC_EVENT_ENTRY(rtg_alc, L2C_TAD_EVENT_RTG_ALC),
+ UC_EVENT_ENTRY(rtg_alc_hit, L2C_TAD_EVENT_RTG_ALC_HIT),
+ UC_EVENT_ENTRY(rtg_alc_hitwb, L2C_TAD_EVENT_RTG_ALC_HITWB),
+ UC_EVENT_ENTRY(stc_total, L2C_TAD_EVENT_STC_TOTAL),
+ UC_EVENT_ENTRY(stc_total_fail, L2C_TAD_EVENT_STC_TOTAL_FAIL),
+ UC_EVENT_ENTRY(stc_rmt, L2C_TAD_EVENT_STC_RMT),
+ UC_EVENT_ENTRY(stc_rmt_fail, L2C_TAD_EVENT_STC_RMT_FAIL),
+ UC_EVENT_ENTRY(stc_lcl, L2C_TAD_EVENT_STC_LCL),
+ UC_EVENT_ENTRY(stc_lcl_fail, L2C_TAD_EVENT_STC_LCL_FAIL),
+ UC_EVENT_ENTRY(oci_rtg_wait, L2C_TAD_EVENT_OCI_RTG_WAIT),
+ UC_EVENT_ENTRY(oci_fwd_cyc_hit, L2C_TAD_EVENT_OCI_FWD_CYC_HIT),
+ UC_EVENT_ENTRY(oci_fwd_race, L2C_TAD_EVENT_OCI_FWD_RACE),
+ UC_EVENT_ENTRY(oci_haks, L2C_TAD_EVENT_OCI_HAKS),
+ UC_EVENT_ENTRY(oci_fldx_tag_e_nodat, L2C_TAD_EVENT_OCI_FLDX_TAG_E_NODAT),
+ UC_EVENT_ENTRY(oci_fldx_tag_e_dat, L2C_TAD_EVENT_OCI_FLDX_TAG_E_DAT),
+ UC_EVENT_ENTRY(oci_rldd, L2C_TAD_EVENT_OCI_RLDD),
+ UC_EVENT_ENTRY(oci_rldd_pemd, L2C_TAD_EVENT_OCI_RLDD_PEMD),
+ UC_EVENT_ENTRY(oci_rrq_dat_cnt, L2C_TAD_EVENT_OCI_RRQ_DAT_CNT),
+ UC_EVENT_ENTRY(oci_rrq_dat_dmask, L2C_TAD_EVENT_OCI_RRQ_DAT_DMASK),
+ UC_EVENT_ENTRY(oci_rsp_dat_cnt, L2C_TAD_EVENT_OCI_RSP_DAT_CNT),
+ UC_EVENT_ENTRY(oci_rsp_dat_dmaks, L2C_TAD_EVENT_OCI_RSP_DAT_DMASK),
+ UC_EVENT_ENTRY(oci_rsp_dat_vicd_cnt, L2C_TAD_EVENT_OCI_RSP_DAT_VICD_CNT),
+ UC_EVENT_ENTRY(oci_rsp_dat_vicd_dmask, L2C_TAD_EVENT_OCI_RSP_DAT_VICD_DMASK),
+ UC_EVENT_ENTRY(oci_rtg_alc_evict, L2C_TAD_EVENT_OCI_RTG_ALC_EVICT),
+ UC_EVENT_ENTRY(oci_rtg_alc_vic, L2C_TAD_EVENT_OCI_RTG_ALC_VIC),
+ UC_EVENT_ENTRY(qd0_idx, L2C_TAD_EVENT_QD0_IDX),
+ UC_EVENT_ENTRY(qd0_rdat, L2C_TAD_EVENT_QD0_RDAT),
+ UC_EVENT_ENTRY(qd0_bnks, L2C_TAD_EVENT_QD0_BNKS),
+ UC_EVENT_ENTRY(qd0_wdat, L2C_TAD_EVENT_QD0_WDAT),
+ UC_EVENT_ENTRY(qd1_idx, L2C_TAD_EVENT_QD1_IDX),
+ UC_EVENT_ENTRY(qd1_rdat, L2C_TAD_EVENT_QD1_RDAT),
+ UC_EVENT_ENTRY(qd1_bnks, L2C_TAD_EVENT_QD1_BNKS),
+ UC_EVENT_ENTRY(qd1_wdat, L2C_TAD_EVENT_QD1_WDAT),
+ UC_EVENT_ENTRY(qd2_idx, L2C_TAD_EVENT_QD2_IDX),
+ UC_EVENT_ENTRY(qd2_rdat, L2C_TAD_EVENT_QD2_RDAT),
+ UC_EVENT_ENTRY(qd2_bnks, L2C_TAD_EVENT_QD2_BNKS),
+ UC_EVENT_ENTRY(qd2_wdat, L2C_TAD_EVENT_QD2_WDAT),
+ UC_EVENT_ENTRY(qd3_idx, L2C_TAD_EVENT_QD3_IDX),
+ UC_EVENT_ENTRY(qd3_rdat, L2C_TAD_EVENT_QD3_RDAT),
+ UC_EVENT_ENTRY(qd3_bnks, L2C_TAD_EVENT_QD3_BNKS),
+ UC_EVENT_ENTRY(qd3_wdat, L2C_TAD_EVENT_QD3_WDAT),
+ UC_EVENT_ENTRY(qd4_idx, L2C_TAD_EVENT_QD4_IDX),
+ UC_EVENT_ENTRY(qd4_rdat, L2C_TAD_EVENT_QD4_RDAT),
+ UC_EVENT_ENTRY(qd4_bnks, L2C_TAD_EVENT_QD4_BNKS),
+ UC_EVENT_ENTRY(qd4_wdat, L2C_TAD_EVENT_QD4_WDAT),
+ UC_EVENT_ENTRY(qd5_idx, L2C_TAD_EVENT_QD5_IDX),
+ UC_EVENT_ENTRY(qd5_rdat, L2C_TAD_EVENT_QD5_RDAT),
+ UC_EVENT_ENTRY(qd5_bnks, L2C_TAD_EVENT_QD5_BNKS),
+ UC_EVENT_ENTRY(qd5_wdat, L2C_TAD_EVENT_QD5_WDAT),
+ UC_EVENT_ENTRY(qd6_idx, L2C_TAD_EVENT_QD6_IDX),
+ UC_EVENT_ENTRY(qd6_rdat, L2C_TAD_EVENT_QD6_RDAT),
+ UC_EVENT_ENTRY(qd6_bnks, L2C_TAD_EVENT_QD6_BNKS),
+ UC_EVENT_ENTRY(qd6_wdat, L2C_TAD_EVENT_QD6_WDAT),
+ UC_EVENT_ENTRY(qd7_idx, L2C_TAD_EVENT_QD7_IDX),
+ UC_EVENT_ENTRY(qd7_rdat, L2C_TAD_EVENT_QD7_RDAT),
+ UC_EVENT_ENTRY(qd7_bnks, L2C_TAD_EVENT_QD7_BNKS),
+ UC_EVENT_ENTRY(qd7_wdat, L2C_TAD_EVENT_QD7_WDAT),
+ NULL,
+};
+
+static struct attribute_group thunder_l2c_tad_events_group = {
+ .name = "events",
+ .attrs = thunder_l2c_tad_events_attr,
+};
+
+static const struct attribute_group *thunder_l2c_tad_attr_groups[] = {
+ &thunder_uncore_attr_group,
+ &thunder_l2c_tad_format_group,
+ &thunder_l2c_tad_events_group,
+ NULL,
+};
+
+struct pmu thunder_l2c_tad_pmu = {
+ .name = "thunder_l2c_tad",
+ .task_ctx_nr = perf_sw_context,
+ .event_init = thunder_uncore_event_init,
+ .add = thunder_uncore_add_l2c_tad,
+ .del = thunder_uncore_del,
+ .start = thunder_uncore_start_l2c_tad,
+ .stop = thunder_uncore_stop_l2c_tad,
+ .read = thunder_uncore_read,
+ .attr_groups = thunder_l2c_tad_attr_groups,
+};
+
+static bool event_valid(u64 c)
+{
+ if ((c > 0 &&
+ c <= L2C_TAD_EVENT_OPEN_CCPI) ||
+ (c >= L2C_TAD_EVENT_LOOKUP &&
+ c <= L2C_TAD_EVENT_LOOKUP_ALL) ||
+ (c >= L2C_TAD_EVENT_TAG_ALC_HIT &&
+ c <= L2C_TAD_EVENT_TAG_NALC_MISS) ||
+ (c >= L2C_TAD_EVENT_LMC_WR &&
+ c <= L2C_TAD_EVENT_STC_LCL_FAIL) ||
+ (c >= L2C_TAD_EVENT_OCI_RTG_WAIT &&
+ c <= L2C_TAD_EVENT_OCI_RTG_ALC_VIC) ||
+ /* L2C_TAD_EVENT_QD[0..7] IDX,RDAT,BNKS,WDAT => 0x80 .. 0xf3 */
+ ((c & 0x80) && ((c & 0xf) <= 3)))
+ return true;
+
+ return false;
+}
+
+int __init thunder_uncore_l2c_tad_setup(void)
+{
+ int ret = -ENOMEM;
+
+ thunder_uncore_l2c_tad = kzalloc(sizeof(*thunder_uncore_l2c_tad),
+ GFP_KERNEL);
+ if (!thunder_uncore_l2c_tad)
+ goto fail_nomem;
+
+ ret = thunder_uncore_setup(thunder_uncore_l2c_tad, 0xa02e,
+ &thunder_l2c_tad_pmu, L2C_TAD_NR_COUNTERS);
+ if (ret)
+ goto fail;
+
+ thunder_uncore_l2c_tad->event_valid = event_valid;
+ return 0;
+
+fail:
+ kfree(thunder_uncore_l2c_tad);
+fail_nomem:
+ return ret;
+}
--
1.9.1
^ permalink raw reply related
* [PATCH v3 1/5] arm64: perf: Basic uncore counter support for Cavium ThunderX SOC
From: Jan Glauber @ 2016-10-20 9:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476955841-27898-1-git-send-email-jglauber@cavium.com>
Provide "uncore" facilities for different non-CPU performance
counter units.
The uncore PMUs can be found under /sys/bus/event_source/devices.
All counters are exported via sysfs in the corresponding events
files under the PMU directory so the perf tool can list the event names.
There are some points that are special in this implementation:
1) The PMU detection relies on PCI device detection. If a
matching PCI device is found the PMU is created. The code can deal
with multiple units of the same type, e.g. more than one memory
controller.
2) Counters are summarized across different units of the same type
on one NUMA node but not across NUMA nodes.
For instance L2C TAD 0..7 are presented as a single counter
(adding the values from TAD 0 to 7). Although losing the ability
to read a single value the merged values are easier to use.
3) The counters are not CPU related. A random CPU is picked regardless
of the NUMA node. There is a small performance penalty for accessing
counters on a remote note but reading a performance counter is a
slow operation anyway.
Signed-off-by: Jan Glauber <jglauber@cavium.com>
---
drivers/perf/Kconfig | 13 ++
drivers/perf/Makefile | 1 +
drivers/perf/uncore/Makefile | 1 +
drivers/perf/uncore/uncore_cavium.c | 351 ++++++++++++++++++++++++++++++++++++
drivers/perf/uncore/uncore_cavium.h | 71 ++++++++
include/linux/cpuhotplug.h | 1 +
6 files changed, 438 insertions(+)
create mode 100644 drivers/perf/uncore/Makefile
create mode 100644 drivers/perf/uncore/uncore_cavium.c
create mode 100644 drivers/perf/uncore/uncore_cavium.h
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index 4d5c5f9..3266c87 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -19,4 +19,17 @@ config XGENE_PMU
help
Say y if you want to use APM X-Gene SoC performance monitors.
+config UNCORE_PMU
+ bool
+
+config UNCORE_PMU_CAVIUM
+ depends on PERF_EVENTS && NUMA && ARM64
+ bool "Cavium uncore PMU support"
+ select UNCORE_PMU
+ default y
+ help
+ Say y if you want to access performance counters of subsystems
+ on a Cavium SOC like cache controller, memory controller or
+ processor interconnect.
+
endmenu
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index b116e98..144374b 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_ARM_PMU) += arm_pmu.o
+obj-y += uncore/
obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o
diff --git a/drivers/perf/uncore/Makefile b/drivers/perf/uncore/Makefile
new file mode 100644
index 0000000..6130e18
--- /dev/null
+++ b/drivers/perf/uncore/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_UNCORE_PMU_CAVIUM) += uncore_cavium.o
diff --git a/drivers/perf/uncore/uncore_cavium.c b/drivers/perf/uncore/uncore_cavium.c
new file mode 100644
index 0000000..a7b4277
--- /dev/null
+++ b/drivers/perf/uncore/uncore_cavium.c
@@ -0,0 +1,351 @@
+/*
+ * Cavium Thunder uncore PMU support.
+ *
+ * Copyright (C) 2015,2016 Cavium Inc.
+ * Author: Jan Glauber <jan.glauber@cavium.com>
+ */
+
+#include <linux/cpufeature.h>
+#include <linux/numa.h>
+#include <linux/slab.h>
+
+#include "uncore_cavium.h"
+
+/*
+ * Some notes about the various counters supported by this "uncore" PMU
+ * and the design:
+ *
+ * All counters are 64 bit long.
+ * There are no overflow interrupts.
+ * Counters are summarized per node/socket.
+ * Most devices appear as separate PCI devices per socket with the exception
+ * of OCX TLK which appears as one PCI device per socket and contains several
+ * units with counters that are merged.
+ * Some counters are selected via a control register (L2C TAD) and read by
+ * a number of counter registers, others (L2C CBC, LMC & OCX TLK) have
+ * one dedicated counter per event.
+ * Some counters are not stoppable (L2C CBC & LMC).
+ * Some counters are read-only (LMC).
+ * All counters belong to PCI devices, the devices may have additional
+ * drivers but we assume we are the only user of the counter registers.
+ * We map the whole PCI BAR so we must be careful to forbid access to
+ * addresses that contain neither counters nor counter control registers.
+ */
+
+void thunder_uncore_read(struct perf_event *event)
+{
+ struct thunder_uncore *uncore = to_uncore(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunder_uncore_node *node;
+ struct thunder_uncore_unit *unit;
+ u64 prev, delta, new = 0;
+
+ node = get_node(hwc->config, uncore);
+
+ /* read counter values from all units on the node */
+ list_for_each_entry(unit, &node->unit_list, entry)
+ new += readq(hwc->event_base + unit->map);
+
+ prev = local64_read(&hwc->prev_count);
+ local64_set(&hwc->prev_count, new);
+ delta = new - prev;
+ local64_add(delta, &event->count);
+}
+
+int thunder_uncore_add(struct perf_event *event, int flags, u64 config_base,
+ u64 event_base)
+{
+ struct thunder_uncore *uncore = to_uncore(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunder_uncore_node *node;
+ int id;
+
+ node = get_node(hwc->config, uncore);
+ id = get_id(hwc->config);
+
+ if (!cmpxchg(&node->events[id], NULL, event))
+ hwc->idx = id;
+
+ if (hwc->idx == -1)
+ return -EBUSY;
+
+ hwc->config_base = config_base;
+ hwc->event_base = event_base;
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+ if (flags & PERF_EF_START)
+ uncore->pmu.start(event, PERF_EF_RELOAD);
+
+ return 0;
+}
+
+void thunder_uncore_del(struct perf_event *event, int flags)
+{
+ struct thunder_uncore *uncore = to_uncore(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunder_uncore_node *node;
+ int i;
+
+ event->pmu->stop(event, PERF_EF_UPDATE);
+
+ /*
+ * For programmable counters we need to check where we installed it.
+ * To keep this function generic always test the more complicated
+ * case (free running counters won't need the loop).
+ */
+ node = get_node(hwc->config, uncore);
+ for (i = 0; i < node->num_counters; i++) {
+ if (cmpxchg(&node->events[i], event, NULL) == event)
+ break;
+ }
+ hwc->idx = -1;
+}
+
+void thunder_uncore_start(struct perf_event *event, int flags)
+{
+ struct thunder_uncore *uncore = to_uncore(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunder_uncore_node *node;
+ struct thunder_uncore_unit *unit;
+ u64 new = 0;
+
+ /* read counter values from all units on the node */
+ node = get_node(hwc->config, uncore);
+ list_for_each_entry(unit, &node->unit_list, entry)
+ new += readq(hwc->event_base + unit->map);
+ local64_set(&hwc->prev_count, new);
+
+ hwc->state = 0;
+ perf_event_update_userpage(event);
+}
+
+void thunder_uncore_stop(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ hwc->state |= PERF_HES_STOPPED;
+
+ if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+ thunder_uncore_read(event);
+ hwc->state |= PERF_HES_UPTODATE;
+ }
+}
+
+int thunder_uncore_event_init(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct thunder_uncore_node *node;
+ struct thunder_uncore *uncore;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ /* we do not support sampling */
+ if (is_sampling_event(event))
+ return -EINVAL;
+
+ /* counters do not have these bits */
+ if (event->attr.exclude_user ||
+ event->attr.exclude_kernel ||
+ event->attr.exclude_host ||
+ event->attr.exclude_guest ||
+ event->attr.exclude_hv ||
+ event->attr.exclude_idle)
+ return -EINVAL;
+
+ uncore = to_uncore(event->pmu);
+ if (!uncore)
+ return -ENODEV;
+ if (!uncore->event_valid(event->attr.config & UNCORE_EVENT_ID_MASK))
+ return -EINVAL;
+
+ /* check NUMA node */
+ node = get_node(event->attr.config, uncore);
+ if (!node) {
+ pr_debug("Invalid NUMA node selected\n");
+ return -EINVAL;
+ }
+
+ hwc->config = event->attr.config;
+ hwc->idx = -1;
+ return 0;
+}
+
+static ssize_t thunder_uncore_attr_show_cpumask(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct pmu *pmu = dev_get_drvdata(dev);
+ struct thunder_uncore *uncore =
+ container_of(pmu, struct thunder_uncore, pmu);
+
+ return cpumap_print_to_pagebuf(true, buf, &uncore->active_mask);
+}
+static DEVICE_ATTR(cpumask, S_IRUGO, thunder_uncore_attr_show_cpumask, NULL);
+
+static struct attribute *thunder_uncore_attrs[] = {
+ &dev_attr_cpumask.attr,
+ NULL,
+};
+
+struct attribute_group thunder_uncore_attr_group = {
+ .attrs = thunder_uncore_attrs,
+};
+
+ssize_t thunder_events_sysfs_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ struct perf_pmu_events_attr *pmu_attr =
+ container_of(attr, struct perf_pmu_events_attr, attr);
+
+ if (pmu_attr->event_str)
+ return sprintf(page, "%s", pmu_attr->event_str);
+
+ return 0;
+}
+
+/* node attribute depending on number of NUMA nodes */
+static ssize_t node_show(struct device *dev, struct device_attribute *attr,
+ char *page)
+{
+ if (NODES_SHIFT)
+ return sprintf(page, "config:16-%d\n", 16 + NODES_SHIFT - 1);
+ else
+ return sprintf(page, "config:16\n");
+}
+
+struct device_attribute format_attr_node = __ATTR_RO(node);
+
+/*
+ * Thunder uncore events are independent from CPUs. Provide a cpumask
+ * nevertheless to prevent perf from adding the event per-cpu and just
+ * set the mask to one online CPU. Use the same cpumask for all uncore
+ * devices.
+ *
+ * There is a performance penalty for accessing a device from a CPU on
+ * another socket, but we do not care (yet).
+ */
+static int thunder_uncore_offline_cpu(unsigned int old_cpu, struct hlist_node *node)
+{
+ struct thunder_uncore *uncore = hlist_entry_safe(node, struct thunder_uncore, node);
+ int new_cpu;
+
+ if (!cpumask_test_and_clear_cpu(old_cpu, &uncore->active_mask))
+ return 0;
+ new_cpu = cpumask_any_but(cpu_online_mask, old_cpu);
+ if (new_cpu >= nr_cpu_ids)
+ return 0;
+ perf_pmu_migrate_context(&uncore->pmu, old_cpu, new_cpu);
+ cpumask_set_cpu(new_cpu, &uncore->active_mask);
+ return 0;
+}
+
+static struct thunder_uncore_node * __init alloc_node(struct thunder_uncore *uncore,
+ int node_id, int counters)
+{
+ struct thunder_uncore_node *node;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return NULL;
+ node->num_counters = counters;
+ INIT_LIST_HEAD(&node->unit_list);
+ return node;
+}
+
+int __init thunder_uncore_setup(struct thunder_uncore *uncore, int device_id,
+ struct pmu *pmu, int counters)
+{
+ unsigned int vendor_id = PCI_VENDOR_ID_CAVIUM;
+ struct thunder_uncore_unit *unit, *tmp;
+ struct thunder_uncore_node *node;
+ struct pci_dev *pdev = NULL;
+ int ret, node_id, found = 0;
+
+ /* detect PCI devices */
+ while ((pdev = pci_get_device(vendor_id, device_id, pdev))) {
+ if (!pdev)
+ break;
+
+ node_id = dev_to_node(&pdev->dev);
+
+ /* allocate node if necessary */
+ if (!uncore->nodes[node_id])
+ uncore->nodes[node_id] = alloc_node(uncore, node_id, counters);
+
+ node = uncore->nodes[node_id];
+ if (!node) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ unit = kzalloc(sizeof(*unit), GFP_KERNEL);
+ if (!unit) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ unit->pdev = pdev;
+ unit->map = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ list_add(&unit->entry, &node->unit_list);
+ node->nr_units++;
+ found++;
+ }
+
+ if (!found)
+ return -ENODEV;
+
+ cpuhp_state_add_instance_nocalls(CPUHP_AP_UNCORE_CAVIUM_ONLINE,
+ &uncore->node);
+
+ /*
+ * perf PMU is CPU dependent in difference to our uncore devices.
+ * Just pick a CPU and migrate away if it goes offline.
+ */
+ cpumask_set_cpu(smp_processor_id(), &uncore->active_mask);
+
+ uncore->pmu = *pmu;
+ ret = perf_pmu_register(&uncore->pmu, uncore->pmu.name, -1);
+ if (ret)
+ goto fail;
+
+ return 0;
+
+fail:
+ node_id = 0;
+ while (uncore->nodes[node_id]) {
+ node = uncore->nodes[node_id];
+
+ list_for_each_entry_safe(unit, tmp, &node->unit_list, entry) {
+ if (unit->pdev) {
+ if (unit->map)
+ iounmap(unit->map);
+ pci_dev_put(unit->pdev);
+ }
+ kfree(unit);
+ }
+ kfree(uncore->nodes[node_id]);
+ node_id++;
+ }
+ return ret;
+}
+
+static int __init thunder_uncore_init(void)
+{
+ unsigned long implementor = read_cpuid_implementor();
+ int ret;
+
+ if (implementor != ARM_CPU_IMP_CAVIUM)
+ return -ENODEV;
+
+ ret = cpuhp_setup_state_multi(CPUHP_AP_UNCORE_CAVIUM_ONLINE,
+ "AP_PERF_UNCORE_CAVIUM_ONLINE", NULL,
+ thunder_uncore_offline_cpu);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+late_initcall(thunder_uncore_init);
diff --git a/drivers/perf/uncore/uncore_cavium.h b/drivers/perf/uncore/uncore_cavium.h
new file mode 100644
index 0000000..b5d64b5
--- /dev/null
+++ b/drivers/perf/uncore/uncore_cavium.h
@@ -0,0 +1,71 @@
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/perf_event.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "thunderx_uncore: " fmt
+
+#define to_uncore(x) container_of((x), struct thunder_uncore, pmu)
+
+#define UNCORE_EVENT_ID_MASK 0xffff
+#define UNCORE_EVENT_ID_SHIFT 16
+
+/* maximum number of parallel hardware counters for all uncore parts */
+#define MAX_COUNTERS 64
+
+struct thunder_uncore_unit {
+ struct list_head entry;
+ void __iomem *map;
+ struct pci_dev *pdev;
+};
+
+struct thunder_uncore_node {
+ int nr_units;
+ int num_counters;
+ struct list_head unit_list;
+ struct perf_event *events[MAX_COUNTERS];
+};
+
+/* generic uncore struct for different pmu types */
+struct thunder_uncore {
+ struct pmu pmu;
+ bool (*event_valid)(u64);
+ struct hlist_node node;
+ struct thunder_uncore_node *nodes[MAX_NUMNODES];
+ cpumask_t active_mask;
+};
+
+#define UC_EVENT_ENTRY(_name, _id) \
+ &((struct perf_pmu_events_attr[]) { \
+ { \
+ __ATTR(_name, S_IRUGO, thunder_events_sysfs_show, NULL), \
+ 0, \
+ "event=" __stringify(_id), \
+ } \
+ })[0].attr.attr
+
+static inline struct thunder_uncore_node *get_node(u64 config,
+ struct thunder_uncore *uncore)
+{
+ return uncore->nodes[config >> UNCORE_EVENT_ID_SHIFT];
+}
+
+#define get_id(config) (config & UNCORE_EVENT_ID_MASK)
+
+extern struct attribute_group thunder_uncore_attr_group;
+extern struct device_attribute format_attr_node;
+
+/* Prototypes */
+void thunder_uncore_read(struct perf_event *event);
+int thunder_uncore_add(struct perf_event *event, int flags, u64 config_base,
+ u64 event_base);
+void thunder_uncore_del(struct perf_event *event, int flags);
+void thunder_uncore_start(struct perf_event *event, int flags);
+void thunder_uncore_stop(struct perf_event *event, int flags);
+int thunder_uncore_event_init(struct perf_event *event);
+int thunder_uncore_setup(struct thunder_uncore *uncore, int id,
+ struct pmu *pmu, int counters);
+ssize_t thunder_events_sysfs_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page);
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 9b207a8..370a7a2 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -117,6 +117,7 @@ enum cpuhp_state {
CPUHP_AP_PERF_ARM_CCI_ONLINE,
CPUHP_AP_PERF_ARM_CCN_ONLINE,
CPUHP_AP_PERF_ARM_L2X0_ONLINE,
+ CPUHP_AP_UNCORE_CAVIUM_ONLINE,
CPUHP_AP_WORKQUEUE_ONLINE,
CPUHP_AP_RCUTREE_ONLINE,
CPUHP_AP_NOTIFY_ONLINE,
--
1.9.1
^ permalink raw reply related
* [PATCH v3 0/5] Cavium ThunderX uncore PMU support
From: Jan Glauber @ 2016-10-20 9:30 UTC (permalink / raw)
To: linux-arm-kernel
Sorry for the long time it took for re-cooking this patch set.
The v3 should address all of Marks previous comments, things I didn't
change are listed below.
Not changed:
- Stick to NUMA node ID to detect the socket a device belongs to but made
uncore depend on CONFIG_NUMA.
- Stick to initcall for uncore framework because it is easier to do the
scanning for the same type of PCI devices, also I don't know if the PCI layer
would allow for several drivers to register for the same device ID.
Note:
I'm using perf_sw_context in difference to perf_invalid_context
(see WARN_ON in perf_pmu_register). Reason is that with perf_invalid_context
add() is never called and the counter results are shown as "unsupported" by
perf. With perf_sw_context everything works as expected.
Patches are against 4.9.0-rc1
Changes to v2:
- Embedded struct pmu and killed uncore->type
- Simplified add functions
- Unified functions where possible into a common implementation
- Use arrays to translate non-contiguous counter addresses to event_id's
visible to the user
- Sorted includes
- Got rid of division for previous counter values
- Removed unneeded WARN_ONs
- Use sizeof(*ptr)
- Use bool for event_valid return
- Fixed HES_STOPPED logic
- Added some design notes and improved (hopefully) comments
- Removed pass1 counter support for now
- Merged EVENT_ATTR and EVENT_PTR defines into one (unreadable) thing
- Use pmu_enable|disable to start|stop the OCX TLK counter set
- Moved cpumask into thunder_uncore struct
- Switched to new cpuhp stuff. I still don't care about the CPU location
used to access an uncore device, it may cross the CCPI and
we'll pay a performance penalty. We might optimize this later, for now
I feel it is not worth the time optimizing it.
------------------------
Jan Glauber (5):
arm64: perf: Basic uncore counter support for Cavium ThunderX SOC
arm64: perf: Cavium ThunderX L2C TAD uncore support
arm64: perf: Cavium ThunderX L2C CBC uncore support
arm64: perf: Cavium ThunderX LMC uncore support
arm64: perf: Cavium ThunderX OCX TLK uncore support
drivers/perf/Kconfig | 13 +
drivers/perf/Makefile | 1 +
drivers/perf/uncore/Makefile | 5 +
drivers/perf/uncore/uncore_cavium.c | 355 ++++++++++++++++++++++++++
drivers/perf/uncore/uncore_cavium.h | 75 ++++++
drivers/perf/uncore/uncore_cavium_l2c_cbc.c | 148 +++++++++++
drivers/perf/uncore/uncore_cavium_l2c_tad.c | 379 ++++++++++++++++++++++++++++
drivers/perf/uncore/uncore_cavium_lmc.c | 118 +++++++++
drivers/perf/uncore/uncore_cavium_ocx_tlk.c | 344 +++++++++++++++++++++++++
include/linux/cpuhotplug.h | 1 +
10 files changed, 1439 insertions(+)
create mode 100644 drivers/perf/uncore/Makefile
create mode 100644 drivers/perf/uncore/uncore_cavium.c
create mode 100644 drivers/perf/uncore/uncore_cavium.h
create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_cbc.c
create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_tad.c
create mode 100644 drivers/perf/uncore/uncore_cavium_lmc.c
create mode 100644 drivers/perf/uncore/uncore_cavium_ocx_tlk.c
--
1.9.1
^ permalink raw reply
* [PATCH v3 0/11] Add R8A7743/SK-RZG1M board support
From: Simon Horman @ 2016-10-20 9:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cea44556-a578-fb54-11b8-f21f5b991caa@cogentembedded.com>
On Wed, Oct 12, 2016 at 11:29:56AM +0300, Sergei Shtylyov wrote:
> On 10/12/2016 11:09 AM, Simon Horman wrote:
>
> >>> Here's the set of 11 patches against Simon Horman's 'renesas.git' repo's
> >>>'renesas-devel-20161003-v4.8' tag. I'm adding the device tree support for
> >>>the R8A7743-based SK-RZG1M board. The SoC is close to R8A7791 and the board
> >>>seems identical to the R8A7791/Porter board. The device tree patches depend on
> >>>the R8A7743 CPG/MSSR driver series just posted in order to compile and work.
> >>
> >> Forgot to mention that this version causes a regression with the sh_eth
> >>driver (well, actually with phylib): since IRQC now gets a deferred probing,
> >>PHY IRQ doesn't work anymore -- phylib falls back to polling.
> >
> >Is there a resolution to that problem?
>
> Geert has posted his IRQC driver patch recently. Not sure if it was
> intended for merging but it solves the issue.
Ok. I think it is ok to merge support for a new board even if there are
problems as its not regressing (can't break something that previously
didn't exist imho). But of course it would be best if things did work.
Geert, do you have any comments on the relevance of your IRQC driver patch?
^ permalink raw reply
* [PATCH v7 09/11] arm64: dts: r8a7796: salvator-x: enable SDHI0 & 3
From: Simon Horman @ 2016-10-20 9:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160916103218.GM1411@katana>
On Fri, Sep 16, 2016 at 12:32:18PM +0200, Wolfram Sang wrote:
> On Tue, Sep 13, 2016 at 12:57:06PM +0200, Simon Horman wrote:
> > Enable the exposed SD card slots in the DT of the r8a7796/salvator-x.
> >
> > Based on work for the r8a7795/salvator-x by Ai Kyuse.
> >
> > Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
> > Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
>
> Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Thanks, I have queued this up.
^ permalink raw reply
* [PATCH v7 08/11] arm64: dts: r8a7796: add SDHI nodes
From: Simon Horman @ 2016-10-20 9:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160916105321.GB7566@verge.net.au>
On Fri, Sep 16, 2016 at 12:53:22PM +0200, Simon Horman wrote:
> On Fri, Sep 16, 2016 at 12:30:48PM +0200, Wolfram Sang wrote:
> > On Tue, Sep 13, 2016 at 12:57:05PM +0200, Simon Horman wrote:
> > > Add SDHI nodes to the DT of the r8a7796 SoC.
> > >
> > > Based on the DT of the r8a7795 SoC.
> > >
> > > Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
> > > Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> >
> > If you remove the two lines you removed from H3 already:
>
> Thanks, done.
>
> > Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
I have queued this up for v4.10.
^ permalink raw reply
* [PATCH v7 10/11] arm64: dts: r8a7796: salvator-x: enable UHS for SDHI 0 & 3
From: Simon Horman @ 2016-10-20 9:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160916103317.GN1411@katana>
On Fri, Sep 16, 2016 at 12:33:17PM +0200, Wolfram Sang wrote:
> On Tue, Sep 13, 2016 at 12:57:07PM +0200, Simon Horman wrote:
> > Based on work for the r8a7796 by Wolfram Sang.
> >
> > Cc: Wolfram Sang <wsa+renesas@sang-engineering.com>
> > Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
>
> Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Thanks, I have queued this up.
^ permalink raw reply
* [PATCH V4 3/3] ARM64 LPC: LPC driver implementation on Hip06
From: zhichang.yuan @ 2016-10-20 9:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476954940-242159-1-git-send-email-yuanzhichang@hisilicon.com>
On Hip06, the accesses to LPC peripherals work in an indirect way. A
corresponding LPC driver configure some registers in LPC master at first, then
the real accesses on LPC slave devices are finished by the LPC master, which
is transparent to LPC driver.
This patch implement the relevant driver for Hip06 LPC. Cooperating with
indirect-IO, ipmi messages is in service without any changes on ipmi driver.
Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
.../arm/hisilicon/hisilicon-low-pin-count.txt | 31 ++
MAINTAINERS | 8 +
drivers/bus/Kconfig | 8 +
drivers/bus/Makefile | 1 +
drivers/bus/hisi_lpc.c | 501 +++++++++++++++++++++
5 files changed, 549 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
create mode 100644 drivers/bus/hisi_lpc.c
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
new file mode 100644
index 0000000..e681419
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
@@ -0,0 +1,31 @@
+Hisilicon Hip06 low-pin-count device
+ Usually LPC controller is part of PCI host bridge, so the legacy ISA ports
+ locate on LPC bus can be accessed direclty. But some SoCs have independent
+ LPC controller, and access the legacy ports by triggering LPC I/O cycles.
+ Hisilicon Hip06 implements this LPC device.
+
+Required properties:
+- compatible: should be "hisilicon,low-pin-count"
+- #address-cells: must be 2 which stick to the ISA/EISA binding doc.
+- #size-cells: must be 1 which stick to the ISA/EISA binding doc.
+- reg: base memory range where the register set for this device is mapped.
+
+Note:
+ The node name before '@' must be "isa" to represent the binding stick to the
+ ISA/EISA binding specification.
+
+Example:
+
+isa at a01b0000 {
+ compatible = "hisilicom,low-pin-count";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ reg = <0x0 0xa01b0000 0x0 0x1000>;
+
+ ipmi0: bt at e4 {
+ compatible = "ipmi-bt";
+ device_type = "ipmi";
+ reg = <0x01 0xe4 0x04>;
+ status = "disabled";
+ };
+};
diff --git a/MAINTAINERS b/MAINTAINERS
index 1cd38a7..7c69410 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5716,6 +5716,14 @@ F: include/uapi/linux/if_hippi.h
F: net/802/hippi.c
F: drivers/net/hippi/
+HISILICON LPC BUS DRIVER
+M: Zhichang Yuan <yuanzhichang@hisilicon.com>
+L: linux-arm-kernel at lists.infradead.org
+W: http://www.hisilicon.com
+S: Maintained
+F: drivers/bus/hisi_lpc.c
+F: Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
+
HISILICON NETWORK SUBSYSTEM DRIVER
M: Yisen Zhuang <yisen.zhuang@huawei.com>
M: Salil Mehta <salil.mehta@huawei.com>
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 7010dca..a108abc 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -64,6 +64,14 @@ config BRCMSTB_GISB_ARB
arbiter. This driver provides timeout and target abort error handling
and internal bus master decoding.
+config HISILICON_LPC
+ bool "Workaround for nonstandard ISA I/O space on Hisilicon Hip0X"
+ depends on (ARCH_HISI || COMPILE_TEST) && ARM64
+ select ARM64_INDIRECT_PIO
+ help
+ Driver needed for some legacy ISA devices attached to Low-Pin-Count
+ on Hisilicon Hip0X SoC.
+
config IMX_WEIM
bool "Freescale EIM DRIVER"
depends on ARCH_MXC
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index c6cfa6b..10b4983 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_ARM_CCI) += arm-cci.o
obj-$(CONFIG_ARM_CCN) += arm-ccn.o
obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o
+obj-$(CONFIG_HISILICON_LPC) += hisi_lpc.o
obj-$(CONFIG_IMX_WEIM) += imx-weim.o
obj-$(CONFIG_MIPS_CDMM) += mips_cdmm.o
obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o
diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
new file mode 100644
index 0000000..9f48a1a
--- /dev/null
+++ b/drivers/bus/hisi_lpc.c
@@ -0,0 +1,501 @@
+/*
+ * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ * Author: Zou Rongrong <zourongrong@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/acpi.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/serial_8250.h>
+#include <linux/slab.h>
+
+/*
+ * this bit set means each IO operation will target to different port address;
+ * 0 means repeatly IO operations will be sticked on the same port, such as BT;
+ */
+#define FG_INCRADDR_LPC 0x02
+
+struct lpc_cycle_para {
+ unsigned int opflags;
+ unsigned int csize;/* the data length of each operation */
+};
+
+struct hisilpc_dev {
+ spinlock_t cycle_lock;
+ void __iomem *membase;
+ struct extio_ops io_ops;
+};
+
+
+/* The maximum continous operations*/
+#define LPC_MAX_OPCNT 16
+/* only support IO data unit length is four at maximum */
+#define LPC_MAX_DULEN 4
+#if LPC_MAX_DULEN > LPC_MAX_OPCNT
+#error "LPC.. MAX_DULEN must be not bigger than MAX_OPCNT!"
+#endif
+
+#define LPC_REG_START 0x00/* start a new LPC cycle */
+#define LPC_REG_OP_STATUS 0x04/* the current LPC status */
+#define LPC_REG_IRQ_ST 0x08/* interrupt enable&status */
+#define LPC_REG_OP_LEN 0x10/* how many LPC cycles each start */
+#define LPC_REG_CMD 0x14/* command for the required LPC cycle */
+#define LPC_REG_ADDR 0x20/* LPC target address */
+#define LPC_REG_WDATA 0x24/* data to be written */
+#define LPC_REG_RDATA 0x28/* data coming from peer */
+
+
+/* The command register fields*/
+#define LPC_CMD_SAMEADDR 0x08
+#define LPC_CMD_TYPE_IO 0x00
+#define LPC_CMD_WRITE 0x01
+#define LPC_CMD_READ 0x00
+/* the bit attribute is W1C. 1 represents OK. */
+#define LPC_STAT_BYIRQ 0x02
+
+#define LPC_STATUS_IDLE 0x01
+#define LPC_OP_FINISHED 0x02
+
+#define START_WORK 0x01
+
+/*
+ * The minimal waiting interval... Suggest it is not less than 10.
+ * Bigger value probably will lower the performance.
+ */
+#define LPC_NSEC_PERWAIT 100
+/*
+ * The maximum waiting time is about 128us.
+ * The fastest IO cycle time is about 390ns, but the worst case will wait
+ * for extra 256 lpc clocks, so (256 + 13) * 30ns = 8 us. The maximum
+ * burst cycles is 16. So, the maximum waiting time is about 128us under
+ * worst case.
+ * choose 1300 as the maximum.
+ */
+#define LPC_MAX_WAITCNT 1300
+/* About 10us. This is specfic for single IO operation, such as inb. */
+#define LPC_PEROP_WAITCNT 100
+
+
+static inline int wait_lpc_idle(unsigned char *mbase,
+ unsigned int waitcnt) {
+ u32 opstatus;
+
+ while (waitcnt--) {
+ ndelay(LPC_NSEC_PERWAIT);
+ opstatus = readl(mbase + LPC_REG_OP_STATUS);
+ if (opstatus & LPC_STATUS_IDLE)
+ return (opstatus & LPC_OP_FINISHED) ? 0 : (-EIO);
+ }
+ return -ETIME;
+}
+
+
+/**
+ * hisilpc_target_in - trigger a series of lpc cycles to read required data
+ * from target periperal.
+ * @pdev: pointer to hisi lpc device
+ * @para: some paramerters used to control the lpc I/O operations
+ * @ptaddr: the lpc I/O target port address
+ * @buf: where the read back data is stored
+ * @opcnt: how many I/O operations required in this calling
+ *
+ * only one byte data is read each I/O operation.
+ *
+ * Returns 0 on success, non-zero on fail.
+ *
+ */
+static int hisilpc_target_in(struct hisilpc_dev *pdev,
+ struct lpc_cycle_para *para,
+ unsigned long ptaddr, unsigned char *buf,
+ unsigned long opcnt)
+{
+ unsigned int cmd_word;
+ unsigned int waitcnt;
+ int retval;
+ unsigned long flags;
+ unsigned long cnt_per_trans;
+
+ if (!buf || !opcnt || !para || !para->csize || !pdev)
+ return -EINVAL;
+
+ if (opcnt > LPC_MAX_OPCNT)
+ return -EINVAL;
+
+ cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_READ;
+ waitcnt = (LPC_PEROP_WAITCNT);
+ if (!(para->opflags & FG_INCRADDR_LPC)) {
+ cmd_word |= LPC_CMD_SAMEADDR;
+ waitcnt = LPC_MAX_WAITCNT;
+ }
+
+ retval = 0;
+ cnt_per_trans = (para->csize == 1) ? opcnt : para->csize;
+ for (; opcnt && !retval; cnt_per_trans = para->csize) {
+ /* whole operation must be atomic */
+ spin_lock_irqsave(&pdev->cycle_lock, flags);
+
+ writel(cnt_per_trans, pdev->membase + LPC_REG_OP_LEN);
+
+ writel(cmd_word, pdev->membase + LPC_REG_CMD);
+
+ writel(ptaddr, pdev->membase + LPC_REG_ADDR);
+
+ writel(START_WORK, pdev->membase + LPC_REG_START);
+
+ /* whether the operation is finished */
+ retval = wait_lpc_idle(pdev->membase, waitcnt);
+ if (!retval) {
+ opcnt -= cnt_per_trans;
+ for (; cnt_per_trans--; buf++)
+ *buf = readl(pdev->membase + LPC_REG_RDATA);
+ }
+
+ spin_unlock_irqrestore(&pdev->cycle_lock, flags);
+ }
+
+ return retval;
+}
+
+/**
+ * hisilpc_target_out - trigger a series of lpc cycles to write required data
+ * to target periperal.
+ * @pdev: pointer to hisi lpc device
+ * @para: some paramerters used to control the lpc I/O operations
+ * @ptaddr: the lpc I/O target port address
+ * @buf: where the data to be written is stored
+ * @opcnt: how many I/O operations required
+ *
+ * only one byte data is read each I/O operation.
+ *
+ * Returns 0 on success, non-zero on fail.
+ *
+ */
+static int hisilpc_target_out(struct hisilpc_dev *pdev,
+ struct lpc_cycle_para *para,
+ unsigned long ptaddr,
+ const unsigned char *buf,
+ unsigned long opcnt)
+{
+ unsigned int cmd_word;
+ unsigned int waitcnt;
+ int retval;
+ unsigned long flags;
+ unsigned long cnt_per_trans;
+
+ if (!buf || !opcnt || !para || !pdev)
+ return -EINVAL;
+
+ if (opcnt > LPC_MAX_OPCNT)
+ return -EINVAL;
+ /* default is increasing address */
+ cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_WRITE;
+ waitcnt = (LPC_PEROP_WAITCNT);
+ if (!(para->opflags & FG_INCRADDR_LPC)) {
+ cmd_word |= LPC_CMD_SAMEADDR;
+ waitcnt = LPC_MAX_WAITCNT;
+ }
+
+ retval = 0;
+ cnt_per_trans = (para->csize == 1) ? opcnt : para->csize;
+ for (; opcnt && !retval; cnt_per_trans = para->csize) {
+ spin_lock_irqsave(&pdev->cycle_lock, flags);
+
+ writel(cnt_per_trans, pdev->membase + LPC_REG_OP_LEN);
+ opcnt -= cnt_per_trans;
+ for (; cnt_per_trans--; buf++)
+ writel(*buf, pdev->membase + LPC_REG_WDATA);
+
+ writel(cmd_word, pdev->membase + LPC_REG_CMD);
+
+ writel(ptaddr, pdev->membase + LPC_REG_ADDR);
+
+ writel(START_WORK, pdev->membase + LPC_REG_START);
+
+ /* whether the operation is finished */
+ retval = wait_lpc_idle(pdev->membase, waitcnt);
+
+ spin_unlock_irqrestore(&pdev->cycle_lock, flags);
+ }
+
+ return retval;
+}
+
+
+/**
+ * hisilpc_comm_in - read/input the data from the I/O peripheral through LPC.
+ * @devobj: pointer to the device information relevant to LPC controller.
+ * @ptaddr: the target I/O port address.
+ * @dlen: the data length required to read from the target I/O port.
+ *
+ * when succeed, the data read back is stored in buffer pointed by inbuf.
+ * For inb, return the data read from I/O or -1 when error occur.
+ */
+static u64 hisilpc_comm_in(void *devobj, unsigned long ptaddr, size_t dlen)
+{
+ struct hisilpc_dev *lpcdev;
+ struct lpc_cycle_para iopara;
+ u32 rd_data;
+ unsigned char *newbuf;
+ int ret = 0;
+
+ if (!devobj || !dlen || dlen > LPC_MAX_DULEN || (dlen & (dlen - 1)))
+ return -1;
+
+ /* the local buffer must be enough for one data unit */
+ if (sizeof(rd_data) < dlen)
+ return -1;
+
+ newbuf = (unsigned char *)&rd_data;
+
+ lpcdev = (struct hisilpc_dev *)devobj;
+
+ iopara.opflags = FG_INCRADDR_LPC;
+ iopara.csize = dlen;
+
+ ret = hisilpc_target_in(lpcdev, &iopara, ptaddr, newbuf, dlen);
+ if (ret)
+ return -1;
+
+ return le32_to_cpu(rd_data);
+}
+
+/**
+ * hisilpc_comm_out - write/output the data whose maximal length is four bytes to
+ * the I/O peripheral through LPC.
+ * @devobj: pointer to the device information relevant to LPC controller.
+ * @outval: a value to be outputed from caller, maximum is four bytes.
+ * @ptaddr: the target I/O port address.
+ * @dlen: the data length required writing to the target I/O port .
+ *
+ * This function is corresponding to out(b,w,l) only
+ *
+ */
+static void hisilpc_comm_out(void *devobj, unsigned long ptaddr,
+ u32 outval, size_t dlen)
+{
+ struct hisilpc_dev *lpcdev;
+ struct lpc_cycle_para iopara;
+ const unsigned char *newbuf;
+
+ if (!devobj || !dlen || dlen > LPC_MAX_DULEN)
+ return;
+
+ if (sizeof(outval) < dlen)
+ return;
+
+ outval = cpu_to_le32(outval);
+
+ newbuf = (const unsigned char *)&outval;
+ lpcdev = (struct hisilpc_dev *)devobj;
+
+ iopara.opflags = FG_INCRADDR_LPC;
+ iopara.csize = dlen;
+
+ hisilpc_target_out(lpcdev, &iopara, ptaddr, newbuf, dlen);
+}
+
+
+/**
+ * hisilpc_comm_ins - read/input the data in buffer to the I/O peripheral
+ * through LPC, it corresponds to ins(b,w,l)
+ * @devobj: pointer to the device information relevant to LPC controller.
+ * @ptaddr: the target I/O port address.
+ * @inbuf: a buffer where read/input data bytes are stored.
+ * @dlen: the data length required writing to the target I/O port .
+ * @count: how many data units whose length is dlen will be read.
+ *
+ */
+static u64 hisilpc_comm_ins(void *devobj, unsigned long ptaddr,
+ void *inbuf, size_t dlen, unsigned int count)
+{
+ struct hisilpc_dev *lpcdev;
+ struct lpc_cycle_para iopara;
+ unsigned char *newbuf;
+ unsigned int loopcnt, cntleft;
+ unsigned int max_perburst;
+ int ret = 0;
+
+ if (!devobj || !inbuf || !count || !dlen ||
+ dlen > LPC_MAX_DULEN || (dlen & (dlen - 1)))
+ return -1;
+
+ iopara.opflags = 0;
+ if (dlen > 1)
+ iopara.opflags |= FG_INCRADDR_LPC;
+ iopara.csize = dlen;
+
+ lpcdev = (struct hisilpc_dev *)devobj;
+ newbuf = (unsigned char *)inbuf;
+ /*
+ * ensure data stream whose lenght is multiple of dlen to be processed
+ * each IO input
+ */
+ max_perburst = LPC_MAX_OPCNT & (~(dlen - 1));
+ cntleft = count * dlen;
+ do {
+ loopcnt = (cntleft >= max_perburst) ? max_perburst : cntleft;
+ ret = hisilpc_target_in(lpcdev, &iopara, ptaddr, newbuf,
+ loopcnt);
+ if (ret)
+ break;
+ newbuf += loopcnt;
+ cntleft -= loopcnt;
+ } while (cntleft);
+
+ return ret;
+}
+
+/**
+ * hisilpc_comm_outs - write/output the data in buffer to the I/O peripheral
+ * through LPC, it corresponds to outs(b,w,l)
+ * @devobj: pointer to the device information relevant to LPC controller.
+ * @ptaddr: the target I/O port address.
+ * @outbuf: a buffer where write/output data bytes are stored.
+ * @dlen: the data length required writing to the target I/O port .
+ * @count: how many data units whose length is dlen will be written.
+ *
+ */
+static void hisilpc_comm_outs(void *devobj, unsigned long ptaddr,
+ const void *outbuf, size_t dlen, unsigned int count)
+{
+ struct hisilpc_dev *lpcdev;
+ struct lpc_cycle_para iopara;
+ const unsigned char *newbuf;
+ unsigned int loopcnt, cntleft;
+ unsigned int max_perburst;
+ int ret = 0;
+
+ if (!devobj || !outbuf || !count || !dlen ||
+ dlen > LPC_MAX_DULEN || (dlen & (dlen - 1)))
+ return;
+
+ iopara.opflags = 0;
+ if (dlen > 1)
+ iopara.opflags |= FG_INCRADDR_LPC;
+ iopara.csize = dlen;
+
+ lpcdev = (struct hisilpc_dev *)devobj;
+ newbuf = (unsigned char *)outbuf;
+ /*
+ * ensure data stream whose lenght is multiple of dlen to be processed
+ * each IO input
+ */
+ max_perburst = LPC_MAX_OPCNT & (~(dlen - 1));
+ cntleft = count * dlen;
+ do {
+ loopcnt = (cntleft >= max_perburst) ? max_perburst : cntleft;
+ ret = hisilpc_target_out(lpcdev, &iopara, ptaddr, newbuf,
+ loopcnt);
+ if (ret)
+ break;
+ newbuf += loopcnt;
+ cntleft -= loopcnt;
+ } while (cntleft);
+}
+
+
+/**
+ * hisilpc_probe - the probe callback function for hisi lpc device,
+ * will finish all the intialization.
+ * @pdev: the platform device corresponding to hisi lpc
+ *
+ * Returns 0 on success, non-zero on fail.
+ *
+ */
+static int hisilpc_probe(struct platform_device *pdev)
+{
+ struct resource *iores;
+ struct hisilpc_dev *lpcdev;
+ int ret;
+
+ dev_info(&pdev->dev, "hslpc start probing...\n");
+
+ lpcdev = devm_kzalloc(&pdev->dev,
+ sizeof(struct hisilpc_dev), GFP_KERNEL);
+ if (!lpcdev)
+ return -ENOMEM;
+
+ spin_lock_init(&lpcdev->cycle_lock);
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ lpcdev->membase = devm_ioremap_resource(&pdev->dev, iores);
+ if (IS_ERR(lpcdev->membase)) {
+ dev_err(&pdev->dev, "No mem resource for memory mapping!\n");
+ return PTR_ERR(lpcdev->membase);
+ }
+ /*
+ * The first PCIBIOS_MIN_IO is reserved specific for indirectIO.
+ * It will separate indirectIO range from pci host bridge to
+ * avoid the possible PIO conflict.
+ * Set the indirectIO range directly here.
+ */
+ lpcdev->io_ops.start = 0;
+ lpcdev->io_ops.end = PCIBIOS_MIN_IO - 1;
+ lpcdev->io_ops.devpara = lpcdev;
+ lpcdev->io_ops.pfin = hisilpc_comm_in;
+ lpcdev->io_ops.pfout = hisilpc_comm_out;
+ lpcdev->io_ops.pfins = hisilpc_comm_ins;
+ lpcdev->io_ops.pfouts = hisilpc_comm_outs;
+
+ platform_set_drvdata(pdev, lpcdev);
+
+ arm64_set_extops(&lpcdev->io_ops);
+
+ /*
+ * The children scanning is only for dts mode. For ACPI children,
+ * the corresponding devices had be created during acpi scanning.
+ */
+ ret = 0;
+ if (!has_acpi_companion(&pdev->dev))
+ ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
+ if (!ret)
+ dev_info(&pdev->dev, "hslpc end probing. range[0x%lx - %lx]\n",
+ arm64_extio_ops->start, arm64_extio_ops->end);
+ else
+ dev_info(&pdev->dev, "hslpc probing is fail(%d)\n", ret);
+
+ return ret;
+}
+
+static const struct of_device_id hisilpc_of_match[] = {
+ {
+ .compatible = "hisilicon,low-pin-count",
+ },
+ {},
+};
+
+static const struct acpi_device_id hisilpc_acpi_match[] = {
+ {"HISI0191", },
+ {},
+};
+
+static struct platform_driver hisilpc_driver = {
+ .driver = {
+ .name = "hisi_lpc",
+ .of_match_table = hisilpc_of_match,
+ .acpi_match_table = hisilpc_acpi_match,
+ },
+ .probe = hisilpc_probe,
+};
+
+
+builtin_platform_driver(hisilpc_driver);
--
1.9.1
^ permalink raw reply related
* [PATCH V4 2/3] ARM64 LPC: Add missing range exception for special ISA
From: zhichang.yuan @ 2016-10-20 9:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476954940-242159-1-git-send-email-yuanzhichang@hisilicon.com>
Currently if the range property is not specified of_translate_one
returns an error. There are some special devices that work on a
range of I/O ports where it's is not correct to specify a range
property as the cpu addresses are used by special accessors.
Here we add a new exception in of_translate_one to return
the cpu address if the range property is not there. The exception
checks if the parent bus is ISA and if the special accessors are
defined.
Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
arch/arm64/include/asm/io.h | 7 +++++++
arch/arm64/kernel/extio.c | 24 +++++++++++++++++++++++
drivers/of/address.c | 47 +++++++++++++++++++++++++++++++++++++++++++--
drivers/pci/pci.c | 6 +++---
include/linux/of_address.h | 17 ++++++++++++++++
5 files changed, 96 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 136735d..e480199 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -175,6 +175,13 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
#define outsl outsl
DECLARE_EXTIO(l, u32)
+
+
+#define indirect_io_ison indirect_io_ison
+extern int indirect_io_ison(void);
+
+#define chk_indirect_range chk_indirect_range
+extern int chk_indirect_range(u64 taddr);
#endif
diff --git a/arch/arm64/kernel/extio.c b/arch/arm64/kernel/extio.c
index 80cafd5..55df8dc 100644
--- a/arch/arm64/kernel/extio.c
+++ b/arch/arm64/kernel/extio.c
@@ -19,6 +19,30 @@
struct extio_ops *arm64_extio_ops;
+/**
+ * indirect_io_ison - check whether indirectIO can work well. This function only call
+ * before the target I/O address was obtained.
+ *
+ * Returns 1 when indirectIO can work.
+ */
+int indirect_io_ison()
+{
+ return arm64_extio_ops ? 1 : 0;
+}
+
+/**
+ * check_indirect_io - check whether the input taddr is for indirectIO.
+ * @taddr: the io address to be checked.
+ *
+ * Returns 1 when taddr is in the range; otherwise return 0.
+ */
+int chk_indirect_range(u64 taddr)
+{
+ if (arm64_extio_ops->start > taddr || arm64_extio_ops->end < taddr)
+ return 0;
+
+ return 1;
+}
BUILD_EXTIO(b, u8)
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 02b2903..0bee822 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -479,6 +479,39 @@ static int of_empty_ranges_quirk(struct device_node *np)
return false;
}
+
+/*
+ * Check whether the current device being translating use indirectIO.
+ *
+ * return 1 if the check is past, or 0 represents fail checking.
+ */
+static int of_isa_indirect_io(struct device_node *parent,
+ struct of_bus *bus, __be32 *addr,
+ int na, u64 *presult)
+{
+ unsigned int flags;
+ unsigned int rlen;
+
+ /* whether support indirectIO */
+ if (!indirect_io_ison())
+ return 0;
+
+ if (!of_bus_isa_match(parent))
+ return 0;
+
+ flags = bus->get_flags(addr);
+ if (!(flags & IORESOURCE_IO))
+ return 0;
+
+ /* there is ranges property, apply the normal translation directly. */
+ if (of_get_property(parent, "ranges", &rlen))
+ return 0;
+
+ *presult = of_read_number(addr + 1, na - 1);
+
+ return chk_indirect_range(*presult);
+}
+
static int of_translate_one(struct device_node *parent, struct of_bus *bus,
struct of_bus *pbus, __be32 *addr,
int na, int ns, int pna, const char *rprop)
@@ -532,7 +565,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
}
memcpy(addr, ranges + na, 4 * pna);
- finish:
+finish:
of_dump_addr("parent translation for:", addr, pna);
pr_debug("with offset: %llx\n", (unsigned long long)offset);
@@ -595,6 +628,15 @@ static u64 __of_translate_address(struct device_node *dev,
result = of_read_number(addr, na);
break;
}
+ /*
+ * For indirectIO device which has no ranges property, get
+ * the address from reg directly.
+ */
+ if (of_isa_indirect_io(dev, bus, addr, na, &result)) {
+ pr_info("isa indirectIO matched(%s)..addr = 0x%llx\n",
+ of_node_full_name(dev), result);
+ break;
+ }
/* Get new parent bus and counts */
pbus = of_match_bus(parent);
@@ -688,8 +730,9 @@ static int __of_address_to_resource(struct device_node *dev,
if (taddr == OF_BAD_ADDR)
return -EINVAL;
memset(r, 0, sizeof(struct resource));
- if (flags & IORESOURCE_IO) {
+ if (flags & IORESOURCE_IO && taddr >= PCIBIOS_MIN_IO) {
unsigned long port;
+
port = pci_address_to_pio(taddr);
if (port == (unsigned long)-1)
return -EINVAL;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index ba34907..1a08511 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3263,7 +3263,7 @@ int __weak pci_register_io_range(phys_addr_t addr, resource_size_t size)
#ifdef PCI_IOBASE
struct io_range *range;
- resource_size_t allocated_size = 0;
+ resource_size_t allocated_size = PCIBIOS_MIN_IO;
/* check if the range hasn't been previously recorded */
spin_lock(&io_range_lock);
@@ -3312,7 +3312,7 @@ phys_addr_t pci_pio_to_address(unsigned long pio)
#ifdef PCI_IOBASE
struct io_range *range;
- resource_size_t allocated_size = 0;
+ resource_size_t allocated_size = PCIBIOS_MIN_IO;
if (pio > IO_SPACE_LIMIT)
return address;
@@ -3335,7 +3335,7 @@ unsigned long __weak pci_address_to_pio(phys_addr_t address)
{
#ifdef PCI_IOBASE
struct io_range *res;
- resource_size_t offset = 0;
+ resource_size_t offset = PCIBIOS_MIN_IO;
unsigned long addr = -1;
spin_lock(&io_range_lock);
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 3786473..0ba7e21 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -24,6 +24,23 @@ struct of_pci_range {
#define for_each_of_pci_range(parser, range) \
for (; of_pci_range_parser_one(parser, range);)
+
+#ifndef indirect_io_ison
+#define indirect_io_ison indirect_io_ison
+static inline int indirect_io_ison(void)
+{
+ return 0;
+}
+#endif
+
+#ifndef chk_indirect_range
+#define chk_indirect_range chk_indirect_range
+static inline int chk_indirect_range(u64 taddr)
+{
+ return 0;
+}
+#endif
+
/* Translate a DMA address from device space to CPU space */
extern u64 of_translate_dma_address(struct device_node *dev,
const __be32 *in_addr);
--
1.9.1
^ permalink raw reply related
* [PATCH V4 1/3] ARM64 LPC: Indirect ISA port IO introduced
From: zhichang.yuan @ 2016-10-20 9:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476954940-242159-1-git-send-email-yuanzhichang@hisilicon.com>
For arm64, there is no I/O space as other architectural platforms, such as
X86. Most I/O accesses are achieved based on MMIO. But for some arm64 SoCs,
such as Hip06, when accessing some legacy ISA devices connected to LPC, those
known port addresses are used to control the corresponding target devices, for
example, 0x2f8 is for UART, 0xe4 is for ipmi-bt. It is different from the
normal MMIO mode in using.
To drive these devices, this patch introduces a method named indirect-IO.
In this method the in/out pair in arch/arm64/include/asm/io.h will be
redefined. When upper layer drivers call in/out with those known legacy port
addresses to access the peripherals, the hooking functions corrresponding to
those target peripherals will be called. Through this way, those upper layer
drivers which depend on in/out can run on Hip06 without any changes.
Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
arch/arm64/Kconfig | 6 +++
arch/arm64/include/asm/extio.h | 94 ++++++++++++++++++++++++++++++++++++++++++
arch/arm64/include/asm/io.h | 29 +++++++++++++
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/extio.c | 29 +++++++++++++
5 files changed, 159 insertions(+)
create mode 100644 arch/arm64/include/asm/extio.h
create mode 100644 arch/arm64/kernel/extio.c
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 30398db..103dbea 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -163,6 +163,12 @@ config ARCH_MMAP_RND_COMPAT_BITS_MIN
config ARCH_MMAP_RND_COMPAT_BITS_MAX
default 16
+config ARM64_INDIRECT_PIO
+ bool "access peripherals with legacy I/O port"
+ help
+ Support special accessors for ISA I/O devices. This is needed for
+ SoCs that do not support standard read/write for the ISA range.
+
config NO_IOPORT_MAP
def_bool y if !PCI
diff --git a/arch/arm64/include/asm/extio.h b/arch/arm64/include/asm/extio.h
new file mode 100644
index 0000000..6ae0787
--- /dev/null
+++ b/arch/arm64/include/asm/extio.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LINUX_EXTIO_H
+#define __LINUX_EXTIO_H
+
+struct extio_ops {
+ unsigned long start;/* inclusive, sys io addr */
+ unsigned long end;/* inclusive, sys io addr */
+
+ u64 (*pfin)(void *devobj, unsigned long ptaddr, size_t dlen);
+ void (*pfout)(void *devobj, unsigned long ptaddr, u32 outval,
+ size_t dlen);
+ u64 (*pfins)(void *devobj, unsigned long ptaddr, void *inbuf,
+ size_t dlen, unsigned int count);
+ void (*pfouts)(void *devobj, unsigned long ptaddr,
+ const void *outbuf, size_t dlen,
+ unsigned int count);
+ void *devpara;
+};
+
+extern struct extio_ops *arm64_extio_ops;
+
+#define DECLARE_EXTIO(bw, type) \
+extern type in##bw(unsigned long addr); \
+extern void out##bw(type value, unsigned long addr); \
+extern void ins##bw(unsigned long addr, void *buffer, unsigned int count);\
+extern void outs##bw(unsigned long addr, const void *buffer, unsigned int count);
+
+#define BUILD_EXTIO(bw, type) \
+type in##bw(unsigned long addr) \
+{ \
+ if (!arm64_extio_ops || arm64_extio_ops->start > addr || \
+ arm64_extio_ops->end < addr) \
+ return read##bw(PCI_IOBASE + addr); \
+ return arm64_extio_ops->pfin ? \
+ arm64_extio_ops->pfin(arm64_extio_ops->devpara, \
+ addr, sizeof(type)) : -1; \
+} \
+ \
+void out##bw(type value, unsigned long addr) \
+{ \
+ if (!arm64_extio_ops || arm64_extio_ops->start > addr || \
+ arm64_extio_ops->end < addr) \
+ write##bw(value, PCI_IOBASE + addr); \
+ else \
+ if (arm64_extio_ops->pfout) \
+ arm64_extio_ops->pfout(arm64_extio_ops->devpara,\
+ addr, value, sizeof(type)); \
+} \
+ \
+void ins##bw(unsigned long addr, void *buffer, unsigned int count) \
+{ \
+ if (!arm64_extio_ops || arm64_extio_ops->start > addr || \
+ arm64_extio_ops->end < addr) \
+ reads##bw(PCI_IOBASE + addr, buffer, count); \
+ else \
+ if (arm64_extio_ops->pfins) \
+ arm64_extio_ops->pfins(arm64_extio_ops->devpara,\
+ addr, buffer, sizeof(type), count); \
+} \
+ \
+void outs##bw(unsigned long addr, const void *buffer, unsigned int count) \
+{ \
+ if (!arm64_extio_ops || arm64_extio_ops->start > addr || \
+ arm64_extio_ops->end < addr) \
+ writes##bw(PCI_IOBASE + addr, buffer, count); \
+ else \
+ if (arm64_extio_ops->pfouts) \
+ arm64_extio_ops->pfouts(arm64_extio_ops->devpara,\
+ addr, buffer, sizeof(type), count); \
+}
+
+static inline void arm64_set_extops(struct extio_ops *ops)
+{
+ if (ops)
+ WRITE_ONCE(arm64_extio_ops, ops);
+}
+
+#endif /* __LINUX_EXTIO_H*/
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 0bba427..136735d 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -31,6 +31,7 @@
#include <asm/early_ioremap.h>
#include <asm/alternative.h>
#include <asm/cpufeature.h>
+#include <asm/extio.h>
#include <xen/xen.h>
@@ -149,6 +150,34 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
#define IO_SPACE_LIMIT (PCI_IO_SIZE - 1)
#define PCI_IOBASE ((void __iomem *)PCI_IO_START)
+
+/*
+ * redefine the in(s)b/out(s)b for indirect-IO.
+ */
+#ifdef CONFIG_ARM64_INDIRECT_PIO
+#define inb inb
+#define outb outb
+#define insb insb
+#define outsb outsb
+/* external declaration */
+DECLARE_EXTIO(b, u8)
+
+#define inw inw
+#define outw outw
+#define insw insw
+#define outsw outsw
+
+DECLARE_EXTIO(w, u16)
+
+#define inl inl
+#define outl outl
+#define insl insl
+#define outsl outsl
+
+DECLARE_EXTIO(l, u32)
+#endif
+
+
/*
* String version of I/O memory access operations.
*/
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 7d66bba..60e0482 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -31,6 +31,7 @@ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
sys_compat.o entry32.o
arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
+arm64-obj-$(CONFIG_ARM64_INDIRECT_PIO) += extio.o
arm64-obj-$(CONFIG_ARM64_MODULE_PLTS) += module-plts.o
arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
diff --git a/arch/arm64/kernel/extio.c b/arch/arm64/kernel/extio.c
new file mode 100644
index 0000000..80cafd5
--- /dev/null
+++ b/arch/arm64/kernel/extio.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/io.h>
+
+struct extio_ops *arm64_extio_ops;
+
+
+BUILD_EXTIO(b, u8)
+
+BUILD_EXTIO(w, u16)
+
+BUILD_EXTIO(l, u32)
+
+#endif
--
1.9.1
^ 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