Re: [PATCH] phy: amlogic: Replace devm_reset_control_array_get()

2020-11-03 Thread Remi Pommarel
Hi

On Tue, Nov 03, 2020 at 12:37:54PM +0800, Yejune Deng wrote:
> devm_reset_control_array_get_exclusive() looks more readable
> 
> Signed-off-by: Yejune Deng 

Reviewed-by: Remi Pommarel  for phy-meson-axg-pcie

Thanks.


Re: [PATCH 02/17] phy: amlogic: convert to devm_platform_ioremap_resource

2020-10-29 Thread Remi Pommarel
l-usb2.c 
> b/drivers/phy/amlogic/phy-meson-gxl-usb2.c
> index 43ec9bf24abf..875afb2672c7 100644
> --- a/drivers/phy/amlogic/phy-meson-gxl-usb2.c
> +++ b/drivers/phy/amlogic/phy-meson-gxl-usb2.c
> @@ -230,7 +230,6 @@ static int phy_meson_gxl_usb2_probe(struct 
> platform_device *pdev)
>  {
>   struct device *dev = >dev;
>   struct phy_provider *phy_provider;
> - struct resource *res;
>   struct phy_meson_gxl_usb2_priv *priv;
>   struct phy *phy;
>   void __iomem *base;
> @@ -242,8 +241,7 @@ static int phy_meson_gxl_usb2_probe(struct 
> platform_device *pdev)
>  
>   platform_set_drvdata(pdev, priv);
>  
> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - base = devm_ioremap_resource(dev, res);
> + base = devm_platform_ioremap_resource(pdev, 0);
>   if (IS_ERR(base))
>   return PTR_ERR(base);
>  

So without the modification on phy-meson-axg-mipi-pcie-analog.c and
FWIW,

Reviewed-by: Remi Pommarel 

Thanks,

[0] 
https://patchwork.kernel.org/project/linux-amlogic/patch/20200915130339.11079-4-narmstr...@baylibre.com/

-- 
Remi


Re: [PATCH 3/3] phy: amlogic: phy-meson-axg-mipi-pcie-analog: add support for MIPI DSI analog

2020-09-08 Thread Remi Pommarel
Hi,

On Mon, Sep 07, 2020 at 09:34:02AM +0200, Neil Armstrong wrote:
> The AXG Analog MIPI-DSI PHY also provides functions to the PCIe PHY,
> thus we need to have inclusive support for both interfaces at runtime.
> 
> This fixes the regmap get from parent node, removes cell param
> to select a mode and implement runtime configuration & power on/off
> for both functions since they are not exclusive.
> 
> Signed-off-by: Neil Armstrong 
> ---
>  drivers/phy/amlogic/Kconfig   |   1 +
>  .../amlogic/phy-meson-axg-mipi-pcie-analog.c  | 204 --
>  2 files changed, 136 insertions(+), 69 deletions(-)
> 
> diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
> index 99e8a4c7f1f3..db5d0cd757e3 100644
> --- a/drivers/phy/amlogic/Kconfig
> +++ b/drivers/phy/amlogic/Kconfig
> @@ -66,6 +66,7 @@ config PHY_MESON_AXG_MIPI_PCIE_ANALOG
>   depends on OF && (ARCH_MESON || COMPILE_TEST)
>   select GENERIC_PHY
>   select REGMAP_MMIO
> + select GENERIC_PHY_MIPI_DPHY
>   help
> Enable this to support the Meson MIPI + PCIE analog PHY
> found in Meson AXG SoCs.
> diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c 
> b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> index 1431cbf885e1..6eb21551bdd9 100644
> --- a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> +++ b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> @@ -4,9 +4,13 @@
>   *
>   * Copyright (C) 2019 Remi Pommarel 
>   */
> +#include 
> +#include 
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
>  #include 
>  #include 
>  
> @@ -14,10 +18,10 @@
>  #define  HHI_MIPI_CNTL0_COMMON_BLOCK GENMASK(31, 28)
>  #define  HHI_MIPI_CNTL0_ENABLE   BIT(29)
>  #define  HHI_MIPI_CNTL0_BANDGAP  BIT(26)
> -#define  HHI_MIPI_CNTL0_DECODE_TO_RTERM  GENMASK(15, 12)
> -#define  HHI_MIPI_CNTL0_OUTPUT_ENBIT(3)
> +#define  HHI_MIPI_CNTL0_DIF_REF_CTL1 GENMASK(25, 16)
> +#define  HHI_MIPI_CNTL0_DIF_REF_CTL0 GENMASK(15, 0)
>  
> -#define HHI_MIPI_CNTL1 0x01
> +#define HHI_MIPI_CNTL1 0x04
>  #define  HHI_MIPI_CNTL1_CH0_CML_PDR_EN   BIT(12)
>  #define  HHI_MIPI_CNTL1_LP_ABILITY   GENMASK(5, 4)
>  #define  HHI_MIPI_CNTL1_LP_RESISTER  BIT(3)
> @@ -25,100 +29,170 @@
>  #define  HHI_MIPI_CNTL1_INPUT_SELBIT(1)
>  #define  HHI_MIPI_CNTL1_PRBS7_EN BIT(0)
>  
> -#define HHI_MIPI_CNTL2 0x02
> +#define HHI_MIPI_CNTL2 0x08
>  #define  HHI_MIPI_CNTL2_CH_PUGENMASK(31, 25)
>  #define  HHI_MIPI_CNTL2_CH_CTL   GENMASK(24, 19)
>  #define  HHI_MIPI_CNTL2_CH0_DIGDR_EN BIT(18)
>  #define  HHI_MIPI_CNTL2_CH_DIGDR_EN  BIT(17)
>  #define  HHI_MIPI_CNTL2_LPULPS_ENBIT(16)
> -#define  HHI_MIPI_CNTL2_CH_EN(n) BIT(15 - (n))
> +#define  HHI_MIPI_CNTL2_CH_ENGENMASK(15, 11)
>  #define  HHI_MIPI_CNTL2_CH0_LP_CTL   GENMASK(10, 1)
>  
> +#define DSI_LANE_0  (1 << 4)
> +#define DSI_LANE_1  (1 << 3)
> +#define DSI_LANE_CLK(1 << 2)
> +#define DSI_LANE_2  (1 << 1)
> +#define DSI_LANE_3  (1 << 0)
> +#define DSI_LANE_MASK(0x1F)
> +
>  struct phy_axg_mipi_pcie_analog_priv {
>   struct phy *phy;
> - unsigned int mode;
>   struct regmap *regmap;
> + bool dsi_configured;
> + bool dsi_enabled;
> + bool powered;
> + struct phy_configure_opts_mipi_dphy config;
>  };
>  
> -static const struct regmap_config phy_axg_mipi_pcie_analog_regmap_conf = {
> - .reg_bits = 8,
> - .val_bits = 32,
> - .reg_stride = 4,
> - .max_register = HHI_MIPI_CNTL2,
> -};
> +static void phy_bandgap_enable(struct phy_axg_mipi_pcie_analog_priv *priv)
> +{
> + regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> + HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);
>  
> -static int phy_axg_mipi_pcie_analog_power_on(struct phy *phy)
> + regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> + HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
> +}
> +
> +static void phy_bandgap_disable(struct phy_axg_mipi_pcie_analog_priv *priv)
>  {
> - struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
> + regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> + HHI_MIPI_CNTL0_BANDGAP, 0);
> 

[PATCH] mac80211: mesh: Free pending skb when destroying a mpath

2020-07-04 Thread Remi Pommarel
A mpath object can hold reference on a list of skb that are waiting for
mpath resolution to be sent. When destroying a mpath this skb list
should be cleaned up in order to not leak memory.

Fixing that kind of leak:

unreferenced object 0x181c9300 (size 1088):
  comm "openvpn", pid 1782, jiffies 4295071698 (age 80.416s)
  hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 f9 80 36 00 00 00 00 00  ..6.
02 00 07 40 00 00 00 00 00 00 00 00 00 00 00 00  ...@
  backtrace:
[<4bc6a443>] kmem_cache_alloc+0x1a4/0x2f0
[<2caaef13>] sk_prot_alloc.isra.39+0x34/0x178
[<ceeaa916>] sk_alloc+0x34/0x228
[<ca1f1d04>] inet_create+0x198/0x518
[<35626b1c>] __sock_create+0x134/0x328
[<a12b3a87>] __sys_socket+0xb0/0x158
[<ff859f23>] __arm64_sys_socket+0x40/0x58
[<263486ec>] el0_svc_handler+0xd0/0x1a0
[<05b5157d>] el0_svc+0x8/0xc
unreferenced object 0x12973a40 (size 216):
  comm "openvpn", pid 1782, jiffies 4295082137 (age 38.660s)
  hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
00 c0 06 16 00 00 ff ff 00 93 1c 18 00 00 ff ff  
  backtrace:
[<4bc6a443>] kmem_cache_alloc+0x1a4/0x2f0
[<23c8c8f9>] __alloc_skb+0xc0/0x2b8
[<7ad950bb>] alloc_skb_with_frags+0x60/0x320
[<ef90023a>] sock_alloc_send_pskb+0x388/0x3c0
[<104fb1a3>] sock_alloc_send_skb+0x1c/0x28
[<6919d2dd>] __ip_append_data+0xba4/0x11f0
[<83477587>] ip_make_skb+0x14c/0x1a8
[<24f3d592>] udp_sendmsg+0xaf0/0xcf0
[<5aabe255>] inet_sendmsg+0x5c/0x80
[<8651ea08>] __sys_sendto+0x15c/0x218
[<3505c99b>] __arm64_sys_sendto+0x74/0x90
[<263486ec>] el0_svc_handler+0xd0/0x1a0
[<05b5157d>] el0_svc+0x8/0xc

Fixes: 2bdaf386f99c (mac80211: mesh: move path tables into if_mesh)
Signed-off-by: Remi Pommarel 
---
 net/mac80211/mesh_pathtbl.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 117519bf33d6..aca608ae313f 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -521,6 +521,7 @@ static void mesh_path_free_rcu(struct mesh_table *tbl,
del_timer_sync(>timer);
atomic_dec(>u.mesh.mpaths);
atomic_dec(>entries);
+   mesh_path_flush_pending(mpath);
kfree_rcu(mpath, rcu);
 }
 
-- 
2.26.2



[PATCH] mac80211: mesh: Free ie data when leaving mesh

2020-07-04 Thread Remi Pommarel
At ieee80211_join_mesh() some ie data could have been allocated (see
copy_mesh_setup()) and need to be cleaned up when leaving the mesh.

This fixes the following kmemleak report:

unreferenced object 0x116bc600 (size 128):
  comm "wpa_supplicant", pid 608, jiffies 4294898983 (age 293.484s)
  hex dump (first 32 bytes):
30 14 01 00 00 0f ac 04 01 00 00 0f ac 04 01 00  0...
00 0f ac 08 00 00 00 00 c4 65 40 00 00 00 00 00  .e@.
  backtrace:
[<bebe439d>] __kmalloc_track_caller+0x1c0/0x330
[<a349dbe1>] kmemdup+0x28/0x50
[<75d69baa>] ieee80211_join_mesh+0x6c/0x3b8 [mac80211]
[<683bb98b>] __cfg80211_join_mesh+0x1e8/0x4f0 [cfg80211]
[<72cb507f>] nl80211_join_mesh+0x520/0x6b8 [cfg80211]
[<77e9bcf9>] genl_family_rcv_msg+0x374/0x680
[<b1bd936d>] genl_rcv_msg+0x78/0x108
[<22c53788>] netlink_rcv_skb+0xb0/0x1c0
[<11af8ec9>] genl_rcv+0x34/0x48
[<69e41f53>] netlink_unicast+0x268/0x2e8
[<a7517316>] netlink_sendmsg+0x320/0x4c0
[<69cba205>] sys_sendmsg+0x354/0x3a0
[<e06bab0f>] ___sys_sendmsg+0xd8/0x120
[<37340728>] __sys_sendmsg+0xa4/0xf8
[<4fed9776>] __arm64_sys_sendmsg+0x44/0x58
[<1c1e5647>] el0_svc_handler+0xd0/0x1a0

Fixes: c80d545da3f7 (mac80211: Let userspace enable and configure vendor 
specific path selection.)
Signed-off-by: Remi Pommarel 
---
 net/mac80211/cfg.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 9b360544ad6f..1079a07e43e4 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2166,6 +2166,7 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, 
struct net_device *dev)
ieee80211_stop_mesh(sdata);
mutex_lock(>local->mtx);
ieee80211_vif_release_channel(sdata);
+   kfree(sdata->u.mesh.ie);
mutex_unlock(>local->mtx);
 
return 0;
-- 
2.26.2



Re: [PATCH v3] PCI: aardvark: Use LTSSM state to build link training flag

2019-10-14 Thread Remi Pommarel
On Mon, Oct 14, 2019 at 02:45:34PM +0100, Marc Zyngier wrote:
> Hi Remi,
> 
> On 2019-10-14 14:06, Remi Pommarel wrote:
> > Hi Lorenzo, Marc,
> > 
> > On Mon, Oct 14, 2019 at 11:01:29AM +0100, Lorenzo Pieralisi wrote:
> > > On Sun, Oct 13, 2019 at 11:34:15AM +0100, Marc Zyngier wrote:
> > > > On Tue, 1 Oct 2019 09:05:46 +0100
> > > > Andrew Murray  wrote:
> > > >
> > > > Hi Lorenzo,
> > > >
> > > > > On Mon, Sep 30, 2019 at 06:52:30PM +0200, Remi Pommarel wrote:
> > > > > > On Mon, Sep 30, 2019 at 04:40:18PM +0100, Andrew Murray wrote:
> > > > > > > On Wed, May 22, 2019 at 11:33:51PM +0200, Remi Pommarel
> > > wrote:
> > > > > > > > Aardvark's PCI_EXP_LNKSTA_LT flag in its link status
> > > register is not
> > > > > > > > implemented and does not reflect the actual link training
> > > state (the
> > > > > > > > flag is always set to 0). In order to support link
> > > re-training feature
> > > > > > > > this flag has to be emulated. The Link Training and Status
> > > State
> > > > > > > > Machine (LTSSM) flag in Aardvark LMI config register could
> > > be used as
> > > > > > > > a link training indicator. Indeed if the LTSSM is in L0 or
> > > upper state
> > > > > > > > then link training has completed (see [1]).
> > > > > > > >
> > > > > > > > Unfortunately because after asking a link retraining it
> > > takes a while
> > > > > > > > for the LTSSM state to become less than 0x10 (due to L0s
> > > to recovery
> > > > > > > > state transition delays), LTSSM can still be in L0 while
> > > link training
> > > > > > > > has not finished yet. So this waits for link to be in
> > > recovery or lesser
> > > > > > > > state before returning after asking for a link retrain.
> > > > > > > >
> > > > > > > > [1] "PCI Express Base Specification", REV. 4.0
> > > > > > > > PCI Express, February 19 2014, Table 4-14
> > > > > > > >
> > > > > > > > Signed-off-by: Remi Pommarel 
> > > > > > > > ---
> > > > > > > > Changes since v1:
> > > > > > > >   - Rename retraining flag field
> > > > > > > >   - Fix DEVCTL register writing
> > > > > > > >
> > > > > > > > Changes since v2:
> > > > > > > >   - Rewrite patch logic so it is more legible
> > > > > > > >
> > > > > > > > Please note that I will unlikely be able to answer any
> > > comments from May
> > > > > > > > 24th to June 10th.
> > > > > > > > ---
> > > > > > > >  drivers/pci/controller/pci-aardvark.c | 29
> > > ++-
> > > > > > > >  1 file changed, 28 insertions(+), 1 deletion(-)
> > > > > > > >
> > > > > > > > diff --git a/drivers/pci/controller/pci-aardvark.c
> > > b/drivers/pci/controller/pci-aardvark.c
> > > > > > > > index 134e0306ff00..8803083b2174 100644
> > > > > > > > --- a/drivers/pci/controller/pci-aardvark.c
> > > > > > > > +++ b/drivers/pci/controller/pci-aardvark.c
> > > > > > > > @@ -180,6 +180,8 @@
> > > > > > > >  #define LINK_WAIT_MAX_RETRIES  10
> > > > > > > >  #define LINK_WAIT_USLEEP_MIN   9
> > > > > > > >  #define LINK_WAIT_USLEEP_MAX   10
> > > > > > > > +#define RETRAIN_WAIT_MAX_RETRIES   10
> > > > > > > > +#define RETRAIN_WAIT_USLEEP_US 2000
> > > > > > > >
> > > > > > > >  #define MSI_IRQ_NUM32
> > > > > > > >
> > > > > > > > @@ -239,6 +241,17 @@ static int
> > > advk_pcie_wait_for_link(struct advk_pcie *pcie)
> > > > > > > > return -ETIMEDOUT;
> > > > > > > >  }
> > > > > > > >
> > > > > > > > +static void advk_pcie_wait_for_retrain(struct advk_pcie
> > > *pcie)
> > 

Re: [PATCH v3] PCI: aardvark: Use LTSSM state to build link training flag

2019-10-14 Thread Remi Pommarel
Hi Lorenzo, Marc,

On Mon, Oct 14, 2019 at 11:01:29AM +0100, Lorenzo Pieralisi wrote:
> On Sun, Oct 13, 2019 at 11:34:15AM +0100, Marc Zyngier wrote:
> > On Tue, 1 Oct 2019 09:05:46 +0100
> > Andrew Murray  wrote:
> > 
> > Hi Lorenzo,
> > 
> > > On Mon, Sep 30, 2019 at 06:52:30PM +0200, Remi Pommarel wrote:
> > > > On Mon, Sep 30, 2019 at 04:40:18PM +0100, Andrew Murray wrote:  
> > > > > On Wed, May 22, 2019 at 11:33:51PM +0200, Remi Pommarel wrote:  
> > > > > > Aardvark's PCI_EXP_LNKSTA_LT flag in its link status register is not
> > > > > > implemented and does not reflect the actual link training state (the
> > > > > > flag is always set to 0). In order to support link re-training 
> > > > > > feature
> > > > > > this flag has to be emulated. The Link Training and Status State
> > > > > > Machine (LTSSM) flag in Aardvark LMI config register could be used 
> > > > > > as
> > > > > > a link training indicator. Indeed if the LTSSM is in L0 or upper 
> > > > > > state
> > > > > > then link training has completed (see [1]).
> > > > > > 
> > > > > > Unfortunately because after asking a link retraining it takes a 
> > > > > > while
> > > > > > for the LTSSM state to become less than 0x10 (due to L0s to recovery
> > > > > > state transition delays), LTSSM can still be in L0 while link 
> > > > > > training
> > > > > > has not finished yet. So this waits for link to be in recovery or 
> > > > > > lesser
> > > > > > state before returning after asking for a link retrain.
> > > > > > 
> > > > > > [1] "PCI Express Base Specification", REV. 4.0
> > > > > > PCI Express, February 19 2014, Table 4-14
> > > > > > 
> > > > > > Signed-off-by: Remi Pommarel 
> > > > > > ---
> > > > > > Changes since v1:
> > > > > >   - Rename retraining flag field
> > > > > >   - Fix DEVCTL register writing
> > > > > > 
> > > > > > Changes since v2:
> > > > > >   - Rewrite patch logic so it is more legible
> > > > > > 
> > > > > > Please note that I will unlikely be able to answer any comments 
> > > > > > from May
> > > > > > 24th to June 10th.
> > > > > > ---
> > > > > >  drivers/pci/controller/pci-aardvark.c | 29 
> > > > > > ++-
> > > > > >  1 file changed, 28 insertions(+), 1 deletion(-)
> > > > > > 
> > > > > > diff --git a/drivers/pci/controller/pci-aardvark.c 
> > > > > > b/drivers/pci/controller/pci-aardvark.c
> > > > > > index 134e0306ff00..8803083b2174 100644
> > > > > > --- a/drivers/pci/controller/pci-aardvark.c
> > > > > > +++ b/drivers/pci/controller/pci-aardvark.c
> > > > > > @@ -180,6 +180,8 @@
> > > > > >  #define LINK_WAIT_MAX_RETRIES  10
> > > > > >  #define LINK_WAIT_USLEEP_MIN   9
> > > > > >  #define LINK_WAIT_USLEEP_MAX   10
> > > > > > +#define RETRAIN_WAIT_MAX_RETRIES   10
> > > > > > +#define RETRAIN_WAIT_USLEEP_US 2000
> > > > > >  
> > > > > >  #define MSI_IRQ_NUM32
> > > > > >  
> > > > > > @@ -239,6 +241,17 @@ static int advk_pcie_wait_for_link(struct 
> > > > > > advk_pcie *pcie)
> > > > > > return -ETIMEDOUT;
> > > > > >  }
> > > > > >  
> > > > > > +static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie)
> > > > > > +{
> > > > > > +   size_t retries;
> > > > > > +
> > > > > > +   for (retries = 0; retries < RETRAIN_WAIT_MAX_RETRIES; 
> > > > > > ++retries) {
> > > > > > +   if (!advk_pcie_link_up(pcie))
> > > > > > +   break;
> > > > > > +   udelay(RETRAIN_WAIT_USLEEP_US);
> > > > > > +   }
> > > > > > +}
> > > > > > +
> > > > > >  static void advk_pcie_setup_hw(struct advk_pcie *pcie)
> > > &g

Re: [PATCH v3] PCI: aardvark: Use LTSSM state to build link training flag

2019-09-30 Thread Remi Pommarel
On Mon, Sep 30, 2019 at 04:40:18PM +0100, Andrew Murray wrote:
> On Wed, May 22, 2019 at 11:33:51PM +0200, Remi Pommarel wrote:
> > Aardvark's PCI_EXP_LNKSTA_LT flag in its link status register is not
> > implemented and does not reflect the actual link training state (the
> > flag is always set to 0). In order to support link re-training feature
> > this flag has to be emulated. The Link Training and Status State
> > Machine (LTSSM) flag in Aardvark LMI config register could be used as
> > a link training indicator. Indeed if the LTSSM is in L0 or upper state
> > then link training has completed (see [1]).
> > 
> > Unfortunately because after asking a link retraining it takes a while
> > for the LTSSM state to become less than 0x10 (due to L0s to recovery
> > state transition delays), LTSSM can still be in L0 while link training
> > has not finished yet. So this waits for link to be in recovery or lesser
> > state before returning after asking for a link retrain.
> > 
> > [1] "PCI Express Base Specification", REV. 4.0
> > PCI Express, February 19 2014, Table 4-14
> > 
> > Signed-off-by: Remi Pommarel 
> > ---
> > Changes since v1:
> >   - Rename retraining flag field
> >   - Fix DEVCTL register writing
> > 
> > Changes since v2:
> >   - Rewrite patch logic so it is more legible
> > 
> > Please note that I will unlikely be able to answer any comments from May
> > 24th to June 10th.
> > ---
> >  drivers/pci/controller/pci-aardvark.c | 29 ++-
> >  1 file changed, 28 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/pci/controller/pci-aardvark.c 
> > b/drivers/pci/controller/pci-aardvark.c
> > index 134e0306ff00..8803083b2174 100644
> > --- a/drivers/pci/controller/pci-aardvark.c
> > +++ b/drivers/pci/controller/pci-aardvark.c
> > @@ -180,6 +180,8 @@
> >  #define LINK_WAIT_MAX_RETRIES  10
> >  #define LINK_WAIT_USLEEP_MIN   9
> >  #define LINK_WAIT_USLEEP_MAX   10
> > +#define RETRAIN_WAIT_MAX_RETRIES   10
> > +#define RETRAIN_WAIT_USLEEP_US 2000
> >  
> >  #define MSI_IRQ_NUM32
> >  
> > @@ -239,6 +241,17 @@ static int advk_pcie_wait_for_link(struct advk_pcie 
> > *pcie)
> > return -ETIMEDOUT;
> >  }
> >  
> > +static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie)
> > +{
> > +   size_t retries;
> > +
> > +   for (retries = 0; retries < RETRAIN_WAIT_MAX_RETRIES; ++retries) {
> > +   if (!advk_pcie_link_up(pcie))
> > +   break;
> > +   udelay(RETRAIN_WAIT_USLEEP_US);
> > +   }
> > +}
> > +
> >  static void advk_pcie_setup_hw(struct advk_pcie *pcie)
> >  {
> > u32 reg;
> > @@ -426,11 +439,20 @@ advk_pci_bridge_emul_pcie_conf_read(struct 
> > pci_bridge_emul *bridge,
> > return PCI_BRIDGE_EMUL_HANDLED;
> > }
> >  
> > +   case PCI_EXP_LNKCTL: {
> > +   /* u32 contains both PCI_EXP_LNKCTL and PCI_EXP_LNKSTA */
> > +   u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg) &
> > +   ~(PCI_EXP_LNKSTA_LT << 16);
> 
> The commit message says "the flag is always set to 0" - therefore I guess
> you don't *need* to mask out the LT bit here? I assume this is just
> belt-and-braces but thought I'd check incase I've misunderstood or if your
> commit message is inaccurate.
> 
> In any case masking out the bit (or adding a comment) makes this code more
> readable as the reader doesn't need to know what the hardware does with this
> bit.

Actually vendor eventually responded that the bit was reserved, but
during my tests it remains to 0.

So yes I am masking this out mainly for belt-and-braces and legibility.

> > +   if (!advk_pcie_link_up(pcie))
> > +   val |= (PCI_EXP_LNKSTA_LT << 16);
> > +   *value = val;
> > +   return PCI_BRIDGE_EMUL_HANDLED;
> > +   }
> > +
> > case PCI_CAP_LIST_ID:
> > case PCI_EXP_DEVCAP:
> > case PCI_EXP_DEVCTL:
> > case PCI_EXP_LNKCAP:
> > -   case PCI_EXP_LNKCTL:
> > *value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
> > return PCI_BRIDGE_EMUL_HANDLED;
> > default:
> > @@ -447,8 +469,13 @@ advk_pci_bridge_emul_pcie_conf_write(struct 
> > pci_bridge_emul *bridge,
> >  
> > switch (reg) {
> > case PCI_EXP_DEVCTL:
> > +   advk_writel(pcie, new

[PATCH v3] PCI: aardvark: Don't rely on jiffies while holding spinlock

2019-09-27 Thread Remi Pommarel
advk_pcie_wait_pio() can be called while holding a spinlock (from
pci_bus_read_config_dword()), then depends on jiffies in order to
timeout while polling on PIO state registers. In the case the PIO
transaction failed, the timeout will never happen and will also cause
the cpu to stall.

This decrements a variable and wait instead of using jiffies.

Signed-off-by: Remi Pommarel 
---
Changes since v1:
  - Reduce polling delay
  - Change size_t into int for loop counter
Changes since v2:
  - Keep timeout to 1ms by increasing retry counter
---
 drivers/pci/controller/pci-aardvark.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/controller/pci-aardvark.c 
b/drivers/pci/controller/pci-aardvark.c
index fc0fe4d4de49..7b5c9d6c8706 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -175,7 +175,8 @@
(PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn))| \
 PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))
 
-#define PIO_TIMEOUT_MS 1
+#define PIO_RETRY_CNT  500
+#define PIO_RETRY_DELAY2 /* 2 us*/
 
 #define LINK_WAIT_MAX_RETRIES  10
 #define LINK_WAIT_USLEEP_MIN   9
@@ -383,17 +384,16 @@ static void advk_pcie_check_pio_status(struct advk_pcie 
*pcie)
 static int advk_pcie_wait_pio(struct advk_pcie *pcie)
 {
struct device *dev = >pdev->dev;
-   unsigned long timeout;
+   int i;
 
-   timeout = jiffies + msecs_to_jiffies(PIO_TIMEOUT_MS);
-
-   while (time_before(jiffies, timeout)) {
+   for (i = 0; i < PIO_RETRY_CNT; i++) {
u32 start, isr;
 
start = advk_readl(pcie, PIO_START);
isr = advk_readl(pcie, PIO_ISR);
if (!start && isr)
return 0;
+   udelay(PIO_RETRY_DELAY);
}
 
dev_err(dev, "config read/write timed out\n");
-- 
2.20.1



Re: [PATCH v2] PCI: aardvark: Don't rely on jiffies while holding spinlock

2019-09-27 Thread Remi Pommarel
Hi Thomas,

On Fri, Sep 27, 2019 at 10:34:20AM +0200, Thomas Petazzoni wrote:
> Hello Remi,
> 
> Thanks for the new iteration!
> 
> On Fri, 27 Sep 2019 10:31:42 +0200
> Remi Pommarel  wrote:
> 
> > diff --git a/drivers/pci/controller/pci-aardvark.c 
> > b/drivers/pci/controller/pci-aardvark.c
> > index fc0fe4d4de49..ee05ccb2b686 100644
> > --- a/drivers/pci/controller/pci-aardvark.c
> > +++ b/drivers/pci/controller/pci-aardvark.c
> > @@ -175,7 +175,8 @@
> > (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn))| \
> >  PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))
> >  
> > -#define PIO_TIMEOUT_MS 1
> > +#define PIO_RETRY_CNT  10
> > +#define PIO_RETRY_DELAY2 /* 2 us*/
> 
> So this changes the timeout from 1ms to just 20us, a division by 50
> from the previous timeout value. From my measurements, it could
> sometime take up to 6us from a single PIO read operation to complete,
> which is getting close to the 20us timeout.
> 
> Shouldn't PIO_RETRY_CNT be kept at 500, so that we keep using a 1ms
> timeout ?

Damn. You right of course, sorry about that.

Thanks

-- 
Remi


[PATCH v2] PCI: aardvark: Don't rely on jiffies while holding spinlock

2019-09-27 Thread Remi Pommarel
advk_pcie_wait_pio() can be called while holding a spinlock (from
pci_bus_read_config_dword()), then depends on jiffies in order to
timeout while polling on PIO state registers. In the case the PIO
transaction failed, the timeout will never happen and will also cause
the cpu to stall.

This decrements a variable and wait instead of using jiffies.

Signed-off-by: Remi Pommarel 
---
Changes since v1:
  - Reduce polling delay
  - Change size_t into int for loop counter
---
 drivers/pci/controller/pci-aardvark.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/controller/pci-aardvark.c 
b/drivers/pci/controller/pci-aardvark.c
index fc0fe4d4de49..ee05ccb2b686 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -175,7 +175,8 @@
(PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn))| \
 PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))
 
-#define PIO_TIMEOUT_MS 1
+#define PIO_RETRY_CNT  10
+#define PIO_RETRY_DELAY2 /* 2 us*/
 
 #define LINK_WAIT_MAX_RETRIES  10
 #define LINK_WAIT_USLEEP_MIN   9
@@ -383,17 +384,16 @@ static void advk_pcie_check_pio_status(struct advk_pcie 
*pcie)
 static int advk_pcie_wait_pio(struct advk_pcie *pcie)
 {
struct device *dev = >pdev->dev;
-   unsigned long timeout;
+   int i;
 
-   timeout = jiffies + msecs_to_jiffies(PIO_TIMEOUT_MS);
-
-   while (time_before(jiffies, timeout)) {
+   for (i = 0; i < PIO_RETRY_CNT; i++) {
u32 start, isr;
 
start = advk_readl(pcie, PIO_START);
isr = advk_readl(pcie, PIO_ISR);
if (!start && isr)
return 0;
+   udelay(PIO_RETRY_DELAY);
}
 
dev_err(dev, "config read/write timed out\n");
-- 
2.20.1



Re: [PATCH] PCI: aardvark: Don't rely on jiffies while holding spinlock

2019-09-27 Thread Remi Pommarel
Hi Thomas,

Thanks for the review.

On Wed, Sep 25, 2019 at 11:33:51AM +0200, Thomas Petazzoni wrote:
> Hello Remi,
> 
> Thanks for the patch, I have a few comments/questions below.
> 
> On Sun,  1 Sep 2019 16:23:03 +0200
> Remi Pommarel  wrote:
> 
> > diff --git a/drivers/pci/controller/pci-aardvark.c 
> > b/drivers/pci/controller/pci-aardvark.c
> > index fc0fe4d4de49..1fa6d04ad7aa 100644
> > --- a/drivers/pci/controller/pci-aardvark.c
> > +++ b/drivers/pci/controller/pci-aardvark.c
> > @@ -175,7 +175,8 @@
> > (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn))| \
> >  PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))
> >  
> > -#define PIO_TIMEOUT_MS 1
> > +#define PIO_RETRY_CNT  10
> > +#define PIO_RETRY_DELAY100 /* 100 us*/
> >  
> >  #define LINK_WAIT_MAX_RETRIES  10
> >  #define LINK_WAIT_USLEEP_MIN   9
> > @@ -383,17 +384,16 @@ static void advk_pcie_check_pio_status(struct 
> > advk_pcie *pcie)
> >  static int advk_pcie_wait_pio(struct advk_pcie *pcie)
> >  {
> > struct device *dev = >pdev->dev;
> > -   unsigned long timeout;
> > +   size_t i;
> 
> Is it common to use a size_t for a loop counter ?

It was for me but seem not to be used that much. I can change that to an
int.

> >  
> > -   timeout = jiffies + msecs_to_jiffies(PIO_TIMEOUT_MS);
> > -
> > -   while (time_before(jiffies, timeout)) {
> > +   for (i = 0; i < PIO_RETRY_CNT; ++i) {
> 
> I find it more common to use post-increment for loop counters rather
> than pre-increment, but that's a really nitpick and I don't care much.
> 

Will change that to post-increment.

> > u32 start, isr;
> >  
> > start = advk_readl(pcie, PIO_START);
> > isr = advk_readl(pcie, PIO_ISR);
> > if (!start && isr)
> > return 0;
> > +   udelay(PIO_RETRY_DELAY);
> 
> But the bigger issue is that this change causes a 100us delay at
> *every* single PIO read or write operation.
> 
> Indeed, at the first iteration of the loop, the PIO operation has not
> completed, so you will always hit the udelay(100) a first time, and
> it's only at the second iteration of the loop that the PIO operation
> has completed (for successful PIO operations of course, which don't hit
> the timeout).
> 
> I took a measurement around wait_pio() with sched_clock before and
> after the patch. Before the patch, I have measurements like this (in
> nanoseconds):
> 
> [1.562801] time = 6000
> [1.565310] time = 6000
> [1.567809] time = 6080
> [1.570327] time = 6080
> [1.572836] time = 6080
> [1.575339] time = 6080
> [1.577858] time = 2720
> [1.580366] time = 2720
> [1.582862] time = 6000
> [1.585377] time = 2720
> [1.587890] time = 2720
> [1.590393] time = 2720
> 
> So it takes a few microseconds for each PIO operation.
> 
> With your patch applied:
> 
> [2.267291] time = 101680
> [2.270002] time = 100880
> [2.272852] time = 100800
> [2.275573] time = 100880
> [2.278285] time = 100800
> [2.281005] time = 100880
> [2.283722] time = 100800
> [2.286444] time = 100880
> [2.289264] time = 100880
> [2.291981] time = 100800
> [2.294690] time = 100800
> [2.297405] time = 100800
> 
> We're jumping to 100us for every PIO read/write operation. To be
> honest, I don't know if this is very important, there are not that many
> PIO operations, and they are not used in any performance hot path. But
> I thought it was worth pointing out the additional delay caused by this
> implementation change.

Good catch thanks for the measurements, will move to a 2us delay.

-- 
Remi


[PATCH] PCI: aardvark: Don't rely on jiffies while holding spinlock

2019-09-01 Thread Remi Pommarel
advk_pcie_wait_pio() can be called while holding a spinlock (from
pci_bus_read_config_dword()), then depends on jiffies in order to
timeout while polling on PIO state registers. In the case the PIO
transaction failed, the timeout will never happen and will also cause
the cpu to stall.

This decrements a variable and wait instead of using jiffies.

Signed-off-by: Remi Pommarel 
---
 drivers/pci/controller/pci-aardvark.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/controller/pci-aardvark.c 
b/drivers/pci/controller/pci-aardvark.c
index fc0fe4d4de49..1fa6d04ad7aa 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -175,7 +175,8 @@
(PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn))| \
 PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))
 
-#define PIO_TIMEOUT_MS 1
+#define PIO_RETRY_CNT  10
+#define PIO_RETRY_DELAY100 /* 100 us*/
 
 #define LINK_WAIT_MAX_RETRIES  10
 #define LINK_WAIT_USLEEP_MIN   9
@@ -383,17 +384,16 @@ static void advk_pcie_check_pio_status(struct advk_pcie 
*pcie)
 static int advk_pcie_wait_pio(struct advk_pcie *pcie)
 {
struct device *dev = >pdev->dev;
-   unsigned long timeout;
+   size_t i;
 
-   timeout = jiffies + msecs_to_jiffies(PIO_TIMEOUT_MS);
-
-   while (time_before(jiffies, timeout)) {
+   for (i = 0; i < PIO_RETRY_CNT; ++i) {
u32 start, isr;
 
start = advk_readl(pcie, PIO_START);
isr = advk_readl(pcie, PIO_ISR);
if (!start && isr)
return 0;
+   udelay(PIO_RETRY_DELAY);
}
 
dev_err(dev, "config read/write timed out\n");
-- 
2.20.1



[PATCH] iio: adc: meson_saradc: Fix memory allocation order

2019-09-01 Thread Remi Pommarel
meson_saradc's irq handler uses priv->regmap so make sure that it is
allocated before the irq get enabled.

This also fixes crash when CONFIG_DEBUG_SHIRQ is enabled, as device
managed resources are freed in the inverted order they had been
allocated, priv->regmap was freed before the spurious fake irq that
CONFIG_DEBUG_SHIRQ adds called the handler.

Reported-by: Elie Roudninski 
Signed-off-by: Remi Pommarel 
---
 drivers/iio/adc/meson_saradc.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 7b28d045d271..7b27306330a3 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -1219,6 +1219,11 @@ static int meson_sar_adc_probe(struct platform_device 
*pdev)
if (IS_ERR(base))
return PTR_ERR(base);
 
+   priv->regmap = devm_regmap_init_mmio(>dev, base,
+priv->param->regmap_config);
+   if (IS_ERR(priv->regmap))
+   return PTR_ERR(priv->regmap);
+
irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
if (!irq)
return -EINVAL;
@@ -1228,11 +1233,6 @@ static int meson_sar_adc_probe(struct platform_device 
*pdev)
if (ret)
return ret;
 
-   priv->regmap = devm_regmap_init_mmio(>dev, base,
-priv->param->regmap_config);
-   if (IS_ERR(priv->regmap))
-   return PTR_ERR(priv->regmap);
-
priv->clkin = devm_clk_get(>dev, "clkin");
if (IS_ERR(priv->clkin)) {
dev_err(>dev, "failed to get clkin\n");
-- 
2.20.1



Re: [PATCH v3] PCI: aardvark: Use LTSSM state to build link training flag

2019-08-06 Thread Remi Pommarel
On Wed, May 22, 2019 at 11:33:51PM +0200, Remi Pommarel wrote:
> Aardvark's PCI_EXP_LNKSTA_LT flag in its link status register is not
> implemented and does not reflect the actual link training state (the
> flag is always set to 0). In order to support link re-training feature
> this flag has to be emulated. The Link Training and Status State
> Machine (LTSSM) flag in Aardvark LMI config register could be used as
> a link training indicator. Indeed if the LTSSM is in L0 or upper state
> then link training has completed (see [1]).
> 
> Unfortunately because after asking a link retraining it takes a while
> for the LTSSM state to become less than 0x10 (due to L0s to recovery
> state transition delays), LTSSM can still be in L0 while link training
> has not finished yet. So this waits for link to be in recovery or lesser
> state before returning after asking for a link retrain.
> 
> [1] "PCI Express Base Specification", REV. 4.0
> PCI Express, February 19 2014, Table 4-14
> 
> Signed-off-by: Remi Pommarel 
> ---
> Changes since v1:
>   - Rename retraining flag field
>   - Fix DEVCTL register writing
> 
> Changes since v2:
>   - Rewrite patch logic so it is more legible
> 
> Please note that I will unlikely be able to answer any comments from May
> 24th to June 10th.
> ---
>  drivers/pci/controller/pci-aardvark.c | 29 ++-
>  1 file changed, 28 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/controller/pci-aardvark.c 
> b/drivers/pci/controller/pci-aardvark.c
> index 134e0306ff00..8803083b2174 100644
> --- a/drivers/pci/controller/pci-aardvark.c
> +++ b/drivers/pci/controller/pci-aardvark.c
> @@ -180,6 +180,8 @@
>  #define LINK_WAIT_MAX_RETRIES10
>  #define LINK_WAIT_USLEEP_MIN 9
>  #define LINK_WAIT_USLEEP_MAX 10
> +#define RETRAIN_WAIT_MAX_RETRIES 10
> +#define RETRAIN_WAIT_USLEEP_US   2000
>  
>  #define MSI_IRQ_NUM  32
>  
> @@ -239,6 +241,17 @@ static int advk_pcie_wait_for_link(struct advk_pcie 
> *pcie)
>   return -ETIMEDOUT;
>  }
>  
> +static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie)
> +{
> + size_t retries;
> +
> + for (retries = 0; retries < RETRAIN_WAIT_MAX_RETRIES; ++retries) {
> + if (!advk_pcie_link_up(pcie))
> + break;
> + udelay(RETRAIN_WAIT_USLEEP_US);
> + }
> +}
> +
>  static void advk_pcie_setup_hw(struct advk_pcie *pcie)
>  {
>   u32 reg;
> @@ -426,11 +439,20 @@ advk_pci_bridge_emul_pcie_conf_read(struct 
> pci_bridge_emul *bridge,
>   return PCI_BRIDGE_EMUL_HANDLED;
>   }
>  
> + case PCI_EXP_LNKCTL: {
> + /* u32 contains both PCI_EXP_LNKCTL and PCI_EXP_LNKSTA */
> + u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg) &
> + ~(PCI_EXP_LNKSTA_LT << 16);
> + if (!advk_pcie_link_up(pcie))
> + val |= (PCI_EXP_LNKSTA_LT << 16);
> + *value = val;
> + return PCI_BRIDGE_EMUL_HANDLED;
> + }
> +
>   case PCI_CAP_LIST_ID:
>   case PCI_EXP_DEVCAP:
>   case PCI_EXP_DEVCTL:
>   case PCI_EXP_LNKCAP:
> - case PCI_EXP_LNKCTL:
>   *value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
>   return PCI_BRIDGE_EMUL_HANDLED;
>   default:
> @@ -447,8 +469,13 @@ advk_pci_bridge_emul_pcie_conf_write(struct 
> pci_bridge_emul *bridge,
>  
>   switch (reg) {
>   case PCI_EXP_DEVCTL:
> + advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
> + break;
> +
>   case PCI_EXP_LNKCTL:
>   advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
> + if (new & PCI_EXP_LNKCTL_RL)
> + advk_pcie_wait_for_retrain(pcie);
>   break;
>  
>   case PCI_EXP_RTCTL:
> -- 
> 2.20.1

Gentle ping.

Please note that the SError problem discussed in V1 has been handled
and merged in arm-trusted-firmware's mainline.

-- 
Remi


Re: [PATCH v2] PCI: aardvark: Wait for endpoint to be ready before training link

2019-08-06 Thread Remi Pommarel
On Wed, May 22, 2019 at 11:33:50PM +0200, Remi Pommarel wrote:
> When configuring pcie reset pin from gpio (e.g. initially set by
> u-boot) to pcie function this pin goes low for a brief moment
> asserting the PERST# signal. Thus connected device enters fundamental
> reset process and link configuration can only begin after a minimal
> 100ms delay (see [1]).
> 
> Because the pin configuration comes from the "default" pinctrl it is
> implicitly configured before the probe callback is called:
> 
> driver_probe_device()
>   really_probe()
> ...
> pinctrl_bind_pins() /* Here pin goes from gpio to PCIE reset
>function and PERST# is asserted */
> ...
> drv->probe()
> 
> [1] "PCI Express Base Specification", REV. 4.0
> PCI Express, February 19 2014, 6.6.1 Conventional Reset
> 
> Signed-off-by: Remi Pommarel 
> ---
> Changes since v1:
>   - Add a comment about pinctrl implicit pin configuration
>   - Use more legible msleep
>   - Use PCI_PM_D3COLD_WAIT macro
> 
> Please note that I will unlikely be able to answer any comments from May
> 24th to June 10th.
> ---
>  drivers/pci/controller/pci-aardvark.c | 8 
>  1 file changed, 8 insertions(+)
> 
> diff --git a/drivers/pci/controller/pci-aardvark.c 
> b/drivers/pci/controller/pci-aardvark.c
> index 134e0306ff00..d998c2b9cd04 100644
> --- a/drivers/pci/controller/pci-aardvark.c
> +++ b/drivers/pci/controller/pci-aardvark.c
> @@ -324,6 +324,14 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
>   reg |= PIO_CTRL_ADDR_WIN_DISABLE;
>   advk_writel(pcie, reg, PIO_CTRL);
>  
> + /*
> +  * PERST# signal could have been asserted by pinctrl subsystem before
> +  * probe() callback has been called, making the endpoint going into
> +  * fundamental reset. As required by PCI Express spec a delay for at
> +  * least 100ms after such a reset before link training is needed.
> +  */
> + msleep(PCI_PM_D3COLD_WAIT);
> +
>   /* Start link training */
>   reg = advk_readl(pcie, PCIE_CORE_LINK_CTRL_STAT_REG);
>   reg |= PCIE_CORE_LINK_TRAINING;
> -- 
> 2.20.1

Gentle ping.

-- 
Remi


[PATCH v3] PCI: aardvark: Fix PCI_EXP_RTCTL register configuration

2019-06-14 Thread Remi Pommarel
PCI_EXP_RTCTL is used to activate PME interrupt only, so writing into it
should not modify other interrupts' mask. The ISR mask polarity was also
inverted, when PCI_EXP_RTCTL_PMEIE is set PCIE_MSG_PM_PME_MASK mask bit
should actually be cleared.

Fixes: 8a3ebd8de328 ("PCI: aardvark: Implement emulated root PCI bridge config 
space")
Signed-off-by: Remi Pommarel 
---
Changes since v1:
 * Improve code readability
 * Fix mask polarity
 * PME_MASK shift was off by one
Changes since v2:
 * Modify patch title
 * Change Fixes tag to commit that actually introduces the bug
---
 drivers/pci/controller/pci-aardvark.c | 13 +
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/controller/pci-aardvark.c 
b/drivers/pci/controller/pci-aardvark.c
index 134e0306ff00..f6e55c4597b1 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -415,7 +415,7 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul 
*bridge,
 
case PCI_EXP_RTCTL: {
u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG);
-   *value = (val & PCIE_MSG_PM_PME_MASK) ? PCI_EXP_RTCTL_PMEIE : 0;
+   *value = (val & PCIE_MSG_PM_PME_MASK) ? 0 : PCI_EXP_RTCTL_PMEIE;
return PCI_BRIDGE_EMUL_HANDLED;
}
 
@@ -451,10 +451,15 @@ advk_pci_bridge_emul_pcie_conf_write(struct 
pci_bridge_emul *bridge,
advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
break;
 
-   case PCI_EXP_RTCTL:
-   new = (new & PCI_EXP_RTCTL_PMEIE) << 3;
-   advk_writel(pcie, new, PCIE_ISR0_MASK_REG);
+   case PCI_EXP_RTCTL: {
+   /* Only mask/unmask PME interrupt */
+   u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG) &
+   ~PCIE_MSG_PM_PME_MASK;
+   if ((new & PCI_EXP_RTCTL_PMEIE) == 0)
+   val |= PCIE_MSG_PM_PME_MASK;
+   advk_writel(pcie, val, PCIE_ISR0_MASK_REG);
break;
+   }
 
case PCI_EXP_RTSTA:
new = (new & PCI_EXP_RTSTA_PME) >> 9;
-- 
2.20.1



Re: [PATCH v2] PCI: aardvark: Fix PCI_EXP_RTCTL conf register writing

2019-06-14 Thread Remi Pommarel
Hello,

On Fri, Jun 14, 2019 at 10:58:54AM +0200, Thomas Petazzoni wrote:
> Hello,
> 
> On Fri, 14 Jun 2019 08:42:25 +0200
> Remi Pommarel  wrote:
> 
> > PCI_EXP_RTCTL is used to activate PME interrupt only, so writing into it
> > should not modify other interrupts' mask. The ISR mask polarity was also
> > inverted, when PCI_EXP_RTCTL_PMEIE is set PCIE_MSG_PM_PME_MASK mask bit
> > should actually be cleared.
> > 
> > Fixes: 6302bf3ef78d ("PCI: Init PCIe feature bits for managed host bridge 
> > alloc")
> 
> Are you sure about this Fixes tag ? This commit seems unrelated.
> 
> The commit introducing this issue is 8a3ebd8de328301aacbe328650a59253be2ac82c.

The 6302bf3ef78d commit fixes PCI bridge's PME flag which introduces the
configuration of PCI_EXP_RTCTL register (which wasn't used before). So,
yes, PCI_EXP_RTCTL conf was flawed since 8a3ebd8de328 but the infinite
interrupt loop happens only since that 6302bf3ef78d has fixed this PME
flag bug.

I chose to use 6302bf3ef78d because it was the one commit triggering
the bug during my bisect process, but yes maybe using the commit that
introduced (even if it was silently) the problem makes more sense.

So if you want I can do a v3 with this Fixes tag modification.

-- 
Remi


[PATCH v2] PCI: aardvark: Fix PCI_EXP_RTCTL conf register writing

2019-06-14 Thread Remi Pommarel
PCI_EXP_RTCTL is used to activate PME interrupt only, so writing into it
should not modify other interrupts' mask. The ISR mask polarity was also
inverted, when PCI_EXP_RTCTL_PMEIE is set PCIE_MSG_PM_PME_MASK mask bit
should actually be cleared.

Fixes: 6302bf3ef78d ("PCI: Init PCIe feature bits for managed host bridge 
alloc")
Signed-off-by: Remi Pommarel 
---
Changes since v1:
 * Improve code readability
 * Fix mask polarity
 * PME_MASK shift was off by one
---
 drivers/pci/controller/pci-aardvark.c | 13 +
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/controller/pci-aardvark.c 
b/drivers/pci/controller/pci-aardvark.c
index 134e0306ff00..f6e55c4597b1 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -415,7 +415,7 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul 
*bridge,
 
case PCI_EXP_RTCTL: {
u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG);
-   *value = (val & PCIE_MSG_PM_PME_MASK) ? PCI_EXP_RTCTL_PMEIE : 0;
+   *value = (val & PCIE_MSG_PM_PME_MASK) ? 0 : PCI_EXP_RTCTL_PMEIE;
return PCI_BRIDGE_EMUL_HANDLED;
}
 
@@ -451,10 +451,15 @@ advk_pci_bridge_emul_pcie_conf_write(struct 
pci_bridge_emul *bridge,
advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
break;
 
-   case PCI_EXP_RTCTL:
-   new = (new & PCI_EXP_RTCTL_PMEIE) << 3;
-   advk_writel(pcie, new, PCIE_ISR0_MASK_REG);
+   case PCI_EXP_RTCTL: {
+   /* Only mask/unmask PME interrupt */
+   u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG) &
+   ~PCIE_MSG_PM_PME_MASK;
+   if ((new & PCI_EXP_RTCTL_PMEIE) == 0)
+   val |= PCIE_MSG_PM_PME_MASK;
+   advk_writel(pcie, val, PCIE_ISR0_MASK_REG);
break;
+   }
 
case PCI_EXP_RTSTA:
new = (new & PCI_EXP_RTSTA_PME) >> 9;
-- 
2.20.1



Re: [PATCH] PCI: aardvark: Fix PCI_EXP_RTCTL conf register writing

2019-06-13 Thread Remi Pommarel
On Thu, Jun 13, 2019 at 05:14:41PM +0100, Lorenzo Pieralisi wrote:
> On Wed, May 22, 2019 at 11:33:49PM +0200, Remi Pommarel wrote:
> > PCI_EXP_RTCTL is used to activate PME interrupt only, so writing into it
> > should not modify other interrupts' mask (such as ISR0).
> > 
> > Fixes: 6302bf3ef78d ("PCI: Init PCIe feature bits for managed host bridge 
> > alloc")
> > Signed-off-by: Remi Pommarel 
> > ---
> > Please note that I will unlikely be able to answer any comments from May
> > 24th to June 10th.
> > ---
> >  drivers/pci/controller/pci-aardvark.c | 10 +++---
> >  1 file changed, 7 insertions(+), 3 deletions(-)
> > 
> > diff --git a/drivers/pci/controller/pci-aardvark.c 
> > b/drivers/pci/controller/pci-aardvark.c
> > index 134e0306ff00..27102d3b4f9c 100644
> > --- a/drivers/pci/controller/pci-aardvark.c
> > +++ b/drivers/pci/controller/pci-aardvark.c
> > @@ -451,10 +451,14 @@ advk_pci_bridge_emul_pcie_conf_write(struct 
> > pci_bridge_emul *bridge,
> > advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
> > break;
> >  
> > -   case PCI_EXP_RTCTL:
> > -   new = (new & PCI_EXP_RTCTL_PMEIE) << 3;
> > -   advk_writel(pcie, new, PCIE_ISR0_MASK_REG);
> > +   case PCI_EXP_RTCTL: {
> > +   /* Only mask/unmask PME interrupt */
> > +   u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG) &
> > +   ~PCIE_MSG_PM_PME_MASK;
> > +   val |= (new & PCI_EXP_RTCTL_PMEIE) << 3;
> 
> I know you have not introduced this code but maybe we can
> take an opportunity to clarify it (that << 3 shift obfuscates
> a bit):
> 
>   u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG) &
>   ~PCIE_MSG_PM_PME_MASK;
> 
>   if (new & PCI_EXP_RTCTL_PMEIE)
>   val |= PCIE_MSG_PM_PME_MASK;
> 
>   advk_writel(pcie, val, PCIE_ISR0_MASK_REG);
>   break;
> 
> Or I am not reading the code correctly ?

Sure, that clarifies the code at the point where I realize that the
"<< 3" from the original code was off by one and the mask polarity was
inverted. So I'll fix all that in the v2.

Thanks.

-- 
Remi


[PATCH v3] PCI: aardvark: Use LTSSM state to build link training flag

2019-05-22 Thread Remi Pommarel
Aardvark's PCI_EXP_LNKSTA_LT flag in its link status register is not
implemented and does not reflect the actual link training state (the
flag is always set to 0). In order to support link re-training feature
this flag has to be emulated. The Link Training and Status State
Machine (LTSSM) flag in Aardvark LMI config register could be used as
a link training indicator. Indeed if the LTSSM is in L0 or upper state
then link training has completed (see [1]).

Unfortunately because after asking a link retraining it takes a while
for the LTSSM state to become less than 0x10 (due to L0s to recovery
state transition delays), LTSSM can still be in L0 while link training
has not finished yet. So this waits for link to be in recovery or lesser
state before returning after asking for a link retrain.

[1] "PCI Express Base Specification", REV. 4.0
PCI Express, February 19 2014, Table 4-14

Signed-off-by: Remi Pommarel 
---
Changes since v1:
  - Rename retraining flag field
  - Fix DEVCTL register writing

Changes since v2:
  - Rewrite patch logic so it is more legible

Please note that I will unlikely be able to answer any comments from May
24th to June 10th.
---
 drivers/pci/controller/pci-aardvark.c | 29 ++-
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pci-aardvark.c 
b/drivers/pci/controller/pci-aardvark.c
index 134e0306ff00..8803083b2174 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -180,6 +180,8 @@
 #define LINK_WAIT_MAX_RETRIES  10
 #define LINK_WAIT_USLEEP_MIN   9
 #define LINK_WAIT_USLEEP_MAX   10
+#define RETRAIN_WAIT_MAX_RETRIES   10
+#define RETRAIN_WAIT_USLEEP_US 2000
 
 #define MSI_IRQ_NUM32
 
@@ -239,6 +241,17 @@ static int advk_pcie_wait_for_link(struct advk_pcie *pcie)
return -ETIMEDOUT;
 }
 
+static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie)
+{
+   size_t retries;
+
+   for (retries = 0; retries < RETRAIN_WAIT_MAX_RETRIES; ++retries) {
+   if (!advk_pcie_link_up(pcie))
+   break;
+   udelay(RETRAIN_WAIT_USLEEP_US);
+   }
+}
+
 static void advk_pcie_setup_hw(struct advk_pcie *pcie)
 {
u32 reg;
@@ -426,11 +439,20 @@ advk_pci_bridge_emul_pcie_conf_read(struct 
pci_bridge_emul *bridge,
return PCI_BRIDGE_EMUL_HANDLED;
}
 
+   case PCI_EXP_LNKCTL: {
+   /* u32 contains both PCI_EXP_LNKCTL and PCI_EXP_LNKSTA */
+   u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg) &
+   ~(PCI_EXP_LNKSTA_LT << 16);
+   if (!advk_pcie_link_up(pcie))
+   val |= (PCI_EXP_LNKSTA_LT << 16);
+   *value = val;
+   return PCI_BRIDGE_EMUL_HANDLED;
+   }
+
case PCI_CAP_LIST_ID:
case PCI_EXP_DEVCAP:
case PCI_EXP_DEVCTL:
case PCI_EXP_LNKCAP:
-   case PCI_EXP_LNKCTL:
*value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
return PCI_BRIDGE_EMUL_HANDLED;
default:
@@ -447,8 +469,13 @@ advk_pci_bridge_emul_pcie_conf_write(struct 
pci_bridge_emul *bridge,
 
switch (reg) {
case PCI_EXP_DEVCTL:
+   advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
+   break;
+
case PCI_EXP_LNKCTL:
advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
+   if (new & PCI_EXP_LNKCTL_RL)
+   advk_pcie_wait_for_retrain(pcie);
break;
 
case PCI_EXP_RTCTL:
-- 
2.20.1



[PATCH v2] PCI: aardvark: Wait for endpoint to be ready before training link

2019-05-22 Thread Remi Pommarel
When configuring pcie reset pin from gpio (e.g. initially set by
u-boot) to pcie function this pin goes low for a brief moment
asserting the PERST# signal. Thus connected device enters fundamental
reset process and link configuration can only begin after a minimal
100ms delay (see [1]).

Because the pin configuration comes from the "default" pinctrl it is
implicitly configured before the probe callback is called:

driver_probe_device()
  really_probe()
...
pinctrl_bind_pins() /* Here pin goes from gpio to PCIE reset
   function and PERST# is asserted */
...
drv->probe()

[1] "PCI Express Base Specification", REV. 4.0
PCI Express, February 19 2014, 6.6.1 Conventional Reset

Signed-off-by: Remi Pommarel 
---
Changes since v1:
  - Add a comment about pinctrl implicit pin configuration
  - Use more legible msleep
  - Use PCI_PM_D3COLD_WAIT macro

Please note that I will unlikely be able to answer any comments from May
24th to June 10th.
---
 drivers/pci/controller/pci-aardvark.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/pci/controller/pci-aardvark.c 
b/drivers/pci/controller/pci-aardvark.c
index 134e0306ff00..d998c2b9cd04 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -324,6 +324,14 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
reg |= PIO_CTRL_ADDR_WIN_DISABLE;
advk_writel(pcie, reg, PIO_CTRL);
 
+   /*
+* PERST# signal could have been asserted by pinctrl subsystem before
+* probe() callback has been called, making the endpoint going into
+* fundamental reset. As required by PCI Express spec a delay for at
+* least 100ms after such a reset before link training is needed.
+*/
+   msleep(PCI_PM_D3COLD_WAIT);
+
/* Start link training */
reg = advk_readl(pcie, PCIE_CORE_LINK_CTRL_STAT_REG);
reg |= PCIE_CORE_LINK_TRAINING;
-- 
2.20.1



[PATCH] PCI: aardvark: Fix PCI_EXP_RTCTL conf register writing

2019-05-22 Thread Remi Pommarel
PCI_EXP_RTCTL is used to activate PME interrupt only, so writing into it
should not modify other interrupts' mask (such as ISR0).

Fixes: 6302bf3ef78d ("PCI: Init PCIe feature bits for managed host bridge 
alloc")
Signed-off-by: Remi Pommarel 
---
Please note that I will unlikely be able to answer any comments from May
24th to June 10th.
---
 drivers/pci/controller/pci-aardvark.c | 10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/controller/pci-aardvark.c 
b/drivers/pci/controller/pci-aardvark.c
index 134e0306ff00..27102d3b4f9c 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -451,10 +451,14 @@ advk_pci_bridge_emul_pcie_conf_write(struct 
pci_bridge_emul *bridge,
advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
break;
 
-   case PCI_EXP_RTCTL:
-   new = (new & PCI_EXP_RTCTL_PMEIE) << 3;
-   advk_writel(pcie, new, PCIE_ISR0_MASK_REG);
+   case PCI_EXP_RTCTL: {
+   /* Only mask/unmask PME interrupt */
+   u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG) &
+   ~PCIE_MSG_PM_PME_MASK;
+   val |= (new & PCI_EXP_RTCTL_PMEIE) << 3;
+   advk_writel(pcie, val, PCIE_ISR0_MASK_REG);
break;
+   }
 
case PCI_EXP_RTSTA:
new = (new & PCI_EXP_RTSTA_PME) >> 9;
-- 
2.20.1



Re: [PATCH v2] PCI: aardvark: Use LTSSM state to build link training flag

2019-05-21 Thread Remi Pommarel
Hi Lorenzo,

On Tue, Apr 30, 2019 at 12:34:27PM +0100, Lorenzo Pieralisi wrote:
> On Mon, Apr 29, 2019 at 05:32:35PM +0200, Remi Pommarel wrote:
> > Hi Lorenzo,
> > 
> > Sorry for duplicates I forgot to include everyone.
> > 
> > On Thu, Apr 25, 2019 at 04:06:40PM +0100, Lorenzo Pieralisi wrote:
> > > On Thu, Apr 25, 2019 at 04:23:53PM +0200, Remi Pommarel wrote:
> > > > Hi Lorenzo,
> > > > 
> > > > On Thu, Apr 25, 2019 at 12:08:30PM +0100, Lorenzo Pieralisi wrote:
> > > > > On Sat, Mar 16, 2019 at 05:12:43PM +0100, Remi Pommarel wrote:
> > > > > > The PCI_EXP_LNKSTA_LT flag in the emulated root device's 
> > > > > > PCI_EXP_LNKSTA
> > > > > > config register does not reflect the actual link training state and 
> > > > > > is
> > > > > > always cleared. The Link Training and Status State Machine (LTSSM) 
> > > > > > flag
> > > > > > in LMI config register could be used as a link training indicator.
> > > > > > Indeed if the LTSSM is in L0 or upper state then link training has
> > > > > > completed (see [1]).
> > > > > > 
> > > > > > Unfortunately because setting the PCI_EXP_LINCTL_RL flag does not
> > > > > > instantly imply a LTSSM state change (e.g. L0s to recovery state
> > > > > > transition takes some time), LTSSM can be in L0 but link training 
> > > > > > has
> > > > > > not finished yet. Thus a lower L0 LTSSM state followed by a L0 or 
> > > > > > upper
> > > > > > state sequence has to be seen to be sure that link training has been
> > > > > > done.
> > > > > 
> > > > > Hi Remi,
> > > > > 
> > > > > I am a bit confused, so you are saying that the LTSSM flag in the
> > > > > LMI config register can't be used to detect when training is 
> > > > > completed ?
> > > > 
> > > > Not exactly, I am saying that PCI_EXP_LNKSTA_LT from PCI_EXP_LNKSTA
> > > > register can't be used with this hardware, but can be emulated with
> > > > LTSSM flag.
> > > > 
> > > > > 
> > > > > Certainly it can't be used by ASPM core that relies on:
> > > > > 
> > > > > PCI_EXP_LNKSTA_LT flag
> > > > > 
> > > > > in the PCI_EXP_LNKSTA register, and that's what you are setting 
> > > > > through
> > > > > this timeout mechanism IIUC.
> > > > > 
> > > > > Please elaborate on that.
> > > > 
> > > > The problem here is that the hardware does not change PCI_EXP_LNKSTA_LT
> > > > at all. So in order to support link re-training feature we need to
> > > > emulate this flag. To do so LTSSM flag can be used.
> > > 
> > > Understood.
> > > 
> > > > Indeed we can set the emulated PCI_EXP_LNKSTA_LT as soon as re-training
> > > > is asked and wait for LTSSM flag to be back to a configured state
> > > > (e.g. L0, L0s) before clearing it.
> > > 
> > > The check for the LTSSM is carried out through advk_pcie_link_up()
> > > (ie register CFG_REG), correct ?
> > > 
> > 
> > Yes that is correct.
> > 
> > > > The problem with that is that LTSSM flag does not change instantly after
> > > > link re-training has been asked, and will stay in configured state for a
> > > > small amount of time. So the idea is to poll the LTSSM flag and wait for
> > > > it to enter a recovery state then waiting for it to be back in
> > > > configured state.
> > > 
> > > When you say "poll" you mean checking advk_pcie_link_up() ?
> > > 
> > 
> > I mean checking advk_pcie_link_up() in a loop. This loop is done by the
> > user (e.g. ASPM core). ASPM core waits for PCI_EXP_LNKSTA_LT to be
> > cleared in pcie_aspm_configure_common_clock() just after it has set
> > PCI_EXP_LNKCTL_RL.
> > 
> > So the idea was to check advk_pcie_link_up() each time ASPM core checks
> > the PCI_EXP_LNKSTA_LT flag. Please see below patch for an alternative
> > to that.
> > 
> > > More below on the code.
> > > 
> > > > The timeout is only here as a fallback in the unlikely event that we
> > > > missed the LTSSM flag entering recovery state.
> > > > 
> > > > > 
> > > > > I am picking Bjorn's bra

Re: [PATCH v2] PCI: aardvark: Use LTSSM state to build link training flag

2019-04-30 Thread Remi Pommarel
On Mon, Apr 29, 2019 at 02:45:32PM -0500, Bjorn Helgaas wrote:
> On Fri, Apr 26, 2019 at 12:27:57AM +0200, Remi Pommarel wrote:
> > On Thu, Apr 25, 2019 at 04:04:39PM -0500, Bjorn Helgaas wrote:
> > > On Sat, Mar 16, 2019 at 05:12:43PM +0100, Remi Pommarel wrote:
> 
> > > It sounds like reading and/or writing some registers during a retrain
> > > causes some sort of EL1 error?  Is this a separate erratum?  Is there
> > > a list of the registers and operations (read/write) that are affected?
> > > The backtrace below suggests that it's actually a read of LNKCAP or
> > > LNKCTL (not LNKSTA) that caused the error.
> > 
> > IIUC, the backtrace below produces an EL1 error when doing a PIO
> > transfer while the link is still retraining. See my comment below for
> > more about that. But accessing any root complex's register seems fine.
> > > 
> > > It sounds like there are really two problems:
> > > 
> > >   1) Reading PCI_EXP_LNKSTA (or the Aardvark equivalent) doesn't give
> > >  valid data for PCI_EXP_LNKSTA_LT.
> > 
> > The 1) is correct.
> > 
> > >   2) Sometimes config reads cause EL1 errors.
> > 
> > Actually EL1 error happens when we try to access device's register with
> > a PIO transfer, which is when we try to use the link while it is being
> > retrained.
> > 
> > IMHO, 1) and 2) are linked. ASPM core tries to use the link too early
> > because it has read invalid data for PCI_EXP_LNKSTA_LT.
> 
> From the software point of view, there is no such thing as "using the
> link too early".  The pattern of:
> 
>   - Verify that link is up
>   - Access device on other end of link
> 
> is always racy because the link can go down at any time due to hotplug
> or other issues.  In particular, the link can go down after we verify
> that the link is up, but before we access the device.
> 
> Software must be able to deal with that gracefully.  I don't know
> whether that means catching and recovering from that EL1 error, or
> masking it, or what.  This is architecture-specific stuff that's
> outside the scope of PCIe itself.
> 
> But a link going down should never directly cause a kernel panic.

Ah, yes, you are right. There is "worse" than the EL1 error though, boot
can also hang while accessing those registers when link is not in a
ready state.

So, yes, I do agree that there are two issues here. The
PCI_EXP_LNKSTA_LT register one and the EL1 error or hang one. On the
other hand I don't think I can split it in two because this patch only
fixes the former which happens to not trigger the latter (ASPM core is
kind enough to wait for the link to be ready after retraining).

Thus the second issue remains and hot plugging for example would
likely trigger it. I'll try to see with Thomas if we could reach the
vendor about that.

By the way, I have replied to Lorenzo with, what I think, is a more
legible patch. I could send a v3 with it if you prefer this one.

-- 
Remi


Re: [PATCH v2] PCI: aardvark: Use LTSSM state to build link training flag

2019-04-29 Thread Remi Pommarel
Hi Lorenzo,

Sorry for duplicates I forgot to include everyone.

On Thu, Apr 25, 2019 at 04:06:40PM +0100, Lorenzo Pieralisi wrote:
> On Thu, Apr 25, 2019 at 04:23:53PM +0200, Remi Pommarel wrote:
> > Hi Lorenzo,
> > 
> > On Thu, Apr 25, 2019 at 12:08:30PM +0100, Lorenzo Pieralisi wrote:
> > > On Sat, Mar 16, 2019 at 05:12:43PM +0100, Remi Pommarel wrote:
> > > > The PCI_EXP_LNKSTA_LT flag in the emulated root device's PCI_EXP_LNKSTA
> > > > config register does not reflect the actual link training state and is
> > > > always cleared. The Link Training and Status State Machine (LTSSM) flag
> > > > in LMI config register could be used as a link training indicator.
> > > > Indeed if the LTSSM is in L0 or upper state then link training has
> > > > completed (see [1]).
> > > > 
> > > > Unfortunately because setting the PCI_EXP_LINCTL_RL flag does not
> > > > instantly imply a LTSSM state change (e.g. L0s to recovery state
> > > > transition takes some time), LTSSM can be in L0 but link training has
> > > > not finished yet. Thus a lower L0 LTSSM state followed by a L0 or upper
> > > > state sequence has to be seen to be sure that link training has been
> > > > done.
> > > 
> > > Hi Remi,
> > > 
> > > I am a bit confused, so you are saying that the LTSSM flag in the
> > > LMI config register can't be used to detect when training is completed ?
> > 
> > Not exactly, I am saying that PCI_EXP_LNKSTA_LT from PCI_EXP_LNKSTA
> > register can't be used with this hardware, but can be emulated with
> > LTSSM flag.
> > 
> > > 
> > > Certainly it can't be used by ASPM core that relies on:
> > > 
> > > PCI_EXP_LNKSTA_LT flag
> > > 
> > > in the PCI_EXP_LNKSTA register, and that's what you are setting through
> > > this timeout mechanism IIUC.
> > > 
> > > Please elaborate on that.
> > 
> > The problem here is that the hardware does not change PCI_EXP_LNKSTA_LT
> > at all. So in order to support link re-training feature we need to
> > emulate this flag. To do so LTSSM flag can be used.
> 
> Understood.
> 
> > Indeed we can set the emulated PCI_EXP_LNKSTA_LT as soon as re-training
> > is asked and wait for LTSSM flag to be back to a configured state
> > (e.g. L0, L0s) before clearing it.
> 
> The check for the LTSSM is carried out through advk_pcie_link_up()
> (ie register CFG_REG), correct ?
> 

Yes that is correct.

> > The problem with that is that LTSSM flag does not change instantly after
> > link re-training has been asked, and will stay in configured state for a
> > small amount of time. So the idea is to poll the LTSSM flag and wait for
> > it to enter a recovery state then waiting for it to be back in
> > configured state.
> 
> When you say "poll" you mean checking advk_pcie_link_up() ?
> 

I mean checking advk_pcie_link_up() in a loop. This loop is done by the
user (e.g. ASPM core). ASPM core waits for PCI_EXP_LNKSTA_LT to be
cleared in pcie_aspm_configure_common_clock() just after it has set
PCI_EXP_LNKCTL_RL.

So the idea was to check advk_pcie_link_up() each time ASPM core checks
the PCI_EXP_LNKSTA_LT flag. Please see below patch for an alternative
to that.

> More below on the code.
> 
> > The timeout is only here as a fallback in the unlikely event that we
> > missed the LTSSM flag entering recovery state.
> > 
> > > 
> > > I am picking Bjorn's brain on this patch since what you are doing
> > > seems quite arbitrary and honestly it is a bit of a hack.
> > 
> > Yes, sorry, it is a bit of a hack because I try to workaround a
> > hardware issue.
> 
> No problems, it is not your fault.
> > 
> > Please note that vendor has been contacted about this in the meantime
> > and answered the following:
> > 
> > "FW can poll LTSSM state equals any of the following values: 0xB or 0xD
> > or 0xC or 0xE. After that, polls for LTSSM equals 0x10. For your
> > information, LTSSM will transit from 0x10 -> 0xB -> 0xD -> 0xC or 0xE
> > ... -> 0x10".
> > 
> > It is basically what this patch does, I've just added a timeout fallback
> > to not poll LTSSM state forever if its transition to 0xB, 0xD, 0xC or
> > 0xE has been missed.
> 
> When you say "missed" you mean advk_pcie_link_up() returning true, right ?
> 

Not exactly, I mean that LTSSM had the time to go down and back up
between advk_pcie_link_up() because, for example, ASPM core loop took
too much time between two PCI_EXP_LNKSTA_L

Re: [PATCH v2] PCI: aardvark: Use LTSSM state to build link training flag

2019-04-25 Thread Remi Pommarel
Hi Bjorn,

On Thu, Apr 25, 2019 at 04:04:39PM -0500, Bjorn Helgaas wrote:
> Hi Remi,
> 
> On Sat, Mar 16, 2019 at 05:12:43PM +0100, Remi Pommarel wrote:
> > The PCI_EXP_LNKSTA_LT flag in the emulated root device's PCI_EXP_LNKSTA
> > config register does not reflect the actual link training state and is
> > always cleared. The Link Training and Status State Machine (LTSSM) flag
> > in LMI config register could be used as a link training indicator.
> 
> LMI?  I assume this is an Aardvark-specific register?  Maybe "Aardvark
> LMI register", since the other things here are generic PCIe registers?

Yes this is an Aardvark specific register, I would have said that LMI
stands for LTSSM management interface, but this is only guessing as I
don't have access to a datasheet.

> Is this a hardware erratum?  I know advk does some software emulation,
> but it looks like the Aardvark PCIE_CORE_PCIEXP_CAP + PCI_EXP_LNKSTA
> register is awfully close to being exactly the PCIe-defined
> PCI_EXP_LNKSTA, so the difference seems like a mistake.

Vendor says that PCI_EXP_LNKSTA_LT bit in PCI_EXP_LNKSTA is marked as
"reserved" and is not implemented. It does look like a mistake to me.

> 
> > Indeed if the LTSSM is in L0 or upper state then link training has
> > completed (see [1]).
> > 
> > Unfortunately because setting the PCI_EXP_LINCTL_RL flag does not
> 
> s/PCI_EXP_LINCTL_RL/PCI_EXP_LNKCTL_RL/
> 
> > instantly imply a LTSSM state change (e.g. L0s to recovery state
> > transition takes some time), LTSSM can be in L0 but link training has
> > not finished yet. Thus a lower L0 LTSSM state followed by a L0 or upper
> > state sequence has to be seen to be sure that link training has been
> > done.
> > 
> > Because one may not call a pcie conf register read on LNKSTA after
> > doing a retrain link or may miss the link down state due to timing, a
> > 20ms timeout is used. Passing this timeout link is considered retrained.
> 
> It sounds like reading and/or writing some registers during a retrain
> causes some sort of EL1 error?  Is this a separate erratum?  Is there
> a list of the registers and operations (read/write) that are affected?
> The backtrace below suggests that it's actually a read of LNKCAP or
> LNKCTL (not LNKSTA) that caused the error.

IIUC, the backtrace below produces an EL1 error when doing a PIO
transfer while the link is still retraining. See my comment below for
more about that. But accessing any root complex's register seems fine.
> 
> It sounds like there are really two problems:
> 
>   1) Reading PCI_EXP_LNKSTA (or the Aardvark equivalent) doesn't give
>  valid data for PCI_EXP_LNKSTA_LT.

The 1) is correct.

> 
>   2) Sometimes config reads cause EL1 errors.

Actually EL1 error happens when we try to access device's register with
a PIO transfer, which is when we try to use the link while it is being
retrained.

IMHO, 1) and 2) are linked. ASPM core tries to use the link too early
because it has read invalid data for PCI_EXP_LNKSTA_LT.

> 
> If that's the case and if it's possible, can you split this into a
> patch for each issue?
> 
> > This fixes boot hang or kernel panic with the following callstack due to
> > ASPM setup doing a link re-train and polling for PCI_EXP_LNKSTA_LT flag
> > to be cleared before using it.
> > 
> >  8< ---
> > [0.915389]  dump_backtrace+0x0/0x140
> > [0.915391]  show_stack+0x14/0x20
> > [0.915393]  dump_stack+0x90/0xb4
> > [0.915394]  panic+0x134/0x2c0
> > [0.915396]  nmi_panic+0x6c/0x70
> > [0.915398]  arm64_serror_panic+0x74/0x80
> > [0.915400]  is_valid_bugaddr+0x0/0x8
> > [0.915402]  el1_error+0x7c/0xe4
> > [0.915404]  advk_pcie_rd_conf+0x4c/0x250
> > [0.915406]  pci_bus_read_config_word+0x7c/0xd0
> > [0.915408]  pcie_capability_read_word+0x90/0xc8
> > [0.915410]  pcie_get_aspm_reg+0x68/0x118
> > [0.915412]  pcie_aspm_init_link_state+0x460/0xa98
> 
> This backtrace doesn't make sense to me as being related to this
> issue.  You said above that the bug was that PCI_EXP_LNKSTA_LT is not
> updated.  But apparently even *reading* a register at the wrong time
> causes this EL1 error.  And pcie_get_aspm_reg() doesn't even read
> LNKSTA; it only reads LNKCAP and LNKCTL.

In fact here, advk_pcie_rd_conf+0x4c seems to be this line:
advk_writel(pcie, 0, PIO_START);

So EL1 error seems not to happen while accessing root complex registery
but while doing a PIO transfer using the link.

> 
> BTW, if you're including a backtrace in a commit log, you can strip
> out the timestamps

Re: [PATCH] pci: aardvark: Wait for endpoint to be ready before training link

2019-04-25 Thread Remi Pommarel
On Wed, Apr 24, 2019 at 05:50:02PM +0100, Lorenzo Pieralisi wrote:
> On Wed, Apr 24, 2019 at 12:29:18AM +0200, Remi Pommarel wrote:
> > Hi,
> > 
> > On Tue, Apr 23, 2019 at 05:32:15PM +0100, Lorenzo Pieralisi wrote:
> > > On Wed, Mar 13, 2019 at 10:37:52PM +0100, Remi Pommarel wrote:
> > > > When configuring pcie reset pin from gpio (e.g. initially set by
> > > > u-boot) to pcie function this pin goes low for a brief moment
> > > > asserting the PERST# signal. Thus connected device enters fundamental
> > > > reset process and link configuration can only begin after a minimal
> > > > 100ms delay (see [1]).
> > > > 
> > > > This makes sure that link is configured after at least 100ms from
> > > > beginning of probe() callback (shortly after the reset pin function
> > > > configuration switch through pinctrl subsytem).
> 
> I am a bit lost, what's the connection between the probe() callback
> and the reset pin function configuration ?
> 
> Please elaborate.
> 

So currently u-boot configures the reset pin as a GPIO set to high. The
espressobin devicetree defines a default pinctrl to configure this pin
as a PCIe reset function.

As you can see in drivers/base/dd.c, driver_probe_device() calls
really_probe() which first calls pinctrl_bind_pins() then shortly after
drv->probe() callback. The pinctrl_bind_pins() function applies the
default state. So here, just before drv->probe() gets called our reset
pin goes from GPIO function to PCIe reset one making it going low for a
short time during this transition.

Because the pin goes low then gets back to high, PERST# signal is
asserted then deasserted and device enters fundamental reset process
just before drv->probe() is called. So in order to reduce the waiting
time to a minimum I sample jiffies at the very beginning of the probe
function, which is the closer spot from where PERST# is deasserted.

To sum up:

driver_probe_device() {
...
really_probe() {
...
pinctrl_bind_pins(); /* Here PERST# is asserted because pin 
configuration changes */
...
drv->probe();
...
}
...
}

> > > > 
> > > > [1] "PCI Express Base Specification", REV. 2.1
> > > > PCI Express, March 4 2009, 6.6.1 Conventional Reset
> > > > 
> > > > Signed-off-by: Remi Pommarel 
> > > > ---
> > > >  drivers/pci/controller/pci-aardvark.c | 17 ++---
> > > >  1 file changed, 14 insertions(+), 3 deletions(-)
> > > > 
> > > > diff --git a/drivers/pci/controller/pci-aardvark.c 
> > > > b/drivers/pci/controller/pci-aardvark.c
> > > > index a30ae7cf8e7e..70a1023d0ef1 100644
> > > > --- a/drivers/pci/controller/pci-aardvark.c
> > > > +++ b/drivers/pci/controller/pci-aardvark.c
> > > > @@ -177,6 +177,9 @@
> > > >  
> > > >  #define PIO_TIMEOUT_MS 1
> > > >  
> > > > +/* Endpoint can take up to 100ms to be ready after a reset */
> > > > +#define ENDPOINT_RST_MS100
> > > > +
> > > >  #define LINK_WAIT_MAX_RETRIES  10
> > > >  #define LINK_WAIT_USLEEP_MIN   9
> > > >  #define LINK_WAIT_USLEEP_MAX   10
> > > > @@ -242,8 +245,10 @@ static int advk_pcie_wait_for_link(struct 
> > > > advk_pcie *pcie)
> > > > return -ETIMEDOUT;
> > > >  }
> > > >  
> > > > -static void advk_pcie_setup_hw(struct advk_pcie *pcie)
> > > > +static void
> > > > +advk_pcie_setup_hw(struct advk_pcie *pcie, unsigned long ep_rdy_time)
> > > 
> > > Nit: I prefer the prototype to be in one line, I wrap it for you.
> > > 
> > > I am wondering why you need to pass in ep_rdy_time parameter when you
> > > can easily compute it in the function itself.
> > > 
> > 
> > The only reason for that is because the sooner I get the jiffies the
> > lower the delay has to be. I was trying to reduce the impact of this
> > delay to a minimum, but maybe the improvement is not worth it.
> 
> That should just be (roughly) some microseconds unless there is
> something I am missing. Try to measure it :)

So doing that I do a msleep() of around 75-80ms instead of 100ms. So,
yes, are 20ms enough to justify that, or should we just go with a plain
msleep(100) to improve legibility.

-- 
Remi


Re: [PATCH v2] PCI: aardvark: Use LTSSM state to build link training flag

2019-04-25 Thread Remi Pommarel
Hi Lorenzo,

On Thu, Apr 25, 2019 at 12:08:30PM +0100, Lorenzo Pieralisi wrote:
> On Sat, Mar 16, 2019 at 05:12:43PM +0100, Remi Pommarel wrote:
> > The PCI_EXP_LNKSTA_LT flag in the emulated root device's PCI_EXP_LNKSTA
> > config register does not reflect the actual link training state and is
> > always cleared. The Link Training and Status State Machine (LTSSM) flag
> > in LMI config register could be used as a link training indicator.
> > Indeed if the LTSSM is in L0 or upper state then link training has
> > completed (see [1]).
> > 
> > Unfortunately because setting the PCI_EXP_LINCTL_RL flag does not
> > instantly imply a LTSSM state change (e.g. L0s to recovery state
> > transition takes some time), LTSSM can be in L0 but link training has
> > not finished yet. Thus a lower L0 LTSSM state followed by a L0 or upper
> > state sequence has to be seen to be sure that link training has been
> > done.
> 
> Hi Remi,
> 
> I am a bit confused, so you are saying that the LTSSM flag in the
> LMI config register can't be used to detect when training is completed ?

Not exactly, I am saying that PCI_EXP_LNKSTA_LT from PCI_EXP_LNKSTA
register can't be used with this hardware, but can be emulated with
LTSSM flag.

> 
> Certainly it can't be used by ASPM core that relies on:
> 
> PCI_EXP_LNKSTA_LT flag
> 
> in the PCI_EXP_LNKSTA register, and that's what you are setting through
> this timeout mechanism IIUC.
> 
> Please elaborate on that.

The problem here is that the hardware does not change PCI_EXP_LNKSTA_LT
at all. So in order to support link re-training feature we need to
emulate this flag. To do so LTSSM flag can be used.

Indeed we can set the emulated PCI_EXP_LNKSTA_LT as soon as re-training
is asked and wait for LTSSM flag to be back to a configured state
(e.g. L0, L0s) before clearing it.

The problem with that is that LTSSM flag does not change instantly after
link re-training has been asked, and will stay in configured state for a
small amount of time. So the idea is to poll the LTSSM flag and wait for
it to enter a recovery state then waiting for it to be back in
configured state.

The timeout is only here as a fallback in the unlikely event that we
missed the LTSSM flag entering recovery state.

> 
> I am picking Bjorn's brain on this patch since what you are doing
> seems quite arbitrary and honestly it is a bit of a hack.

Yes, sorry, it is a bit of a hack because I try to workaround a
hardware issue.

Please note that vendor has been contacted about this in the meantime
and answered the following:

"FW can poll LTSSM state equals any of the following values: 0xB or 0xD
or 0xC or 0xE. After that, polls for LTSSM equals 0x10. For your
information, LTSSM will transit from 0x10 -> 0xB -> 0xD -> 0xC or 0xE
... -> 0x10".

It is basically what this patch does, I've just added a timeout fallback
to not poll LTSSM state forever if its transition to 0xB, 0xD, 0xC or
0xE has been missed.

-- 
Remi

> 
> I wonder whether it is not better to avoid advertising ASPM support.
> 
> Lorenzo
> 
> > Because one may not call a pcie conf register read on LNKSTA after
> > doing a retrain link or may miss the link down state due to timing, a
> > 20ms timeout is used. Passing this timeout link is considered retrained.
> > 
> > This fixes boot hang or kernel panic with the following callstack due to
> > ASPM setup doing a link re-train and polling for PCI_EXP_LNKSTA_LT flag
> > to be cleared before using it.
> > 
> >  8< ---
> > [0.915389]  dump_backtrace+0x0/0x140
> > [0.915391]  show_stack+0x14/0x20
> > [0.915393]  dump_stack+0x90/0xb4
> > [0.915394]  panic+0x134/0x2c0
> > [0.915396]  nmi_panic+0x6c/0x70
> > [0.915398]  arm64_serror_panic+0x74/0x80
> > [0.915400]  is_valid_bugaddr+0x0/0x8
> > [0.915402]  el1_error+0x7c/0xe4
> > [0.915404]  advk_pcie_rd_conf+0x4c/0x250
> > [0.915406]  pci_bus_read_config_word+0x7c/0xd0
> > [0.915408]  pcie_capability_read_word+0x90/0xc8
> > [0.915410]  pcie_get_aspm_reg+0x68/0x118
> > [0.915412]  pcie_aspm_init_link_state+0x460/0xa98
> > [0.915414]  pci_scan_slot+0xe8/0x100
> > [0.915416]  pci_scan_child_bus_extend+0x50/0x288
> > [0.915418]  pci_scan_bridge_extend+0x348/0x4f0
> > [0.915420]  pci_scan_child_bus_extend+0x1dc/0x288
> > [0.915423]  pci_scan_root_bus_bridge+0xc4/0xe0
> > [0.915424]  pci_host_probe+0x14/0xa8
> > [0.915426]  advk_pcie_probe+0x838/0x910
> > [...]
> >  8< ---
> &

Re: [PATCH] pci: aardvark: Wait for endpoint to be ready before training link

2019-04-23 Thread Remi Pommarel
Hi,

On Tue, Apr 23, 2019 at 05:32:15PM +0100, Lorenzo Pieralisi wrote:
> On Wed, Mar 13, 2019 at 10:37:52PM +0100, Remi Pommarel wrote:
> > When configuring pcie reset pin from gpio (e.g. initially set by
> > u-boot) to pcie function this pin goes low for a brief moment
> > asserting the PERST# signal. Thus connected device enters fundamental
> > reset process and link configuration can only begin after a minimal
> > 100ms delay (see [1]).
> > 
> > This makes sure that link is configured after at least 100ms from
> > beginning of probe() callback (shortly after the reset pin function
> > configuration switch through pinctrl subsytem).
> > 
> > [1] "PCI Express Base Specification", REV. 2.1
> > PCI Express, March 4 2009, 6.6.1 Conventional Reset
> > 
> > Signed-off-by: Remi Pommarel 
> > ---
> >  drivers/pci/controller/pci-aardvark.c | 17 ++---
> >  1 file changed, 14 insertions(+), 3 deletions(-)
> > 
> > diff --git a/drivers/pci/controller/pci-aardvark.c 
> > b/drivers/pci/controller/pci-aardvark.c
> > index a30ae7cf8e7e..70a1023d0ef1 100644
> > --- a/drivers/pci/controller/pci-aardvark.c
> > +++ b/drivers/pci/controller/pci-aardvark.c
> > @@ -177,6 +177,9 @@
> >  
> >  #define PIO_TIMEOUT_MS 1
> >  
> > +/* Endpoint can take up to 100ms to be ready after a reset */
> > +#define ENDPOINT_RST_MS100
> > +
> >  #define LINK_WAIT_MAX_RETRIES  10
> >  #define LINK_WAIT_USLEEP_MIN   9
> >  #define LINK_WAIT_USLEEP_MAX   10
> > @@ -242,8 +245,10 @@ static int advk_pcie_wait_for_link(struct advk_pcie 
> > *pcie)
> > return -ETIMEDOUT;
> >  }
> >  
> > -static void advk_pcie_setup_hw(struct advk_pcie *pcie)
> > +static void
> > +advk_pcie_setup_hw(struct advk_pcie *pcie, unsigned long ep_rdy_time)
> 
> Nit: I prefer the prototype to be in one line, I wrap it for you.
> 
> I am wondering why you need to pass in ep_rdy_time parameter when you
> can easily compute it in the function itself.
> 

The only reason for that is because the sooner I get the jiffies the
lower the delay has to be. I was trying to reduce the impact of this
delay to a minimum, but maybe the improvement is not worth it.

-- 
Remi


[PATCH v2] PCI: aardvark: Use LTSSM state to build link training flag

2019-03-16 Thread Remi Pommarel
The PCI_EXP_LNKSTA_LT flag in the emulated root device's PCI_EXP_LNKSTA
config register does not reflect the actual link training state and is
always cleared. The Link Training and Status State Machine (LTSSM) flag
in LMI config register could be used as a link training indicator.
Indeed if the LTSSM is in L0 or upper state then link training has
completed (see [1]).

Unfortunately because setting the PCI_EXP_LINCTL_RL flag does not
instantly imply a LTSSM state change (e.g. L0s to recovery state
transition takes some time), LTSSM can be in L0 but link training has
not finished yet. Thus a lower L0 LTSSM state followed by a L0 or upper
state sequence has to be seen to be sure that link training has been
done.

Because one may not call a pcie conf register read on LNKSTA after
doing a retrain link or may miss the link down state due to timing, a
20ms timeout is used. Passing this timeout link is considered retrained.

This fixes boot hang or kernel panic with the following callstack due to
ASPM setup doing a link re-train and polling for PCI_EXP_LNKSTA_LT flag
to be cleared before using it.

 8< ---
[0.915389]  dump_backtrace+0x0/0x140
[0.915391]  show_stack+0x14/0x20
[0.915393]  dump_stack+0x90/0xb4
[0.915394]  panic+0x134/0x2c0
[0.915396]  nmi_panic+0x6c/0x70
[0.915398]  arm64_serror_panic+0x74/0x80
[0.915400]  is_valid_bugaddr+0x0/0x8
[0.915402]  el1_error+0x7c/0xe4
[0.915404]  advk_pcie_rd_conf+0x4c/0x250
[0.915406]  pci_bus_read_config_word+0x7c/0xd0
[0.915408]  pcie_capability_read_word+0x90/0xc8
[0.915410]  pcie_get_aspm_reg+0x68/0x118
[0.915412]  pcie_aspm_init_link_state+0x460/0xa98
[0.915414]  pci_scan_slot+0xe8/0x100
[0.915416]  pci_scan_child_bus_extend+0x50/0x288
[0.915418]  pci_scan_bridge_extend+0x348/0x4f0
[0.915420]  pci_scan_child_bus_extend+0x1dc/0x288
[0.915423]  pci_scan_root_bus_bridge+0xc4/0xe0
[0.915424]  pci_host_probe+0x14/0xa8
[0.915426]  advk_pcie_probe+0x838/0x910
[...]
 8< ---

[1] "PCI Express Base Specification", REV. 2.1
PCI Express, March 4 2009, Table 4-7

Signed-off-by: Remi Pommarel 
---
Changes since v1:
  - Rename retraining flag field
  - Fix DEVCTL register writing
---
 drivers/pci/controller/pci-aardvark.c | 33 ++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pci-aardvark.c 
b/drivers/pci/controller/pci-aardvark.c
index eb58dfdaba1b..47b707b5fc2c 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -180,6 +180,7 @@
 #define LINK_WAIT_MAX_RETRIES  10
 #define LINK_WAIT_USLEEP_MIN   9
 #define LINK_WAIT_USLEEP_MAX   10
+#define LINK_RETRAIN_DELAY_MAX (20 * HZ / 1000) /* 20 ms */
 
 #define MSI_IRQ_NUM32
 
@@ -199,6 +200,8 @@ struct advk_pcie {
u16 msi_msg;
int root_bus_nr;
struct pci_bridge_emul bridge;
+   unsigned long rl_deadline; /* Retrain link jiffies deadline */
+   u8 rl_asked; /* Retraining has been asked and is in transition */
 };
 
 static inline void advk_writel(struct advk_pcie *pcie, u32 val, u64 reg)
@@ -400,6 +403,19 @@ static int advk_pcie_wait_pio(struct advk_pcie *pcie)
return -ETIMEDOUT;
 }
 
+static int advk_pcie_link_retraining(struct advk_pcie *pcie)
+{
+   if (!advk_pcie_link_up(pcie)) {
+   pcie->rl_asked = 0;
+   return 1;
+   }
+
+   if (pcie->rl_asked && time_before(jiffies, pcie->rl_deadline))
+   return 1;
+
+   pcie->rl_asked = 0;
+   return 0;
+}
 
 static pci_bridge_emul_read_status_t
 advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
@@ -426,11 +442,19 @@ advk_pci_bridge_emul_pcie_conf_read(struct 
pci_bridge_emul *bridge,
return PCI_BRIDGE_EMUL_HANDLED;
}
 
+   case PCI_EXP_LNKCTL: {
+   u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg) &
+   ~(PCI_EXP_LNKSTA_LT << 16);
+   if (advk_pcie_link_retraining(pcie))
+   val |= (PCI_EXP_LNKSTA_LT << 16);
+   *value = val;
+   return PCI_BRIDGE_EMUL_HANDLED;
+   }
+
case PCI_CAP_LIST_ID:
case PCI_EXP_DEVCAP:
case PCI_EXP_DEVCTL:
case PCI_EXP_LNKCAP:
-   case PCI_EXP_LNKCTL:
*value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
return PCI_BRIDGE_EMUL_HANDLED;
default:
@@ -447,8 +471,15 @@ advk_pci_bridge_emul_pcie_conf_write(struct 
pci_bridge_emul *bridge,
 
switch (reg) {
case PCI_EXP_DEVCTL:
+

[PATCH] pci: aardvark: Wait for endpoint to be ready before training link

2019-03-13 Thread Remi Pommarel
When configuring pcie reset pin from gpio (e.g. initially set by
u-boot) to pcie function this pin goes low for a brief moment
asserting the PERST# signal. Thus connected device enters fundamental
reset process and link configuration can only begin after a minimal
100ms delay (see [1]).

This makes sure that link is configured after at least 100ms from
beginning of probe() callback (shortly after the reset pin function
configuration switch through pinctrl subsytem).

[1] "PCI Express Base Specification", REV. 2.1
PCI Express, March 4 2009, 6.6.1 Conventional Reset

Signed-off-by: Remi Pommarel 
---
 drivers/pci/controller/pci-aardvark.c | 17 ++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/controller/pci-aardvark.c 
b/drivers/pci/controller/pci-aardvark.c
index a30ae7cf8e7e..70a1023d0ef1 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -177,6 +177,9 @@
 
 #define PIO_TIMEOUT_MS 1
 
+/* Endpoint can take up to 100ms to be ready after a reset */
+#define ENDPOINT_RST_MS100
+
 #define LINK_WAIT_MAX_RETRIES  10
 #define LINK_WAIT_USLEEP_MIN   9
 #define LINK_WAIT_USLEEP_MAX   10
@@ -242,8 +245,10 @@ static int advk_pcie_wait_for_link(struct advk_pcie *pcie)
return -ETIMEDOUT;
 }
 
-static void advk_pcie_setup_hw(struct advk_pcie *pcie)
+static void
+advk_pcie_setup_hw(struct advk_pcie *pcie, unsigned long ep_rdy_time)
 {
+   unsigned long now;
u32 reg;
 
/* Set to Direct mode */
@@ -327,9 +332,12 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
reg |= PIO_CTRL_ADDR_WIN_DISABLE;
advk_writel(pcie, reg, PIO_CTRL);
 
-   /* Start link training */
+   /* Wait for endpoint to exit reset state and start link training */
reg = advk_readl(pcie, PCIE_CORE_LINK_CTRL_STAT_REG);
reg |= PCIE_CORE_LINK_TRAINING;
+   now = jiffies;
+   if (time_before(now, ep_rdy_time))
+   msleep(jiffies_to_msecs(ep_rdy_time - now));
advk_writel(pcie, reg, PCIE_CORE_LINK_CTRL_STAT_REG);
 
advk_pcie_wait_for_link(pcie);
@@ -993,8 +1001,11 @@ static int advk_pcie_probe(struct platform_device *pdev)
struct advk_pcie *pcie;
struct resource *res;
struct pci_host_bridge *bridge;
+   unsigned long ep_rdy_time;
int ret, irq;
 
+   ep_rdy_time = jiffies + msecs_to_jiffies(ENDPOINT_RST_MS);
+
bridge = devm_pci_alloc_host_bridge(dev, sizeof(struct advk_pcie));
if (!bridge)
return -ENOMEM;
@@ -1022,7 +1033,7 @@ static int advk_pcie_probe(struct platform_device *pdev)
return ret;
}
 
-   advk_pcie_setup_hw(pcie);
+   advk_pcie_setup_hw(pcie, ep_rdy_time);
 
advk_sw_pci_bridge_init(pcie);
 
-- 
2.20.1



[PATCH] PCI: aardvark: Use LTSSM state to build link training flag

2019-03-05 Thread Remi Pommarel
The PCI_EXP_LNKSTA_LT flag in the emulated root device's PCI_EXP_LNKSTA
config register does not reflect the actual link training state and is
always cleared. The Link Training and Status State Machine (LTSSM) flag
in LMI config register could be used as a link training indicator.
Indeed if the LTSSM is in L0 or upper state then link training has
completed (see [1]).

Unfortunately because setting the PCI_EXP_LINCTL_RL flag does not
instantly imply a LTSSM state change (e.g. L0s to recovery state
transition takes some time), LTSSM can be in L0 but link training has
not finished yet. Thus a lower L0 LTSSM state followed by a L0 or upper
state sequence has to be seen to be sure that link training has been
done.

Because one may not call a pcie conf register read on LNKSTA after
doing a retrain link or may miss the link down state due to timing, a
20ms timeout is used. Passing this timeout link is considered retrained.

This fixes boot hang or kernel panic with the following callstack due to
ASPM setup doing a link re-train and polling for PCI_EXP_LNKSTA_LT flag
to be cleared before using it.

 8< ---
[0.915389]  dump_backtrace+0x0/0x140
[0.915391]  show_stack+0x14/0x20
[0.915393]  dump_stack+0x90/0xb4
[0.915394]  panic+0x134/0x2c0
[0.915396]  nmi_panic+0x6c/0x70
[0.915398]  arm64_serror_panic+0x74/0x80
[0.915400]  is_valid_bugaddr+0x0/0x8
[0.915402]  el1_error+0x7c/0xe4
[0.915404]  advk_pcie_rd_conf+0x4c/0x250
[0.915406]  pci_bus_read_config_word+0x7c/0xd0
[0.915408]  pcie_capability_read_word+0x90/0xc8
[0.915410]  pcie_get_aspm_reg+0x68/0x118
[0.915412]  pcie_aspm_init_link_state+0x460/0xa98
[0.915414]  pci_scan_slot+0xe8/0x100
[0.915416]  pci_scan_child_bus_extend+0x50/0x288
[0.915418]  pci_scan_bridge_extend+0x348/0x4f0
[0.915420]  pci_scan_child_bus_extend+0x1dc/0x288
[0.915423]  pci_scan_root_bus_bridge+0xc4/0xe0
[0.915424]  pci_host_probe+0x14/0xa8
[0.915426]  advk_pcie_probe+0x838/0x910
[...]
 8< ---

[1] "PCI Express Base Specification", REV. 2.1
PCI Express, March 4 2009, Table 4-7

Signed-off-by: Remi Pommarel 
---
Beside the lack of publicly available documentation I tried to find a
better workaround for this. But after having monitored every defined
registers, none seemed to reflect the actual link training state.
Vendor has been contacted about this issue about a month ago.
---
 drivers/pci/controller/pci-aardvark.c | 30 ++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pci-aardvark.c 
b/drivers/pci/controller/pci-aardvark.c
index eb58dfdaba1b..a30ae7cf8e7e 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -180,6 +180,7 @@
 #define LINK_WAIT_MAX_RETRIES  10
 #define LINK_WAIT_USLEEP_MIN   9
 #define LINK_WAIT_USLEEP_MAX   10
+#define LINK_RETRAIN_DELAY_MAX (20 * HZ / 1000) /* 20 ms */
 
 #define MSI_IRQ_NUM32
 
@@ -199,6 +200,8 @@ struct advk_pcie {
u16 msi_msg;
int root_bus_nr;
struct pci_bridge_emul bridge;
+   unsigned long rl_deadline; /* Retrain link jiffies deadline */
+   u8 retraining; /* Retraining has been asked and is in transition */
 };
 
 static inline void advk_writel(struct advk_pcie *pcie, u32 val, u64 reg)
@@ -400,6 +403,19 @@ static int advk_pcie_wait_pio(struct advk_pcie *pcie)
return -ETIMEDOUT;
 }
 
+static int advk_pcie_link_retraining(struct advk_pcie *pcie)
+{
+   if (!advk_pcie_link_up(pcie)) {
+   pcie->retraining = 0;
+   return 1;
+   }
+
+   if (pcie->retraining && time_before(jiffies, pcie->rl_deadline))
+   return 1;
+
+   pcie->retraining = 0;
+   return 0;
+}
 
 static pci_bridge_emul_read_status_t
 advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
@@ -426,11 +442,19 @@ advk_pci_bridge_emul_pcie_conf_read(struct 
pci_bridge_emul *bridge,
return PCI_BRIDGE_EMUL_HANDLED;
}
 
+   case PCI_EXP_LNKCTL: {
+   u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg) &
+   ~(PCI_EXP_LNKSTA_LT << 16);
+   if (advk_pcie_link_retraining(pcie))
+   val |= (PCI_EXP_LNKSTA_LT << 16);
+   *value = val;
+   return PCI_BRIDGE_EMUL_HANDLED;
+   }
+
case PCI_CAP_LIST_ID:
case PCI_EXP_DEVCAP:
case PCI_EXP_DEVCTL:
case PCI_EXP_LNKCAP:
-   case PCI_EXP_LNKCTL:
*value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
return PCI_BRI

Re: [PATCH] arm64: dts: armada-3720-espressobin: Configure RGMII and SMI pins

2019-01-28 Thread Remi Pommarel
This patch has been included in patchset [1], please ignore this one.

[1] https://lkml.org/lkml/2019/1/28/1876

-- 
Remi


[PATCH 1/2] arm64: dts: armada-3720-espressobin: Configure RGMII and SMI pins

2019-01-28 Thread Remi Pommarel
In order to be able to communicate with the 88e6341 switch some pins
have to be repurposed as RGMII and SMI pins.

This fixes ethernet support on system booted via a bootloader that
has not already configured those pins (e.g. mainline u-boot, or vendor
u-boot compiled without ethernet support).

Signed-off-by: Remi Pommarel 
---
 arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts | 2 ++
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi| 5 +
 2 files changed, 7 insertions(+)

diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts 
b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
index 846003bb480c..b60897edc885 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
@@ -196,6 +196,8 @@
 };
 
  {
+   pinctrl-names = "default";
+   pinctrl-0 = <_pins>, <_pins>;
phy-mode = "rgmii-id";
status = "okay";
 
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi 
b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index e05594ea15fb..f61538910901 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -271,6 +271,11 @@
function = "mii";
};
 
+   smi_pins: smi-pins {
+   groups = "smi";
+   function = "smi";
+   };
+
sdio_pins: sdio-pins {
groups = "sdio_sb";
function = "sdio";
-- 
2.20.1



[PATCH 2/2] arm64: dts: armada-3720-espressobin: Set mv88e6341 cpu port as RGMII-ID

2019-01-28 Thread Remi Pommarel
The mv88e6341 ethernet switch needs the cpu port control register to be
set with TX and RX internal delay in order to work.

This fixes ethernet support on system booted via a bootloader that
has not already configured this register (e.g. mainline u-boot, or
vendor u-boot compiled without ethernet support).

Signed-off-by: Remi Pommarel 
---
 arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts | 5 +
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts 
b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
index b60897edc885..86e8a1e3207f 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
@@ -156,6 +156,11 @@
reg = <0>;
label = "cpu";
ethernet = <>;
+   phy-mode = "rgmii-id";
+   fixed-link {
+   speed = <1000>;
+   full-duplex;
+   };
};
 
port@1 {
-- 
2.20.1



[PATCH 0/2] Fix espressobin ethernet support on mainline u-boot

2019-01-28 Thread Remi Pommarel
This patchset fixes ethernet and mv88e6341 switch support on espressobin
board when bootloader does not initialize needed registers.

This patchset should be applied along with pinctrl fixes from [1] which
have been merged in next branch of linux-pinctrl tree.

[1] https://lkml.org/lkml/2018/12/21/507

Remi Pommarel (2):
  arm64: dts: armada-3720-espressobin: Configure RGMII and SMI pins
  arm64: dts: armada-3720-espressobin: Set mv88e6341 cpu port as
RGMII-ID

 arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts | 7 +++
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi| 5 +
 2 files changed, 12 insertions(+)

-- 
2.20.1



[PATCH] arm64: dts: armada-3720-espressobin: Configure RGMII and SMI pins

2019-01-23 Thread Remi Pommarel
In order to be able to communicate with the 88e6341 switch some pins
have to be repurposed as RGMII and SMI pins.

This fixes ethernet support on system booted via a bootloader that
has not already configured those pins (e.g. mainline u-boot, or vendor
u-boot compiled without ethernet support).

Signed-off-by: Remi Pommarel 
---
This should be applied along with pinctrl fixes from
https://lkml.org/lkml/2018/12/21/507 which have been merged in next branch of
linux-pinctrl tree.
---
 arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts | 2 ++
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi| 5 +
 2 files changed, 7 insertions(+)

diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts 
b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
index 846003bb480c..b60897edc885 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
@@ -196,6 +196,8 @@
 };
 
  {
+   pinctrl-names = "default";
+   pinctrl-0 = <_pins>, <_pins>;
phy-mode = "rgmii-id";
status = "okay";
 
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi 
b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index e05594ea15fb..f61538910901 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -271,6 +271,11 @@
function = "mii";
};
 
+   smi_pins: smi-pins {
+   groups = "smi";
+   function = "smi";
+   };
+
sdio_pins: sdio-pins {
groups = "sdio_sb";
function = "sdio";
-- 
2.20.1



[PATCH v2] mmc: meson-gx: Free irq in release() callback

2019-01-10 Thread Remi Pommarel
Because the irq was requested through device managed resources API
(devm_request_threaded_irq()) it was freed after meson_mmc_remove()
completion, thus after mmc_free_host() has reclaimed meson_host memory.
As this irq is IRQF_SHARED, while using CONFIG_DEBUG_SHIRQ, its handler
get called by free_irq(). So meson_mmc_irq() was called after the
meson_host memory reclamation and was using invalid memory.

We ended up with the following scenario:
device_release_driver()
meson_mmc_remove()
mmc_free_host() /* Freeing host memory */
...
devres_release_all()
devm_irq_release()
__free_irq()
meson_mmc_irq() /* Uses freed memory */

To avoid this, the irq is released in meson_mmc_remove() and in
mseon_mmc_probe() error path before mmc_free_host() gets called.

This fixes https://marc.info/?l=linux-mmc=154707415208716.

Signed-off-by: Remi Pommarel 
---
Changes since v1:
- Fix it also in the error handling of probe callback
---
 drivers/mmc/host/meson-gx-mmc.c | 18 +++---
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
index c2690c1a50ff..f115d7c63ffe 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -179,6 +179,8 @@ struct meson_host {
struct sd_emmc_desc *descs;
dma_addr_t descs_dma_addr;
 
+   int irq;
+
bool vqmmc_enabled;
 };
 
@@ -1231,7 +1233,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
struct resource *res;
struct meson_host *host;
struct mmc_host *mmc;
-   int ret, irq;
+   int ret;
 
mmc = mmc_alloc_host(sizeof(struct meson_host), >dev);
if (!mmc)
@@ -1276,8 +1278,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
goto free_host;
}
 
-   irq = platform_get_irq(pdev, 0);
-   if (irq <= 0) {
+   host->irq = platform_get_irq(pdev, 0);
+   if (host->irq <= 0) {
dev_err(>dev, "failed to get interrupt resource.\n");
ret = -EINVAL;
goto free_host;
@@ -1331,9 +1333,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
writel(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN,
   host->regs + SD_EMMC_IRQ_EN);
 
-   ret = devm_request_threaded_irq(>dev, irq, meson_mmc_irq,
-   meson_mmc_irq_thread, IRQF_SHARED,
-   NULL, host);
+   ret = request_threaded_irq(host->irq, meson_mmc_irq,
+   meson_mmc_irq_thread, IRQF_SHARED, NULL, host);
if (ret)
goto err_init_clk;
 
@@ -1351,7 +1352,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
if (host->bounce_buf == NULL) {
dev_err(host->dev, "Unable to map allocate DMA bounce 
buffer.\n");
ret = -ENOMEM;
-   goto err_init_clk;
+   goto err_free_irq;
}
 
host->descs = dma_alloc_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
@@ -1370,6 +1371,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
 err_bounce_buf:
dma_free_coherent(host->dev, host->bounce_buf_size,
  host->bounce_buf, host->bounce_dma_addr);
+err_free_irq:
+   free_irq(host->irq, host);
 err_init_clk:
clk_disable_unprepare(host->mmc_clk);
 err_core_clk:
@@ -1387,6 +1390,7 @@ static int meson_mmc_remove(struct platform_device *pdev)
 
/* disable interrupts */
writel(0, host->regs + SD_EMMC_IRQ_EN);
+   free_irq(host->irq, host);
 
dma_free_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
  host->descs, host->descs_dma_addr);
-- 
2.20.1



Re: [PATCH] mmc: meson-gx: Free irq in release() callback

2019-01-10 Thread Remi Pommarel
On Thu, Jan 10, 2019 at 07:49:08PM +0100, Remi Pommarel wrote:
> Because the irq was requested through device managed resources API
> (devm_request_threaded_irq()) it was freed after meson_mmc_remove()
> completion, thus after mmc_free_host() has reclaimed meson_host memory.
> As this irq is IRQF_SHARED, while using CONFIG_DEBUG_SHIRQ, its handler
> get called by free_irq(). So meson_mmc_irq() was called after the
> meson_host memory reclamation and was using invalid memory.
> 
> We ended up with the following scenario:
> device_release_driver()
>   meson_mmc_remove()
>   mmc_free_host() /* Freeing host memory */
>   ...
>   devres_release_all()
>   devm_irq_release()
>   __free_irq()
>   meson_mmc_irq() /* Uses freed memory */
> 
> To avoid this, the irq is released in meson_mmc_remove() before
> mmc_free_host() gets called.
> 

Oups, I missed the fact that the same can happen if probe() callback
fails after allocating the irq.

I will send a V2 for that.

-- 
Remi


[PATCH] mmc: meson-gx: Free irq in release() callback

2019-01-10 Thread Remi Pommarel
Because the irq was requested through device managed resources API
(devm_request_threaded_irq()) it was freed after meson_mmc_remove()
completion, thus after mmc_free_host() has reclaimed meson_host memory.
As this irq is IRQF_SHARED, while using CONFIG_DEBUG_SHIRQ, its handler
get called by free_irq(). So meson_mmc_irq() was called after the
meson_host memory reclamation and was using invalid memory.

We ended up with the following scenario:
device_release_driver()
meson_mmc_remove()
mmc_free_host() /* Freeing host memory */
...
devres_release_all()
devm_irq_release()
__free_irq()
meson_mmc_irq() /* Uses freed memory */

To avoid this, the irq is released in meson_mmc_remove() before
mmc_free_host() gets called.

This fixes https://marc.info/?l=linux-mmc=154707415208716.

Signed-off-by: Remi Pommarel 
---
 drivers/mmc/host/meson-gx-mmc.c | 14 --
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
index c2690c1a50ff..412cfd16bf15 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -179,6 +179,8 @@ struct meson_host {
struct sd_emmc_desc *descs;
dma_addr_t descs_dma_addr;
 
+   int irq;
+
bool vqmmc_enabled;
 };
 
@@ -1231,7 +1233,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
struct resource *res;
struct meson_host *host;
struct mmc_host *mmc;
-   int ret, irq;
+   int ret;
 
mmc = mmc_alloc_host(sizeof(struct meson_host), >dev);
if (!mmc)
@@ -1276,8 +1278,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
goto free_host;
}
 
-   irq = platform_get_irq(pdev, 0);
-   if (irq <= 0) {
+   host->irq = platform_get_irq(pdev, 0);
+   if (host->irq <= 0) {
dev_err(>dev, "failed to get interrupt resource.\n");
ret = -EINVAL;
goto free_host;
@@ -1331,9 +1333,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
writel(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN,
   host->regs + SD_EMMC_IRQ_EN);
 
-   ret = devm_request_threaded_irq(>dev, irq, meson_mmc_irq,
-   meson_mmc_irq_thread, IRQF_SHARED,
-   NULL, host);
+   ret = devm_request_threaded_irq(>dev, host->irq, meson_mmc_irq,
+   meson_mmc_irq_thread, IRQF_SHARED, NULL, host);
if (ret)
goto err_init_clk;
 
@@ -1387,6 +1388,7 @@ static int meson_mmc_remove(struct platform_device *pdev)
 
/* disable interrupts */
writel(0, host->regs + SD_EMMC_IRQ_EN);
+   devm_free_irq(host->dev, host->irq, host);
 
dma_free_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
  host->descs, host->descs_dma_addr);
-- 
2.20.1



Re: [PATCH 0/4] Add specific vt input's key map

2018-09-12 Thread Remi Pommarel
On Wed, Sep 12, 2018 at 03:35:19PM +0100, Alan Cox wrote:
> On Tue, 11 Sep 2018 22:23:55 +0200
> Remi Pommarel  wrote:
> 
> > This patchset adds a way to have a specific keyboard config (i.e.
> > keycode to keysym map) for a vt attached input.
> 
> Who actually needs this given that you can't even render most
> international symbols in text mode and X and friends already deal with
> mapping of keyboards at this degree of fine-ness and even more so ?

Let say you share one computer among people used to different keyboard
layouts, so you have plugged in one keyboard for each of those people.
Let say you have encrypted your disk with a long passphrase, the one
that boots up the computer has to enter it. It could be annoying to
learn another layout just to enter a passphrase to boot. This allows to
set an udev rule in initrd to use a different layout per keyboard so
every people using this computer can use their favorite layout to enter
the passphrase.

I am in such a situation and so is @Elie.

I also don't start X server at boot time (or sometimes I switch to a linux
VT) it is not very convenient for me to switch layout to enter my password,
or even to type "startx".

I do agree that it is not an absolute must-have or shiny feature, it is
just a convenient one, at least for me.

-- 
Remi


Re: [PATCH 0/4] Add specific vt input's key map

2018-09-12 Thread Remi Pommarel
On Wed, Sep 12, 2018 at 03:35:19PM +0100, Alan Cox wrote:
> On Tue, 11 Sep 2018 22:23:55 +0200
> Remi Pommarel  wrote:
> 
> > This patchset adds a way to have a specific keyboard config (i.e.
> > keycode to keysym map) for a vt attached input.
> 
> Who actually needs this given that you can't even render most
> international symbols in text mode and X and friends already deal with
> mapping of keyboards at this degree of fine-ness and even more so ?

Let say you share one computer among people used to different keyboard
layouts, so you have plugged in one keyboard for each of those people.
Let say you have encrypted your disk with a long passphrase, the one
that boots up the computer has to enter it. It could be annoying to
learn another layout just to enter a passphrase to boot. This allows to
set an udev rule in initrd to use a different layout per keyboard so
every people using this computer can use their favorite layout to enter
the passphrase.

I am in such a situation and so is @Elie.

I also don't start X server at boot time (or sometimes I switch to a linux
VT) it is not very convenient for me to switch layout to enter my password,
or even to type "startx".

I do agree that it is not an absolute must-have or shiny feature, it is
just a convenient one, at least for me.

-- 
Remi


Re: [RFC PATCH 0/4] Add specific vt input's key map

2018-09-12 Thread Remi Pommarel
Hi,
 
On Tue, Sep 11, 2018 at 08:47:55PM +0200, Greg Kroah-Hartman wrote:  
> 
> Normally I do not review "RFC" patches as it implies the submitter does
> not think they are a valid solution.  How about resending them as if you
> think this is something ready to be merged?

I had used "RFC" here because I had one or two questions about the
implementation choices I made on those patches and not really on the
solution itself. So, yes, I don't mind sending another round of those
patches without RFC.

Thanks,

-- 
Remi



Re: [RFC PATCH 0/4] Add specific vt input's key map

2018-09-12 Thread Remi Pommarel
Hi,
 
On Tue, Sep 11, 2018 at 08:47:55PM +0200, Greg Kroah-Hartman wrote:  
> 
> Normally I do not review "RFC" patches as it implies the submitter does
> not think they are a valid solution.  How about resending them as if you
> think this is something ready to be merged?

I had used "RFC" here because I had one or two questions about the
implementation choices I made on those patches and not really on the
solution itself. So, yes, I don't mind sending another round of those
patches without RFC.

Thanks,

-- 
Remi



[PATCH 1/4] drivers/tty/vt/keyboard.c: refactor getting/setting a keymap entry

2018-09-11 Thread Remi Pommarel
In order to ease the addition of the ability of an input to use a
different key configuration (keycode to keysym map), the operations of
getting and setting an entry in a key map is moved in respective
functions.

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 201 ++
 1 file changed, 118 insertions(+), 83 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 88312c6c92cc..89fabb8ae04e 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1874,115 +1874,150 @@ int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode 
__user *user_kbkc,
return kc;
 }
 
-#define i (tmp.kb_index)
-#define s (tmp.kb_table)
-#define v (tmp.kb_value)
+#define i (kbe->kb_index)
+#define s (kbe->kb_table)
+#define v (kbe->kb_value)
 
-int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
-   int console)
+/*
+ * Get a keysym value from a key map
+ *
+ * @kb: Virtual console structure
+ * @kmaps: Key map array
+ * @kbe : Entry to find in key map
+ */
+static ushort __kdsk_getent(struct kbd_struct const *kb, ushort **kmaps,
+   struct kbentry const *kbe)
 {
-   struct kbd_struct *kb = kbd_table + console;
-   struct kbentry tmp;
-   ushort *key_map, *new_map, val, ov;
+   ushort *key_map, val;
unsigned long flags;
 
-   if (copy_from_user(, user_kbe, sizeof(struct kbentry)))
-   return -EFAULT;
+   /* Ensure another thread doesn't free it under us */
+   spin_lock_irqsave(_event_lock, flags);
+   key_map = kmaps[s];
+   if (key_map) {
+   val = U(key_map[i]);
+   if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
+   val = K_HOLE;
+   } else
+   val = (i ? K_HOLE : K_NOSUCHMAP);
+   spin_unlock_irqrestore(_event_lock, flags);
 
-   if (!capable(CAP_SYS_TTY_CONFIG))
-   perm = 0;
+   return val;
+}
 
-   switch (cmd) {
-   case KDGKBENT:
-   /* Ensure another thread doesn't free it under us */
+/*
+ * Set a keysym value in a key map
+ *
+ * @kb: Virtual console structure
+ * @kmaps: Key map array
+ * @kbe : Entry to set in key map
+ */
+static int __kdsk_setent(struct kbd_struct const *kb, ushort **kmaps,
+   struct kbentry const *kbe)
+{
+   ushort *key_map, *new_map, ov;
+   unsigned long flags;
+
+   if (!i && v == K_NOSUCHMAP) {
spin_lock_irqsave(_event_lock, flags);
-   key_map = key_maps[s];
-   if (key_map) {
-   val = U(key_map[i]);
-   if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
-   val = K_HOLE;
-   } else
-   val = (i ? K_HOLE : K_NOSUCHMAP);
-   spin_unlock_irqrestore(_event_lock, flags);
-   return put_user(val, _kbe->kb_value);
-   case KDSKBENT:
-   if (!perm)
-   return -EPERM;
-   if (!i && v == K_NOSUCHMAP) {
-   spin_lock_irqsave(_event_lock, flags);
-   /* deallocate map */
-   key_map = key_maps[s];
-   if (s && key_map) {
-   key_maps[s] = NULL;
-   if (key_map[0] == U(K_ALLOCATED)) {
-   kfree(key_map);
-   keymap_count--;
-   }
+   /* deallocate map */
+   key_map = kmaps[s];
+   if (s && key_map) {
+   kmaps[s] = NULL;
+   if (key_map[0] == U(K_ALLOCATED)) {
+   kfree(key_map);
+   keymap_count--;
}
-   spin_unlock_irqrestore(_event_lock, flags);
-   break;
}
+   spin_unlock_irqrestore(_event_lock, flags);
+   return 0;
+   }
 
-   if (KTYP(v) < NR_TYPES) {
-   if (KVAL(v) > max_vals[KTYP(v)])
-   return -EINVAL;
-   } else
-   if (kb->kbdmode != VC_UNICODE)
-   return -EINVAL;
+   if (KTYP(v) < NR_TYPES) {
+   if (KVAL(v) > max_vals[KTYP(v)])
+   return -EINVAL;
+   } else if (kb->kbdmode != VC_UNICODE)
+   return -EINVAL;
 
-   /* ++Geert: non-PC keyboards may generate keycode zero */
+   /* ++Geert: non-PC keyboards may generate keycode zero */
 #if !defined(__mc68000__) && !defined(__powerpc__)
-   /* assignment to entry 0 only tests validity of args */
-   i

[PATCH 0/4] Add specific vt input's key map

2018-09-11 Thread Remi Pommarel
This patchset adds a way to have a specific keyboard config (i.e.
keycode to keysym map) for a vt attached input.

Because one can have different keyboards with different layouts on the
same VT, it can be useful to be able to associate a different keymap
with a different input. In order to do so this patchset introduces
three new ioctls:

1) KDGKBIENT
Get an input key map's entry. If the input does not have a
specific key map the requested entry is fetched from global
key map.

2) KDSKBIENT
Set an input key map's entry. If the input does not yet have a
specific key map, a new one is created with the current global
key map content copied in.

3) KDSKBIRST
Reset an input key map. The input does not use a specific key
map anymore and keycode translations are done with global key
map.

In order to keep old behavior compatibility and not waste memory, an
input uses the global key_maps[] array by default and KDGKBENT/KDSKBENT
ioctls still get/set entries in this global key map. The specific key
map is only allocated on the first call to KDSKBIENT.

A patch for loadkeys is ready to be sent to the ML if this patchset
seems sane to you.

Here are some questions I had while doing this patchset:

- Is it ok to add new ioctl to old legacy code ? I added those ioctl
  the old way in order to match the header style. Maybe it is better to
  use the __IO* macros ?

- I am not quite sure about the meaning of keymap_count. IIUC, it is a
  counter of used keymap function arrays statically or dynamically
  allocated. If it is not the case, the modificiation in kc_setent() that
  decrements keymap_count even if a statically keymap function is removed
  with "K_NOSUCHMAP" (in PATCH 2/4) may be wrong ?

- kbd_detach_conf is a bit clumsy because it tries to copy a shared sparse
  pointer array without using GFP_ATOMIC.

Remi Pommarel (4):
  drivers/tty/vt/keyboard.c: refactor getting/setting a keymap entry
  drivers/tty/vt/keyboard.c: add keyboard config for each vt's input
  drivers/tty/vt/keyboard.c: Make key_down[] bitmap input dependent
  drivers/tty/vt: add ioctl to manage input specific keyboard configs

 drivers/tty/vt/keyboard.c | 531 ++
 drivers/tty/vt/vt_ioctl.c |   9 +
 fs/compat_ioctl.c |   3 +
 include/linux/vt_kern.h   |   4 +
 include/uapi/linux/kd.h   |   9 +
 5 files changed, 452 insertions(+), 104 deletions(-)

-- 
2.18.0



[PATCH 1/4] drivers/tty/vt/keyboard.c: refactor getting/setting a keymap entry

2018-09-11 Thread Remi Pommarel
In order to ease the addition of the ability of an input to use a
different key configuration (keycode to keysym map), the operations of
getting and setting an entry in a key map is moved in respective
functions.

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 201 ++
 1 file changed, 118 insertions(+), 83 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 88312c6c92cc..89fabb8ae04e 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1874,115 +1874,150 @@ int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode 
__user *user_kbkc,
return kc;
 }
 
-#define i (tmp.kb_index)
-#define s (tmp.kb_table)
-#define v (tmp.kb_value)
+#define i (kbe->kb_index)
+#define s (kbe->kb_table)
+#define v (kbe->kb_value)
 
-int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
-   int console)
+/*
+ * Get a keysym value from a key map
+ *
+ * @kb: Virtual console structure
+ * @kmaps: Key map array
+ * @kbe : Entry to find in key map
+ */
+static ushort __kdsk_getent(struct kbd_struct const *kb, ushort **kmaps,
+   struct kbentry const *kbe)
 {
-   struct kbd_struct *kb = kbd_table + console;
-   struct kbentry tmp;
-   ushort *key_map, *new_map, val, ov;
+   ushort *key_map, val;
unsigned long flags;
 
-   if (copy_from_user(, user_kbe, sizeof(struct kbentry)))
-   return -EFAULT;
+   /* Ensure another thread doesn't free it under us */
+   spin_lock_irqsave(_event_lock, flags);
+   key_map = kmaps[s];
+   if (key_map) {
+   val = U(key_map[i]);
+   if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
+   val = K_HOLE;
+   } else
+   val = (i ? K_HOLE : K_NOSUCHMAP);
+   spin_unlock_irqrestore(_event_lock, flags);
 
-   if (!capable(CAP_SYS_TTY_CONFIG))
-   perm = 0;
+   return val;
+}
 
-   switch (cmd) {
-   case KDGKBENT:
-   /* Ensure another thread doesn't free it under us */
+/*
+ * Set a keysym value in a key map
+ *
+ * @kb: Virtual console structure
+ * @kmaps: Key map array
+ * @kbe : Entry to set in key map
+ */
+static int __kdsk_setent(struct kbd_struct const *kb, ushort **kmaps,
+   struct kbentry const *kbe)
+{
+   ushort *key_map, *new_map, ov;
+   unsigned long flags;
+
+   if (!i && v == K_NOSUCHMAP) {
spin_lock_irqsave(_event_lock, flags);
-   key_map = key_maps[s];
-   if (key_map) {
-   val = U(key_map[i]);
-   if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
-   val = K_HOLE;
-   } else
-   val = (i ? K_HOLE : K_NOSUCHMAP);
-   spin_unlock_irqrestore(_event_lock, flags);
-   return put_user(val, _kbe->kb_value);
-   case KDSKBENT:
-   if (!perm)
-   return -EPERM;
-   if (!i && v == K_NOSUCHMAP) {
-   spin_lock_irqsave(_event_lock, flags);
-   /* deallocate map */
-   key_map = key_maps[s];
-   if (s && key_map) {
-   key_maps[s] = NULL;
-   if (key_map[0] == U(K_ALLOCATED)) {
-   kfree(key_map);
-   keymap_count--;
-   }
+   /* deallocate map */
+   key_map = kmaps[s];
+   if (s && key_map) {
+   kmaps[s] = NULL;
+   if (key_map[0] == U(K_ALLOCATED)) {
+   kfree(key_map);
+   keymap_count--;
}
-   spin_unlock_irqrestore(_event_lock, flags);
-   break;
}
+   spin_unlock_irqrestore(_event_lock, flags);
+   return 0;
+   }
 
-   if (KTYP(v) < NR_TYPES) {
-   if (KVAL(v) > max_vals[KTYP(v)])
-   return -EINVAL;
-   } else
-   if (kb->kbdmode != VC_UNICODE)
-   return -EINVAL;
+   if (KTYP(v) < NR_TYPES) {
+   if (KVAL(v) > max_vals[KTYP(v)])
+   return -EINVAL;
+   } else if (kb->kbdmode != VC_UNICODE)
+   return -EINVAL;
 
-   /* ++Geert: non-PC keyboards may generate keycode zero */
+   /* ++Geert: non-PC keyboards may generate keycode zero */
 #if !defined(__mc68000__) && !defined(__powerpc__)
-   /* assignment to entry 0 only tests validity of args */
-   i

[PATCH 0/4] Add specific vt input's key map

2018-09-11 Thread Remi Pommarel
This patchset adds a way to have a specific keyboard config (i.e.
keycode to keysym map) for a vt attached input.

Because one can have different keyboards with different layouts on the
same VT, it can be useful to be able to associate a different keymap
with a different input. In order to do so this patchset introduces
three new ioctls:

1) KDGKBIENT
Get an input key map's entry. If the input does not have a
specific key map the requested entry is fetched from global
key map.

2) KDSKBIENT
Set an input key map's entry. If the input does not yet have a
specific key map, a new one is created with the current global
key map content copied in.

3) KDSKBIRST
Reset an input key map. The input does not use a specific key
map anymore and keycode translations are done with global key
map.

In order to keep old behavior compatibility and not waste memory, an
input uses the global key_maps[] array by default and KDGKBENT/KDSKBENT
ioctls still get/set entries in this global key map. The specific key
map is only allocated on the first call to KDSKBIENT.

A patch for loadkeys is ready to be sent to the ML if this patchset
seems sane to you.

Here are some questions I had while doing this patchset:

- Is it ok to add new ioctl to old legacy code ? I added those ioctl
  the old way in order to match the header style. Maybe it is better to
  use the __IO* macros ?

- I am not quite sure about the meaning of keymap_count. IIUC, it is a
  counter of used keymap function arrays statically or dynamically
  allocated. If it is not the case, the modificiation in kc_setent() that
  decrements keymap_count even if a statically keymap function is removed
  with "K_NOSUCHMAP" (in PATCH 2/4) may be wrong ?

- kbd_detach_conf is a bit clumsy because it tries to copy a shared sparse
  pointer array without using GFP_ATOMIC.

Remi Pommarel (4):
  drivers/tty/vt/keyboard.c: refactor getting/setting a keymap entry
  drivers/tty/vt/keyboard.c: add keyboard config for each vt's input
  drivers/tty/vt/keyboard.c: Make key_down[] bitmap input dependent
  drivers/tty/vt: add ioctl to manage input specific keyboard configs

 drivers/tty/vt/keyboard.c | 531 ++
 drivers/tty/vt/vt_ioctl.c |   9 +
 fs/compat_ioctl.c |   3 +
 include/linux/vt_kern.h   |   4 +
 include/uapi/linux/kd.h   |   9 +
 5 files changed, 452 insertions(+), 104 deletions(-)

-- 
2.18.0



[PATCH 3/4] drivers/tty/vt/keyboard.c: Make key_down[] bitmap input dependent

2018-09-11 Thread Remi Pommarel
A kbd_handle input can have a specific keyboard config that makes
keycode to keysym mapping array different from another one. Because
key_down[] bitmap stores currently pressed key as keycode, it should be
associated with an input keymap in order to retrieve the associated
keysym.

Allocating this array in each input allows to retrieve its associated
keymap.

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 46 +++
 1 file changed, 32 insertions(+), 14 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 4f09331ad5c3..7272e1828838 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -122,6 +122,7 @@ struct kbd_handle {
struct kref ref;
struct kbd_conf *conf;
struct input_handle handle;
+   unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];/* keyboard key bitmap */
 };
 #define hdl_to_kbd_handle(h) (container_of(h, struct kbd_handle, handle))
 
@@ -140,7 +141,6 @@ static const int NR_TYPES = ARRAY_SIZE(max_vals);
 static struct input_handler kbd_handler;
 static DEFINE_SPINLOCK(kbd_event_lock);
 static DEFINE_SPINLOCK(led_lock);
-static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap 
*/
 static unsigned char shift_down[NR_SHIFT]; /* shift state 
counters.. */
 static bool dead_key_next;
 static int npadch = -1;/* -1 or number 
assembled on pad */
@@ -378,20 +378,18 @@ static void to_utf8(struct vc_data *vc, uint c)
 
 /*
  * Called after returning from RAW mode or when changing consoles - recompute
- * shift_down[] and shift_state from key_down[] maybe called when keymap is
- * undefined, so that shiftkey release is seen. The caller must hold the
- * kbd_event_lock.
+ * shift_down[] and shift_state from each input's key_down[] maybe called when
+ * keymap is undefined, so that shiftkey release is seen. The caller must hold
+ * the kbd_event_lock.
  */
 
-static void do_compute_shiftstate(void)
+static int do_compute_input_shiftstate(struct input_handle *handle, void *data)
 {
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
unsigned int k, sym, val;
 
-   shift_state = 0;
-   memset(shift_down, 0, sizeof(shift_down));
-
-   for_each_set_bit(k, key_down, min(NR_KEYS, KEY_CNT)) {
-   sym = U(key_maps[0][k]);
+   for_each_set_bit(k, kh->key_down, min(NR_KEYS, KEY_CNT)) {
+   sym = U(kh->conf->maps[0][k]);
if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
continue;
 
@@ -402,6 +400,15 @@ static void do_compute_shiftstate(void)
shift_down[val]++;
shift_state |= BIT(val);
}
+   return 0;
+}
+
+static void do_compute_shiftstate(void)
+{
+   shift_state = 0;
+   memset(shift_down, 0, sizeof(shift_down));
+   input_handler_for_each_handle(_handler, NULL,
+   do_compute_input_shiftstate);
 }
 
 /* We still have to export this method to vt.c */
@@ -1278,6 +1285,17 @@ static int sparc_l1_a_state;
 extern void sun_do_break(void);
 #endif
 
+static int is_alt_down(struct input_handle *handle, void *data)
+{
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
+
+   if (test_bit(KEY_LEFTALT, kh->key_down) ||
+   test_bit(KEY_RIGHTALT, kh->key_down))
+   return 1;
+
+   return 0;
+}
+
 static int emulate_raw(struct vc_data *vc, unsigned int keycode,
   unsigned char up_flag)
 {
@@ -1308,8 +1326,8 @@ static int emulate_raw(struct vc_data *vc, unsigned int 
keycode,
 * pressing PrtSc/SysRq alone, but simply 0x54
 * when pressing Alt+PrtSc/SysRq.
 */
-   if (test_bit(KEY_LEFTALT, key_down) ||
-   test_bit(KEY_RIGHTALT, key_down)) {
+   if (input_handler_for_each_handle(_handler, NULL,
+   is_alt_down)) {
put_queue(vc, 0x54 | up_flag);
} else {
put_queue(vc, 0xe0);
@@ -1424,9 +1442,9 @@ static void kbd_keycode(struct kbd_handle *kh, unsigned 
int keycode, int down,
}
 
if (down)
-   set_bit(keycode, key_down);
+   set_bit(keycode, kh->key_down);
else
-   clear_bit(keycode, key_down);
+   clear_bit(keycode, kh->key_down);
 
if (rep &&
(!vc_kbd_mode(kbd, VC_REPEAT) ||
-- 
2.18.0



[PATCH 3/4] drivers/tty/vt/keyboard.c: Make key_down[] bitmap input dependent

2018-09-11 Thread Remi Pommarel
A kbd_handle input can have a specific keyboard config that makes
keycode to keysym mapping array different from another one. Because
key_down[] bitmap stores currently pressed key as keycode, it should be
associated with an input keymap in order to retrieve the associated
keysym.

Allocating this array in each input allows to retrieve its associated
keymap.

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 46 +++
 1 file changed, 32 insertions(+), 14 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 4f09331ad5c3..7272e1828838 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -122,6 +122,7 @@ struct kbd_handle {
struct kref ref;
struct kbd_conf *conf;
struct input_handle handle;
+   unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];/* keyboard key bitmap */
 };
 #define hdl_to_kbd_handle(h) (container_of(h, struct kbd_handle, handle))
 
@@ -140,7 +141,6 @@ static const int NR_TYPES = ARRAY_SIZE(max_vals);
 static struct input_handler kbd_handler;
 static DEFINE_SPINLOCK(kbd_event_lock);
 static DEFINE_SPINLOCK(led_lock);
-static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap 
*/
 static unsigned char shift_down[NR_SHIFT]; /* shift state 
counters.. */
 static bool dead_key_next;
 static int npadch = -1;/* -1 or number 
assembled on pad */
@@ -378,20 +378,18 @@ static void to_utf8(struct vc_data *vc, uint c)
 
 /*
  * Called after returning from RAW mode or when changing consoles - recompute
- * shift_down[] and shift_state from key_down[] maybe called when keymap is
- * undefined, so that shiftkey release is seen. The caller must hold the
- * kbd_event_lock.
+ * shift_down[] and shift_state from each input's key_down[] maybe called when
+ * keymap is undefined, so that shiftkey release is seen. The caller must hold
+ * the kbd_event_lock.
  */
 
-static void do_compute_shiftstate(void)
+static int do_compute_input_shiftstate(struct input_handle *handle, void *data)
 {
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
unsigned int k, sym, val;
 
-   shift_state = 0;
-   memset(shift_down, 0, sizeof(shift_down));
-
-   for_each_set_bit(k, key_down, min(NR_KEYS, KEY_CNT)) {
-   sym = U(key_maps[0][k]);
+   for_each_set_bit(k, kh->key_down, min(NR_KEYS, KEY_CNT)) {
+   sym = U(kh->conf->maps[0][k]);
if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
continue;
 
@@ -402,6 +400,15 @@ static void do_compute_shiftstate(void)
shift_down[val]++;
shift_state |= BIT(val);
}
+   return 0;
+}
+
+static void do_compute_shiftstate(void)
+{
+   shift_state = 0;
+   memset(shift_down, 0, sizeof(shift_down));
+   input_handler_for_each_handle(_handler, NULL,
+   do_compute_input_shiftstate);
 }
 
 /* We still have to export this method to vt.c */
@@ -1278,6 +1285,17 @@ static int sparc_l1_a_state;
 extern void sun_do_break(void);
 #endif
 
+static int is_alt_down(struct input_handle *handle, void *data)
+{
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
+
+   if (test_bit(KEY_LEFTALT, kh->key_down) ||
+   test_bit(KEY_RIGHTALT, kh->key_down))
+   return 1;
+
+   return 0;
+}
+
 static int emulate_raw(struct vc_data *vc, unsigned int keycode,
   unsigned char up_flag)
 {
@@ -1308,8 +1326,8 @@ static int emulate_raw(struct vc_data *vc, unsigned int 
keycode,
 * pressing PrtSc/SysRq alone, but simply 0x54
 * when pressing Alt+PrtSc/SysRq.
 */
-   if (test_bit(KEY_LEFTALT, key_down) ||
-   test_bit(KEY_RIGHTALT, key_down)) {
+   if (input_handler_for_each_handle(_handler, NULL,
+   is_alt_down)) {
put_queue(vc, 0x54 | up_flag);
} else {
put_queue(vc, 0xe0);
@@ -1424,9 +1442,9 @@ static void kbd_keycode(struct kbd_handle *kh, unsigned 
int keycode, int down,
}
 
if (down)
-   set_bit(keycode, key_down);
+   set_bit(keycode, kh->key_down);
else
-   clear_bit(keycode, key_down);
+   clear_bit(keycode, kh->key_down);
 
if (rep &&
(!vc_kbd_mode(kbd, VC_REPEAT) ||
-- 
2.18.0



[PATCH 4/4] drivers/tty/vt: add ioctl to manage input specific keyboard configs

2018-09-11 Thread Remi Pommarel
Because user can use different keyboards with different layouts on the
same tty, an input could have a different key map from another one. In
order to use and modify this specific key map the user can call three
new ioctls:

1) KDGKBIENT
Get an input key map's entry. If the input does not have a
specific keyboard config the requested entry is fetched from
global key map.

2) KDSKBIENT
Set an input key map's entry. If the input does not yet have a
specific keyboard config, a new one is created with the current
global config (the one modified with KDSKBENT) content copied
in.

3) KDSKBIRST
Reset an input key map. The input does not use a specific
keyboard config anymore and keycode translations are done with
global key map.

In order to remain compatible with old behavior, an input uses global
key map by default and KDGKENT/KDSKENT still get/set entries in the
global key map.

Below is an example of this ioctl usage:
- 8< -
struct kbientry kbi = {
.id = { /* Input is found by its input_id */
.bustype = 0x0003,
.product = 0x00B2,
.vendor = 0x2319,
.version = 0x0200,
},
.entry = { /* Entry to set or get */
.kb_table = 0,
.kb_index = 0x10,
.kb_value = 0x0B61,
},
};
int ret;

/* First set new entry for input 0003:00B2:2319:0200 */
ret = ioctl(fd, KDSKBIENT, ); /* fd is a tty open file */
if(ret < 0)
/* Error handling */

/* Get specific entry, on success kbi.entry.kb_value will be set */
ret = ioctl(fd, KDSKBIENT, );
if(ret < 0)
/* Error handling */

/* Reset input key map so that global key_maps is used */
ret = ioctl(fd, KDSKBIRST, );
if(ret < 0)
/* Error handling */
- 8< -

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 126 ++
 drivers/tty/vt/vt_ioctl.c |   9 +++
 fs/compat_ioctl.c |   3 +
 include/linux/vt_kern.h   |   4 ++
 include/uapi/linux/kd.h   |   9 +++
 5 files changed, 151 insertions(+)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 7272e1828838..9707d1ebeab4 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -2180,6 +2180,132 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user 
*user_kbe, int perm,
return ret;
 }
 
+/*
+ * Input keymap helper functions
+ */
+struct kbd_lookup_data {
+   struct input_id *id;
+   struct kbd_handle *kh;
+};
+
+static int _kbd_get_helper(struct input_handle *handle, void *data)
+{
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
+   struct kbd_lookup_data *d = data;
+
+   if (memcmp(d->id, >dev->id, sizeof(*d->id)) != 0)
+   return 0;
+
+   d->kh = kh;
+   kref_get(>ref);
+   return 1;
+}
+
+/*
+ * Get an input specific handle.
+ * The caller will hold a reference on the found kbd_handle, if it exists, and
+ * should deref it after usage (with kbd_put).
+ */
+static int kbd_get(struct kbd_handle **kh, struct input_id *id)
+{
+   struct kbd_lookup_data d = {
+   .id = id,
+   };
+   int ret;
+
+   ret = input_handler_for_each_handle(_handler, , _kbd_get_helper);
+   *kh = d.kh;
+
+   return (ret == 0);
+}
+
+static void kbd_put(struct kbd_handle *kh)
+{
+   kref_put(>ref, kbd_destroy);
+}
+
+int vt_do_kdski_ioctl(int cmd, struct kbientry __user *user_kbie, int perm,
+   int console)
+{
+   struct kbd_struct *kb = kbd_table + console;
+   struct kbd_handle *kh;
+   struct kbientry tmp;
+   ushort val;
+   int ret = 0;
+
+   if (copy_from_user(, user_kbie, sizeof(struct kbientry))) {
+   ret = -EFAULT;
+   goto out;
+   }
+
+   if (!capable(CAP_SYS_TTY_CONFIG))
+   perm = 0;
+
+   ret = kbd_get(, );
+   if (ret != 0) {
+   ret = -EINVAL;
+   goto out;
+   }
+
+   switch (cmd) {
+   case KDGKBIENT:
+   val = kc_getent(kb, kh->conf, );
+   ret = put_user(val, _kbie->entry.kb_value);
+   break;
+   case KDSKBIENT:
+   if (!perm) {
+   ret = -EPERM;
+   break;
+   }
+   /* A keyconf's keymap is created only if global one is used */
+   ret = kbd_detach_conf(kh);
+   if (ret != 0)
+   break;
+
+   ret = kc_setent(kb, kh->conf, );
+   break;
+   }
+
+   kbd_put(kh);
+out:
+   return ret;
+}
+
+int vt_do_kdskirst_ioctl(int cmd, struct input_id __user *user_iid, int perm,
+   int console)
+{
+   struct kbd_handle *kh;
+

[PATCH 4/4] drivers/tty/vt: add ioctl to manage input specific keyboard configs

2018-09-11 Thread Remi Pommarel
Because user can use different keyboards with different layouts on the
same tty, an input could have a different key map from another one. In
order to use and modify this specific key map the user can call three
new ioctls:

1) KDGKBIENT
Get an input key map's entry. If the input does not have a
specific keyboard config the requested entry is fetched from
global key map.

2) KDSKBIENT
Set an input key map's entry. If the input does not yet have a
specific keyboard config, a new one is created with the current
global config (the one modified with KDSKBENT) content copied
in.

3) KDSKBIRST
Reset an input key map. The input does not use a specific
keyboard config anymore and keycode translations are done with
global key map.

In order to remain compatible with old behavior, an input uses global
key map by default and KDGKENT/KDSKENT still get/set entries in the
global key map.

Below is an example of this ioctl usage:
- 8< -
struct kbientry kbi = {
.id = { /* Input is found by its input_id */
.bustype = 0x0003,
.product = 0x00B2,
.vendor = 0x2319,
.version = 0x0200,
},
.entry = { /* Entry to set or get */
.kb_table = 0,
.kb_index = 0x10,
.kb_value = 0x0B61,
},
};
int ret;

/* First set new entry for input 0003:00B2:2319:0200 */
ret = ioctl(fd, KDSKBIENT, ); /* fd is a tty open file */
if(ret < 0)
/* Error handling */

/* Get specific entry, on success kbi.entry.kb_value will be set */
ret = ioctl(fd, KDSKBIENT, );
if(ret < 0)
/* Error handling */

/* Reset input key map so that global key_maps is used */
ret = ioctl(fd, KDSKBIRST, );
if(ret < 0)
/* Error handling */
- 8< -

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 126 ++
 drivers/tty/vt/vt_ioctl.c |   9 +++
 fs/compat_ioctl.c |   3 +
 include/linux/vt_kern.h   |   4 ++
 include/uapi/linux/kd.h   |   9 +++
 5 files changed, 151 insertions(+)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 7272e1828838..9707d1ebeab4 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -2180,6 +2180,132 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user 
*user_kbe, int perm,
return ret;
 }
 
+/*
+ * Input keymap helper functions
+ */
+struct kbd_lookup_data {
+   struct input_id *id;
+   struct kbd_handle *kh;
+};
+
+static int _kbd_get_helper(struct input_handle *handle, void *data)
+{
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
+   struct kbd_lookup_data *d = data;
+
+   if (memcmp(d->id, >dev->id, sizeof(*d->id)) != 0)
+   return 0;
+
+   d->kh = kh;
+   kref_get(>ref);
+   return 1;
+}
+
+/*
+ * Get an input specific handle.
+ * The caller will hold a reference on the found kbd_handle, if it exists, and
+ * should deref it after usage (with kbd_put).
+ */
+static int kbd_get(struct kbd_handle **kh, struct input_id *id)
+{
+   struct kbd_lookup_data d = {
+   .id = id,
+   };
+   int ret;
+
+   ret = input_handler_for_each_handle(_handler, , _kbd_get_helper);
+   *kh = d.kh;
+
+   return (ret == 0);
+}
+
+static void kbd_put(struct kbd_handle *kh)
+{
+   kref_put(>ref, kbd_destroy);
+}
+
+int vt_do_kdski_ioctl(int cmd, struct kbientry __user *user_kbie, int perm,
+   int console)
+{
+   struct kbd_struct *kb = kbd_table + console;
+   struct kbd_handle *kh;
+   struct kbientry tmp;
+   ushort val;
+   int ret = 0;
+
+   if (copy_from_user(, user_kbie, sizeof(struct kbientry))) {
+   ret = -EFAULT;
+   goto out;
+   }
+
+   if (!capable(CAP_SYS_TTY_CONFIG))
+   perm = 0;
+
+   ret = kbd_get(, );
+   if (ret != 0) {
+   ret = -EINVAL;
+   goto out;
+   }
+
+   switch (cmd) {
+   case KDGKBIENT:
+   val = kc_getent(kb, kh->conf, );
+   ret = put_user(val, _kbie->entry.kb_value);
+   break;
+   case KDSKBIENT:
+   if (!perm) {
+   ret = -EPERM;
+   break;
+   }
+   /* A keyconf's keymap is created only if global one is used */
+   ret = kbd_detach_conf(kh);
+   if (ret != 0)
+   break;
+
+   ret = kc_setent(kb, kh->conf, );
+   break;
+   }
+
+   kbd_put(kh);
+out:
+   return ret;
+}
+
+int vt_do_kdskirst_ioctl(int cmd, struct input_id __user *user_iid, int perm,
+   int console)
+{
+   struct kbd_handle *kh;
+

[PATCH 2/4] drivers/tty/vt/keyboard.c: add keyboard config for each vt's input

2018-09-11 Thread Remi Pommarel
Each connected kbd_handle holds a keyboard config that contains the
keymap used to translate keycode into keysym. At init and until the
kbd_handle gets detached it uses the global keyboard config
(aka key_maps[]) array to translate keycode into keysym.

For now, it is not possible for the user to detach a kbd_handle from
global config. Some new ioctl will be introduced to do so.

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 198 --
 1 file changed, 171 insertions(+), 27 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 89fabb8ae04e..4f09331ad5c3 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -108,6 +108,23 @@ struct vt_spawn_console vt_spawn_con = {
  * Internal Data.
  */
 
+/* Input handle's specific key configuration */
+struct kbd_conf {
+   ushort **maps;
+   unsigned int keymap_count;
+};
+
+static struct kbd_conf _gkeyconf;
+#define KC_IS_GLOBAL(kc) ((kc) == &_gkeyconf)
+
+/* Input handle */
+struct kbd_handle {
+   struct kref ref;
+   struct kbd_conf *conf;
+   struct input_handle handle;
+};
+#define hdl_to_kbd_handle(h) (container_of(h, struct kbd_handle, handle))
+
 static struct kbd_struct kbd_table[MAX_NR_CONSOLES];
 static struct kbd_struct *kbd = kbd_table;
 
@@ -1343,9 +1360,11 @@ static void kbd_rawcode(unsigned char data)
put_queue(vc, data);
 }
 
-static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
+static void kbd_keycode(struct kbd_handle *kh, unsigned int keycode, int down,
+   int hw_raw)
 {
struct vc_data *vc = vc_cons[fg_console].d;
+   struct kbd_conf *kconf = kh->conf;
unsigned short keysym, *key_map;
unsigned char type;
bool raw_mode;
@@ -1422,7 +1441,7 @@ static void kbd_keycode(unsigned int keycode, int down, 
int hw_raw)
 
param.shift = shift_final = (shift_state | kbd->slockstate) ^ 
kbd->lockstate;
param.ledstate = kbd->ledflagstate;
-   key_map = key_maps[shift_final];
+   key_map = kconf->maps[shift_final];
 
rc = atomic_notifier_call_chain(_notifier_list,
KBD_KEYCODE, );
@@ -1458,7 +1477,7 @@ static void kbd_keycode(unsigned int keycode, int down, 
int hw_raw)
if (type == KT_LETTER) {
type = KT_LATIN;
if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
-   key_map = key_maps[shift_final ^ (1 << KG_SHIFT)];
+   key_map = kconf->maps[shift_final ^ (1 << KG_SHIFT)];
if (key_map)
keysym = key_map[keycode];
}
@@ -1485,13 +1504,15 @@ static void kbd_keycode(unsigned int keycode, int down, 
int hw_raw)
 static void kbd_event(struct input_handle *handle, unsigned int event_type,
  unsigned int event_code, int value)
 {
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
+
/* We are called with interrupts disabled, just take the lock */
spin_lock(_event_lock);
 
if (event_type == EV_MSC && event_code == MSC_RAW && 
HW_RAW(handle->dev))
kbd_rawcode(value);
if (event_type == EV_KEY)
-   kbd_keycode(event_code, value, HW_RAW(handle->dev));
+   kbd_keycode(kh, event_code, value, HW_RAW(handle->dev));
 
spin_unlock(_event_lock);
 
@@ -1519,6 +1540,114 @@ static bool kbd_match(struct input_handler *handler, 
struct input_dev *dev)
return false;
 }
 
+/*
+ * Keyconf functions
+ */
+
+static void kbd_init_conf(struct kbd_handle *kh)
+{
+   kh->conf = &_gkeyconf;
+}
+
+/*
+ * Detach an input from global keyboard config. If keyboard config is already
+ * detached, nothing is modified.
+ */
+static int kbd_detach_conf(struct kbd_handle *kh)
+{
+   struct kbd_conf *kconf;
+   ushort **tmp, **maps = NULL;
+   size_t i, tmpcnt = 0;
+   unsigned long flags;
+   unsigned int count = 0;
+   int err = -ENOMEM;
+
+   kconf = kmalloc(sizeof(*kconf), GFP_KERNEL);
+   if (kconf == NULL)
+   goto reterr;
+
+   maps = kcalloc(MAX_NR_KEYMAPS, sizeof(*maps), GFP_KERNEL);
+   if (maps == NULL)
+   goto reterr;
+
+   tmp = kmalloc_array(MAX_NR_KEYMAPS, sizeof(*tmp), GFP_KERNEL);
+   if (tmp == NULL)
+   goto reterr;
+
+   spin_lock_irqsave(_event_lock, flags);
+
+   if (!KC_IS_GLOBAL(kh->conf))
+   goto out;  /* We have been raced at keymap creation */
+   count = kh->conf->keymap_count;
+
+   /* Pre-alloc enough tmp buffer to avoid allocating with lock held */
+   while (tmpcnt < count) {
+   spin_unlock_irqrestore(_event_lock, flags);
+   for (; tmpcnt < count; ++tmpcnt) {
+   tmp[tmpcnt] = kmallo

[PATCH 2/4] drivers/tty/vt/keyboard.c: add keyboard config for each vt's input

2018-09-11 Thread Remi Pommarel
Each connected kbd_handle holds a keyboard config that contains the
keymap used to translate keycode into keysym. At init and until the
kbd_handle gets detached it uses the global keyboard config
(aka key_maps[]) array to translate keycode into keysym.

For now, it is not possible for the user to detach a kbd_handle from
global config. Some new ioctl will be introduced to do so.

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 198 --
 1 file changed, 171 insertions(+), 27 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 89fabb8ae04e..4f09331ad5c3 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -108,6 +108,23 @@ struct vt_spawn_console vt_spawn_con = {
  * Internal Data.
  */
 
+/* Input handle's specific key configuration */
+struct kbd_conf {
+   ushort **maps;
+   unsigned int keymap_count;
+};
+
+static struct kbd_conf _gkeyconf;
+#define KC_IS_GLOBAL(kc) ((kc) == &_gkeyconf)
+
+/* Input handle */
+struct kbd_handle {
+   struct kref ref;
+   struct kbd_conf *conf;
+   struct input_handle handle;
+};
+#define hdl_to_kbd_handle(h) (container_of(h, struct kbd_handle, handle))
+
 static struct kbd_struct kbd_table[MAX_NR_CONSOLES];
 static struct kbd_struct *kbd = kbd_table;
 
@@ -1343,9 +1360,11 @@ static void kbd_rawcode(unsigned char data)
put_queue(vc, data);
 }
 
-static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
+static void kbd_keycode(struct kbd_handle *kh, unsigned int keycode, int down,
+   int hw_raw)
 {
struct vc_data *vc = vc_cons[fg_console].d;
+   struct kbd_conf *kconf = kh->conf;
unsigned short keysym, *key_map;
unsigned char type;
bool raw_mode;
@@ -1422,7 +1441,7 @@ static void kbd_keycode(unsigned int keycode, int down, 
int hw_raw)
 
param.shift = shift_final = (shift_state | kbd->slockstate) ^ 
kbd->lockstate;
param.ledstate = kbd->ledflagstate;
-   key_map = key_maps[shift_final];
+   key_map = kconf->maps[shift_final];
 
rc = atomic_notifier_call_chain(_notifier_list,
KBD_KEYCODE, );
@@ -1458,7 +1477,7 @@ static void kbd_keycode(unsigned int keycode, int down, 
int hw_raw)
if (type == KT_LETTER) {
type = KT_LATIN;
if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
-   key_map = key_maps[shift_final ^ (1 << KG_SHIFT)];
+   key_map = kconf->maps[shift_final ^ (1 << KG_SHIFT)];
if (key_map)
keysym = key_map[keycode];
}
@@ -1485,13 +1504,15 @@ static void kbd_keycode(unsigned int keycode, int down, 
int hw_raw)
 static void kbd_event(struct input_handle *handle, unsigned int event_type,
  unsigned int event_code, int value)
 {
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
+
/* We are called with interrupts disabled, just take the lock */
spin_lock(_event_lock);
 
if (event_type == EV_MSC && event_code == MSC_RAW && 
HW_RAW(handle->dev))
kbd_rawcode(value);
if (event_type == EV_KEY)
-   kbd_keycode(event_code, value, HW_RAW(handle->dev));
+   kbd_keycode(kh, event_code, value, HW_RAW(handle->dev));
 
spin_unlock(_event_lock);
 
@@ -1519,6 +1540,114 @@ static bool kbd_match(struct input_handler *handler, 
struct input_dev *dev)
return false;
 }
 
+/*
+ * Keyconf functions
+ */
+
+static void kbd_init_conf(struct kbd_handle *kh)
+{
+   kh->conf = &_gkeyconf;
+}
+
+/*
+ * Detach an input from global keyboard config. If keyboard config is already
+ * detached, nothing is modified.
+ */
+static int kbd_detach_conf(struct kbd_handle *kh)
+{
+   struct kbd_conf *kconf;
+   ushort **tmp, **maps = NULL;
+   size_t i, tmpcnt = 0;
+   unsigned long flags;
+   unsigned int count = 0;
+   int err = -ENOMEM;
+
+   kconf = kmalloc(sizeof(*kconf), GFP_KERNEL);
+   if (kconf == NULL)
+   goto reterr;
+
+   maps = kcalloc(MAX_NR_KEYMAPS, sizeof(*maps), GFP_KERNEL);
+   if (maps == NULL)
+   goto reterr;
+
+   tmp = kmalloc_array(MAX_NR_KEYMAPS, sizeof(*tmp), GFP_KERNEL);
+   if (tmp == NULL)
+   goto reterr;
+
+   spin_lock_irqsave(_event_lock, flags);
+
+   if (!KC_IS_GLOBAL(kh->conf))
+   goto out;  /* We have been raced at keymap creation */
+   count = kh->conf->keymap_count;
+
+   /* Pre-alloc enough tmp buffer to avoid allocating with lock held */
+   while (tmpcnt < count) {
+   spin_unlock_irqrestore(_event_lock, flags);
+   for (; tmpcnt < count; ++tmpcnt) {
+   tmp[tmpcnt] = kmallo

Re: [RFC PATCH 0/4] Add specific vt input's key map

2018-09-05 Thread Remi Pommarel
Hi,

Just a gentle ping.

Any comments on this patchset that adds a way to have multiple
keyboards with different keymap on a VT would be nice.

Thanks

-- 
Remi


Re: [RFC PATCH 0/4] Add specific vt input's key map

2018-09-05 Thread Remi Pommarel
Hi,

Just a gentle ping.

Any comments on this patchset that adds a way to have multiple
keyboards with different keymap on a VT would be nice.

Thanks

-- 
Remi


[RFC PATCH 2/4] drivers/tty/vt/keyboard.c: add keyboard config for each vt's input

2018-08-22 Thread Remi Pommarel
Each connected kbd_handle holds a keyboard config that contains the
keymap used to translate keycode into keysym. At init and until the
kbd_handle gets detached it uses the global keyboard config
(aka key_maps[]) array to translate keycode into keysym.

For now, it is not possible for the user to detach a kbd_handle from
global config. Some new ioctl will be introduced to do so.

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 198 --
 1 file changed, 171 insertions(+), 27 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 89fabb8ae04e..4f09331ad5c3 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -108,6 +108,23 @@ struct vt_spawn_console vt_spawn_con = {
  * Internal Data.
  */
 
+/* Input handle's specific key configuration */
+struct kbd_conf {
+   ushort **maps;
+   unsigned int keymap_count;
+};
+
+static struct kbd_conf _gkeyconf;
+#define KC_IS_GLOBAL(kc) ((kc) == &_gkeyconf)
+
+/* Input handle */
+struct kbd_handle {
+   struct kref ref;
+   struct kbd_conf *conf;
+   struct input_handle handle;
+};
+#define hdl_to_kbd_handle(h) (container_of(h, struct kbd_handle, handle))
+
 static struct kbd_struct kbd_table[MAX_NR_CONSOLES];
 static struct kbd_struct *kbd = kbd_table;
 
@@ -1343,9 +1360,11 @@ static void kbd_rawcode(unsigned char data)
put_queue(vc, data);
 }
 
-static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
+static void kbd_keycode(struct kbd_handle *kh, unsigned int keycode, int down,
+   int hw_raw)
 {
struct vc_data *vc = vc_cons[fg_console].d;
+   struct kbd_conf *kconf = kh->conf;
unsigned short keysym, *key_map;
unsigned char type;
bool raw_mode;
@@ -1422,7 +1441,7 @@ static void kbd_keycode(unsigned int keycode, int down, 
int hw_raw)
 
param.shift = shift_final = (shift_state | kbd->slockstate) ^ 
kbd->lockstate;
param.ledstate = kbd->ledflagstate;
-   key_map = key_maps[shift_final];
+   key_map = kconf->maps[shift_final];
 
rc = atomic_notifier_call_chain(_notifier_list,
KBD_KEYCODE, );
@@ -1458,7 +1477,7 @@ static void kbd_keycode(unsigned int keycode, int down, 
int hw_raw)
if (type == KT_LETTER) {
type = KT_LATIN;
if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
-   key_map = key_maps[shift_final ^ (1 << KG_SHIFT)];
+   key_map = kconf->maps[shift_final ^ (1 << KG_SHIFT)];
if (key_map)
keysym = key_map[keycode];
}
@@ -1485,13 +1504,15 @@ static void kbd_keycode(unsigned int keycode, int down, 
int hw_raw)
 static void kbd_event(struct input_handle *handle, unsigned int event_type,
  unsigned int event_code, int value)
 {
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
+
/* We are called with interrupts disabled, just take the lock */
spin_lock(_event_lock);
 
if (event_type == EV_MSC && event_code == MSC_RAW && 
HW_RAW(handle->dev))
kbd_rawcode(value);
if (event_type == EV_KEY)
-   kbd_keycode(event_code, value, HW_RAW(handle->dev));
+   kbd_keycode(kh, event_code, value, HW_RAW(handle->dev));
 
spin_unlock(_event_lock);
 
@@ -1519,6 +1540,114 @@ static bool kbd_match(struct input_handler *handler, 
struct input_dev *dev)
return false;
 }
 
+/*
+ * Keyconf functions
+ */
+
+static void kbd_init_conf(struct kbd_handle *kh)
+{
+   kh->conf = &_gkeyconf;
+}
+
+/*
+ * Detach an input from global keyboard config. If keyboard config is already
+ * detached, nothing is modified.
+ */
+static int kbd_detach_conf(struct kbd_handle *kh)
+{
+   struct kbd_conf *kconf;
+   ushort **tmp, **maps = NULL;
+   size_t i, tmpcnt = 0;
+   unsigned long flags;
+   unsigned int count = 0;
+   int err = -ENOMEM;
+
+   kconf = kmalloc(sizeof(*kconf), GFP_KERNEL);
+   if (kconf == NULL)
+   goto reterr;
+
+   maps = kcalloc(MAX_NR_KEYMAPS, sizeof(*maps), GFP_KERNEL);
+   if (maps == NULL)
+   goto reterr;
+
+   tmp = kmalloc_array(MAX_NR_KEYMAPS, sizeof(*tmp), GFP_KERNEL);
+   if (tmp == NULL)
+   goto reterr;
+
+   spin_lock_irqsave(_event_lock, flags);
+
+   if (!KC_IS_GLOBAL(kh->conf))
+   goto out;  /* We have been raced at keymap creation */
+   count = kh->conf->keymap_count;
+
+   /* Pre-alloc enough tmp buffer to avoid allocating with lock held */
+   while (tmpcnt < count) {
+   spin_unlock_irqrestore(_event_lock, flags);
+   for (; tmpcnt < count; ++tmpcnt) {
+   tmp[tmpcnt] = kmallo

[RFC PATCH 1/4] drivers/tty/vt/keyboard.c: refactor getting/setting a keymap entry

2018-08-22 Thread Remi Pommarel
In order to ease the addition of the ability of an input to use a
different key configuration (keycode to keysym map), the operations of
getting and setting an entry in a key map is moved in respective
functions.

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 201 ++
 1 file changed, 118 insertions(+), 83 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 88312c6c92cc..89fabb8ae04e 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1874,115 +1874,150 @@ int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode 
__user *user_kbkc,
return kc;
 }
 
-#define i (tmp.kb_index)
-#define s (tmp.kb_table)
-#define v (tmp.kb_value)
+#define i (kbe->kb_index)
+#define s (kbe->kb_table)
+#define v (kbe->kb_value)
 
-int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
-   int console)
+/*
+ * Get a keysym value from a key map
+ *
+ * @kb: Virtual console structure
+ * @kmaps: Key map array
+ * @kbe : Entry to find in key map
+ */
+static ushort __kdsk_getent(struct kbd_struct const *kb, ushort **kmaps,
+   struct kbentry const *kbe)
 {
-   struct kbd_struct *kb = kbd_table + console;
-   struct kbentry tmp;
-   ushort *key_map, *new_map, val, ov;
+   ushort *key_map, val;
unsigned long flags;
 
-   if (copy_from_user(, user_kbe, sizeof(struct kbentry)))
-   return -EFAULT;
+   /* Ensure another thread doesn't free it under us */
+   spin_lock_irqsave(_event_lock, flags);
+   key_map = kmaps[s];
+   if (key_map) {
+   val = U(key_map[i]);
+   if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
+   val = K_HOLE;
+   } else
+   val = (i ? K_HOLE : K_NOSUCHMAP);
+   spin_unlock_irqrestore(_event_lock, flags);
 
-   if (!capable(CAP_SYS_TTY_CONFIG))
-   perm = 0;
+   return val;
+}
 
-   switch (cmd) {
-   case KDGKBENT:
-   /* Ensure another thread doesn't free it under us */
+/*
+ * Set a keysym value in a key map
+ *
+ * @kb: Virtual console structure
+ * @kmaps: Key map array
+ * @kbe : Entry to set in key map
+ */
+static int __kdsk_setent(struct kbd_struct const *kb, ushort **kmaps,
+   struct kbentry const *kbe)
+{
+   ushort *key_map, *new_map, ov;
+   unsigned long flags;
+
+   if (!i && v == K_NOSUCHMAP) {
spin_lock_irqsave(_event_lock, flags);
-   key_map = key_maps[s];
-   if (key_map) {
-   val = U(key_map[i]);
-   if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
-   val = K_HOLE;
-   } else
-   val = (i ? K_HOLE : K_NOSUCHMAP);
-   spin_unlock_irqrestore(_event_lock, flags);
-   return put_user(val, _kbe->kb_value);
-   case KDSKBENT:
-   if (!perm)
-   return -EPERM;
-   if (!i && v == K_NOSUCHMAP) {
-   spin_lock_irqsave(_event_lock, flags);
-   /* deallocate map */
-   key_map = key_maps[s];
-   if (s && key_map) {
-   key_maps[s] = NULL;
-   if (key_map[0] == U(K_ALLOCATED)) {
-   kfree(key_map);
-   keymap_count--;
-   }
+   /* deallocate map */
+   key_map = kmaps[s];
+   if (s && key_map) {
+   kmaps[s] = NULL;
+   if (key_map[0] == U(K_ALLOCATED)) {
+   kfree(key_map);
+   keymap_count--;
}
-   spin_unlock_irqrestore(_event_lock, flags);
-   break;
}
+   spin_unlock_irqrestore(_event_lock, flags);
+   return 0;
+   }
 
-   if (KTYP(v) < NR_TYPES) {
-   if (KVAL(v) > max_vals[KTYP(v)])
-   return -EINVAL;
-   } else
-   if (kb->kbdmode != VC_UNICODE)
-   return -EINVAL;
+   if (KTYP(v) < NR_TYPES) {
+   if (KVAL(v) > max_vals[KTYP(v)])
+   return -EINVAL;
+   } else if (kb->kbdmode != VC_UNICODE)
+   return -EINVAL;
 
-   /* ++Geert: non-PC keyboards may generate keycode zero */
+   /* ++Geert: non-PC keyboards may generate keycode zero */
 #if !defined(__mc68000__) && !defined(__powerpc__)
-   /* assignment to entry 0 only tests validity of args */
-   i

[RFC PATCH 2/4] drivers/tty/vt/keyboard.c: add keyboard config for each vt's input

2018-08-22 Thread Remi Pommarel
Each connected kbd_handle holds a keyboard config that contains the
keymap used to translate keycode into keysym. At init and until the
kbd_handle gets detached it uses the global keyboard config
(aka key_maps[]) array to translate keycode into keysym.

For now, it is not possible for the user to detach a kbd_handle from
global config. Some new ioctl will be introduced to do so.

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 198 --
 1 file changed, 171 insertions(+), 27 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 89fabb8ae04e..4f09331ad5c3 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -108,6 +108,23 @@ struct vt_spawn_console vt_spawn_con = {
  * Internal Data.
  */
 
+/* Input handle's specific key configuration */
+struct kbd_conf {
+   ushort **maps;
+   unsigned int keymap_count;
+};
+
+static struct kbd_conf _gkeyconf;
+#define KC_IS_GLOBAL(kc) ((kc) == &_gkeyconf)
+
+/* Input handle */
+struct kbd_handle {
+   struct kref ref;
+   struct kbd_conf *conf;
+   struct input_handle handle;
+};
+#define hdl_to_kbd_handle(h) (container_of(h, struct kbd_handle, handle))
+
 static struct kbd_struct kbd_table[MAX_NR_CONSOLES];
 static struct kbd_struct *kbd = kbd_table;
 
@@ -1343,9 +1360,11 @@ static void kbd_rawcode(unsigned char data)
put_queue(vc, data);
 }
 
-static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
+static void kbd_keycode(struct kbd_handle *kh, unsigned int keycode, int down,
+   int hw_raw)
 {
struct vc_data *vc = vc_cons[fg_console].d;
+   struct kbd_conf *kconf = kh->conf;
unsigned short keysym, *key_map;
unsigned char type;
bool raw_mode;
@@ -1422,7 +1441,7 @@ static void kbd_keycode(unsigned int keycode, int down, 
int hw_raw)
 
param.shift = shift_final = (shift_state | kbd->slockstate) ^ 
kbd->lockstate;
param.ledstate = kbd->ledflagstate;
-   key_map = key_maps[shift_final];
+   key_map = kconf->maps[shift_final];
 
rc = atomic_notifier_call_chain(_notifier_list,
KBD_KEYCODE, );
@@ -1458,7 +1477,7 @@ static void kbd_keycode(unsigned int keycode, int down, 
int hw_raw)
if (type == KT_LETTER) {
type = KT_LATIN;
if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
-   key_map = key_maps[shift_final ^ (1 << KG_SHIFT)];
+   key_map = kconf->maps[shift_final ^ (1 << KG_SHIFT)];
if (key_map)
keysym = key_map[keycode];
}
@@ -1485,13 +1504,15 @@ static void kbd_keycode(unsigned int keycode, int down, 
int hw_raw)
 static void kbd_event(struct input_handle *handle, unsigned int event_type,
  unsigned int event_code, int value)
 {
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
+
/* We are called with interrupts disabled, just take the lock */
spin_lock(_event_lock);
 
if (event_type == EV_MSC && event_code == MSC_RAW && 
HW_RAW(handle->dev))
kbd_rawcode(value);
if (event_type == EV_KEY)
-   kbd_keycode(event_code, value, HW_RAW(handle->dev));
+   kbd_keycode(kh, event_code, value, HW_RAW(handle->dev));
 
spin_unlock(_event_lock);
 
@@ -1519,6 +1540,114 @@ static bool kbd_match(struct input_handler *handler, 
struct input_dev *dev)
return false;
 }
 
+/*
+ * Keyconf functions
+ */
+
+static void kbd_init_conf(struct kbd_handle *kh)
+{
+   kh->conf = &_gkeyconf;
+}
+
+/*
+ * Detach an input from global keyboard config. If keyboard config is already
+ * detached, nothing is modified.
+ */
+static int kbd_detach_conf(struct kbd_handle *kh)
+{
+   struct kbd_conf *kconf;
+   ushort **tmp, **maps = NULL;
+   size_t i, tmpcnt = 0;
+   unsigned long flags;
+   unsigned int count = 0;
+   int err = -ENOMEM;
+
+   kconf = kmalloc(sizeof(*kconf), GFP_KERNEL);
+   if (kconf == NULL)
+   goto reterr;
+
+   maps = kcalloc(MAX_NR_KEYMAPS, sizeof(*maps), GFP_KERNEL);
+   if (maps == NULL)
+   goto reterr;
+
+   tmp = kmalloc_array(MAX_NR_KEYMAPS, sizeof(*tmp), GFP_KERNEL);
+   if (tmp == NULL)
+   goto reterr;
+
+   spin_lock_irqsave(_event_lock, flags);
+
+   if (!KC_IS_GLOBAL(kh->conf))
+   goto out;  /* We have been raced at keymap creation */
+   count = kh->conf->keymap_count;
+
+   /* Pre-alloc enough tmp buffer to avoid allocating with lock held */
+   while (tmpcnt < count) {
+   spin_unlock_irqrestore(_event_lock, flags);
+   for (; tmpcnt < count; ++tmpcnt) {
+   tmp[tmpcnt] = kmallo

[RFC PATCH 1/4] drivers/tty/vt/keyboard.c: refactor getting/setting a keymap entry

2018-08-22 Thread Remi Pommarel
In order to ease the addition of the ability of an input to use a
different key configuration (keycode to keysym map), the operations of
getting and setting an entry in a key map is moved in respective
functions.

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 201 ++
 1 file changed, 118 insertions(+), 83 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 88312c6c92cc..89fabb8ae04e 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1874,115 +1874,150 @@ int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode 
__user *user_kbkc,
return kc;
 }
 
-#define i (tmp.kb_index)
-#define s (tmp.kb_table)
-#define v (tmp.kb_value)
+#define i (kbe->kb_index)
+#define s (kbe->kb_table)
+#define v (kbe->kb_value)
 
-int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
-   int console)
+/*
+ * Get a keysym value from a key map
+ *
+ * @kb: Virtual console structure
+ * @kmaps: Key map array
+ * @kbe : Entry to find in key map
+ */
+static ushort __kdsk_getent(struct kbd_struct const *kb, ushort **kmaps,
+   struct kbentry const *kbe)
 {
-   struct kbd_struct *kb = kbd_table + console;
-   struct kbentry tmp;
-   ushort *key_map, *new_map, val, ov;
+   ushort *key_map, val;
unsigned long flags;
 
-   if (copy_from_user(, user_kbe, sizeof(struct kbentry)))
-   return -EFAULT;
+   /* Ensure another thread doesn't free it under us */
+   spin_lock_irqsave(_event_lock, flags);
+   key_map = kmaps[s];
+   if (key_map) {
+   val = U(key_map[i]);
+   if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
+   val = K_HOLE;
+   } else
+   val = (i ? K_HOLE : K_NOSUCHMAP);
+   spin_unlock_irqrestore(_event_lock, flags);
 
-   if (!capable(CAP_SYS_TTY_CONFIG))
-   perm = 0;
+   return val;
+}
 
-   switch (cmd) {
-   case KDGKBENT:
-   /* Ensure another thread doesn't free it under us */
+/*
+ * Set a keysym value in a key map
+ *
+ * @kb: Virtual console structure
+ * @kmaps: Key map array
+ * @kbe : Entry to set in key map
+ */
+static int __kdsk_setent(struct kbd_struct const *kb, ushort **kmaps,
+   struct kbentry const *kbe)
+{
+   ushort *key_map, *new_map, ov;
+   unsigned long flags;
+
+   if (!i && v == K_NOSUCHMAP) {
spin_lock_irqsave(_event_lock, flags);
-   key_map = key_maps[s];
-   if (key_map) {
-   val = U(key_map[i]);
-   if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
-   val = K_HOLE;
-   } else
-   val = (i ? K_HOLE : K_NOSUCHMAP);
-   spin_unlock_irqrestore(_event_lock, flags);
-   return put_user(val, _kbe->kb_value);
-   case KDSKBENT:
-   if (!perm)
-   return -EPERM;
-   if (!i && v == K_NOSUCHMAP) {
-   spin_lock_irqsave(_event_lock, flags);
-   /* deallocate map */
-   key_map = key_maps[s];
-   if (s && key_map) {
-   key_maps[s] = NULL;
-   if (key_map[0] == U(K_ALLOCATED)) {
-   kfree(key_map);
-   keymap_count--;
-   }
+   /* deallocate map */
+   key_map = kmaps[s];
+   if (s && key_map) {
+   kmaps[s] = NULL;
+   if (key_map[0] == U(K_ALLOCATED)) {
+   kfree(key_map);
+   keymap_count--;
}
-   spin_unlock_irqrestore(_event_lock, flags);
-   break;
}
+   spin_unlock_irqrestore(_event_lock, flags);
+   return 0;
+   }
 
-   if (KTYP(v) < NR_TYPES) {
-   if (KVAL(v) > max_vals[KTYP(v)])
-   return -EINVAL;
-   } else
-   if (kb->kbdmode != VC_UNICODE)
-   return -EINVAL;
+   if (KTYP(v) < NR_TYPES) {
+   if (KVAL(v) > max_vals[KTYP(v)])
+   return -EINVAL;
+   } else if (kb->kbdmode != VC_UNICODE)
+   return -EINVAL;
 
-   /* ++Geert: non-PC keyboards may generate keycode zero */
+   /* ++Geert: non-PC keyboards may generate keycode zero */
 #if !defined(__mc68000__) && !defined(__powerpc__)
-   /* assignment to entry 0 only tests validity of args */
-   i

[RFC PATCH 0/4] Add specific vt input's key map

2018-08-22 Thread Remi Pommarel
This patchset adds a way to have a specific keyboard config (i.e.
keycode to keysym map) for a vt attached input.

Because one can have different keyboards with different layouts on the
same VT, it can be useful to be able to associate a different keymap
with a different input. In order to do so this patchset introduces
three new ioctls:

1) KDGKBIENT
Get an input key map's entry. If the input does not have a
specific key map the requested entry is fetched from global
key map.

2) KDSKBIENT
Set an input key map's entry. If the input does not yet have a
specific key map, a new one is created with the current global
key map content copied in.

3) KDSKBIRST
Reset an input key map. The input does not use a specific key
map anymore and keycode translations are done with global key
map.

In order to keep old behavior compatibility and not waste memory, an
input uses the global key_maps[] array by default and KDGKBENT/KDSKBENT
ioctls still get/set entries in this global key map. The specific key
map is only allocated on the first call to KDSKBIENT.

A patch for loadkeys is ready to be sent to the ML if this patchset
seems sane to you.

Here are some questions I had while doing this patchset:

- Maybe there is a way, I am not aware of, that can allow one to use
  different keyboard layout on same VT ?

- Is it ok to add new ioctl to old legacy code ? I added those ioctl
  the old way in order to match the header style. Maybe it is better to
  use the __IO* macros ?

- Should key_down bitmap be really input specific (i.e. PATCH 3/4) ?

- I am not quite sure about the meaning of keymap_count. IIUC, it is a
  counter of used keymap function arrays statically or dynamically
  allocated. If it is not the case, the modificiation in kc_setent() that
  decrements keymap_count even if a statically keymap function is removed
  with "K_NOSUCHMAP" (in PATCH 2/4) may be wrong ?

- kbd_detach_conf is a bit clumsy because it tries to copy a shared sparse
  pointer array without using GFP_ATOMIC.

- Is this patchset even a sensible idea ?

Remi Pommarel (4):
  drivers/tty/vt/keyboard.c: refactor getting/setting a keymap entry
  drivers/tty/vt/keyboard.c: add keyboard config for each vt's input
  drivers/tty/vt/keyboard.c: Make key_down[] bitmap input dependent
  drivers/tty/vt: add ioctl to manage input specific keyboard configs

 drivers/tty/vt/keyboard.c | 531 ++
 drivers/tty/vt/vt_ioctl.c |   9 +
 fs/compat_ioctl.c |   3 +
 include/linux/vt_kern.h   |   4 +
 include/uapi/linux/kd.h   |   9 +
 5 files changed, 452 insertions(+), 104 deletions(-)

-- 
2.18.0



[RFC PATCH 4/4] drivers/tty/vt: add ioctl to manage input specific keyboard configs

2018-08-22 Thread Remi Pommarel
Because user can use different keyboards with different layouts on the
same tty, an input could have a different key map from another one. In
order to use and modify this specific key map the user can call three
new ioctls:

1) KDGKBIENT
Get an input key map's entry. If the input does not have a
specific keyboard config the requested entry is fetched from
global key map.

2) KDSKBIENT
Set an input key map's entry. If the input does not yet have a
specific keyboard config, a new one is created with the current
global config (the one modified with KDSKBENT) content copied
in.

3) KDSKBIRST
Reset an input key map. The input does not use a specific
keyboard config anymore and keycode translations are done with
global key map.

In order to remain compatible with old behavior, an input uses global
key map by default and KDGKENT/KDSKENT still get/set entries in the
global key map.

Below is an example of this ioctl usage:
- 8< -
struct kbientry kbi = {
.id = { /* Input is found by its input_id */
.bustype = 0x0003,
.product = 0x00B2,
.vendor = 0x2319,
.version = 0x0200,
},
.entry = { /* Entry to set or get */
.kb_table = 0,
.kb_index = 0x10,
.kb_value = 0x0B61,
},
};
int ret;

/* First set new entry for input 0003:00B2:2319:0200 */
ret = ioctl(fd, KDSKBIENT, ); /* fd is a tty open file */
if(ret < 0)
/* Error handling */

/* Get specific entry, on success kbi.entry.kb_value will be set */
ret = ioctl(fd, KDSKBIENT, );
if(ret < 0)
/* Error handling */

/* Reset input key map so that global key_maps is used */
ret = ioctl(fd, KDSKBIRST, );
if(ret < 0)
/* Error handling */
- 8< -

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 126 ++
 drivers/tty/vt/vt_ioctl.c |   9 +++
 fs/compat_ioctl.c |   3 +
 include/linux/vt_kern.h   |   4 ++
 include/uapi/linux/kd.h   |   9 +++
 5 files changed, 151 insertions(+)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 7272e1828838..9707d1ebeab4 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -2180,6 +2180,132 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user 
*user_kbe, int perm,
return ret;
 }
 
+/*
+ * Input keymap helper functions
+ */
+struct kbd_lookup_data {
+   struct input_id *id;
+   struct kbd_handle *kh;
+};
+
+static int _kbd_get_helper(struct input_handle *handle, void *data)
+{
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
+   struct kbd_lookup_data *d = data;
+
+   if (memcmp(d->id, >dev->id, sizeof(*d->id)) != 0)
+   return 0;
+
+   d->kh = kh;
+   kref_get(>ref);
+   return 1;
+}
+
+/*
+ * Get an input specific handle.
+ * The caller will hold a reference on the found kbd_handle, if it exists, and
+ * should deref it after usage (with kbd_put).
+ */
+static int kbd_get(struct kbd_handle **kh, struct input_id *id)
+{
+   struct kbd_lookup_data d = {
+   .id = id,
+   };
+   int ret;
+
+   ret = input_handler_for_each_handle(_handler, , _kbd_get_helper);
+   *kh = d.kh;
+
+   return (ret == 0);
+}
+
+static void kbd_put(struct kbd_handle *kh)
+{
+   kref_put(>ref, kbd_destroy);
+}
+
+int vt_do_kdski_ioctl(int cmd, struct kbientry __user *user_kbie, int perm,
+   int console)
+{
+   struct kbd_struct *kb = kbd_table + console;
+   struct kbd_handle *kh;
+   struct kbientry tmp;
+   ushort val;
+   int ret = 0;
+
+   if (copy_from_user(, user_kbie, sizeof(struct kbientry))) {
+   ret = -EFAULT;
+   goto out;
+   }
+
+   if (!capable(CAP_SYS_TTY_CONFIG))
+   perm = 0;
+
+   ret = kbd_get(, );
+   if (ret != 0) {
+   ret = -EINVAL;
+   goto out;
+   }
+
+   switch (cmd) {
+   case KDGKBIENT:
+   val = kc_getent(kb, kh->conf, );
+   ret = put_user(val, _kbie->entry.kb_value);
+   break;
+   case KDSKBIENT:
+   if (!perm) {
+   ret = -EPERM;
+   break;
+   }
+   /* A keyconf's keymap is created only if global one is used */
+   ret = kbd_detach_conf(kh);
+   if (ret != 0)
+   break;
+
+   ret = kc_setent(kb, kh->conf, );
+   break;
+   }
+
+   kbd_put(kh);
+out:
+   return ret;
+}
+
+int vt_do_kdskirst_ioctl(int cmd, struct input_id __user *user_iid, int perm,
+   int console)
+{
+   struct kbd_handle *kh;
+

[RFC PATCH 4/4] drivers/tty/vt: add ioctl to manage input specific keyboard configs

2018-08-22 Thread Remi Pommarel
Because user can use different keyboards with different layouts on the
same tty, an input could have a different key map from another one. In
order to use and modify this specific key map the user can call three
new ioctls:

1) KDGKBIENT
Get an input key map's entry. If the input does not have a
specific keyboard config the requested entry is fetched from
global key map.

2) KDSKBIENT
Set an input key map's entry. If the input does not yet have a
specific keyboard config, a new one is created with the current
global config (the one modified with KDSKBENT) content copied
in.

3) KDSKBIRST
Reset an input key map. The input does not use a specific
keyboard config anymore and keycode translations are done with
global key map.

In order to remain compatible with old behavior, an input uses global
key map by default and KDGKENT/KDSKENT still get/set entries in the
global key map.

Below is an example of this ioctl usage:
- 8< -
struct kbientry kbi = {
.id = { /* Input is found by its input_id */
.bustype = 0x0003,
.product = 0x00B2,
.vendor = 0x2319,
.version = 0x0200,
},
.entry = { /* Entry to set or get */
.kb_table = 0,
.kb_index = 0x10,
.kb_value = 0x0B61,
},
};
int ret;

/* First set new entry for input 0003:00B2:2319:0200 */
ret = ioctl(fd, KDSKBIENT, ); /* fd is a tty open file */
if(ret < 0)
/* Error handling */

/* Get specific entry, on success kbi.entry.kb_value will be set */
ret = ioctl(fd, KDSKBIENT, );
if(ret < 0)
/* Error handling */

/* Reset input key map so that global key_maps is used */
ret = ioctl(fd, KDSKBIRST, );
if(ret < 0)
/* Error handling */
- 8< -

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 126 ++
 drivers/tty/vt/vt_ioctl.c |   9 +++
 fs/compat_ioctl.c |   3 +
 include/linux/vt_kern.h   |   4 ++
 include/uapi/linux/kd.h   |   9 +++
 5 files changed, 151 insertions(+)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 7272e1828838..9707d1ebeab4 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -2180,6 +2180,132 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user 
*user_kbe, int perm,
return ret;
 }
 
+/*
+ * Input keymap helper functions
+ */
+struct kbd_lookup_data {
+   struct input_id *id;
+   struct kbd_handle *kh;
+};
+
+static int _kbd_get_helper(struct input_handle *handle, void *data)
+{
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
+   struct kbd_lookup_data *d = data;
+
+   if (memcmp(d->id, >dev->id, sizeof(*d->id)) != 0)
+   return 0;
+
+   d->kh = kh;
+   kref_get(>ref);
+   return 1;
+}
+
+/*
+ * Get an input specific handle.
+ * The caller will hold a reference on the found kbd_handle, if it exists, and
+ * should deref it after usage (with kbd_put).
+ */
+static int kbd_get(struct kbd_handle **kh, struct input_id *id)
+{
+   struct kbd_lookup_data d = {
+   .id = id,
+   };
+   int ret;
+
+   ret = input_handler_for_each_handle(_handler, , _kbd_get_helper);
+   *kh = d.kh;
+
+   return (ret == 0);
+}
+
+static void kbd_put(struct kbd_handle *kh)
+{
+   kref_put(>ref, kbd_destroy);
+}
+
+int vt_do_kdski_ioctl(int cmd, struct kbientry __user *user_kbie, int perm,
+   int console)
+{
+   struct kbd_struct *kb = kbd_table + console;
+   struct kbd_handle *kh;
+   struct kbientry tmp;
+   ushort val;
+   int ret = 0;
+
+   if (copy_from_user(, user_kbie, sizeof(struct kbientry))) {
+   ret = -EFAULT;
+   goto out;
+   }
+
+   if (!capable(CAP_SYS_TTY_CONFIG))
+   perm = 0;
+
+   ret = kbd_get(, );
+   if (ret != 0) {
+   ret = -EINVAL;
+   goto out;
+   }
+
+   switch (cmd) {
+   case KDGKBIENT:
+   val = kc_getent(kb, kh->conf, );
+   ret = put_user(val, _kbie->entry.kb_value);
+   break;
+   case KDSKBIENT:
+   if (!perm) {
+   ret = -EPERM;
+   break;
+   }
+   /* A keyconf's keymap is created only if global one is used */
+   ret = kbd_detach_conf(kh);
+   if (ret != 0)
+   break;
+
+   ret = kc_setent(kb, kh->conf, );
+   break;
+   }
+
+   kbd_put(kh);
+out:
+   return ret;
+}
+
+int vt_do_kdskirst_ioctl(int cmd, struct input_id __user *user_iid, int perm,
+   int console)
+{
+   struct kbd_handle *kh;
+

[RFC PATCH 0/4] Add specific vt input's key map

2018-08-22 Thread Remi Pommarel
This patchset adds a way to have a specific keyboard config (i.e.
keycode to keysym map) for a vt attached input.

Because one can have different keyboards with different layouts on the
same VT, it can be useful to be able to associate a different keymap
with a different input. In order to do so this patchset introduces
three new ioctls:

1) KDGKBIENT
Get an input key map's entry. If the input does not have a
specific key map the requested entry is fetched from global
key map.

2) KDSKBIENT
Set an input key map's entry. If the input does not yet have a
specific key map, a new one is created with the current global
key map content copied in.

3) KDSKBIRST
Reset an input key map. The input does not use a specific key
map anymore and keycode translations are done with global key
map.

In order to keep old behavior compatibility and not waste memory, an
input uses the global key_maps[] array by default and KDGKBENT/KDSKBENT
ioctls still get/set entries in this global key map. The specific key
map is only allocated on the first call to KDSKBIENT.

A patch for loadkeys is ready to be sent to the ML if this patchset
seems sane to you.

Here are some questions I had while doing this patchset:

- Maybe there is a way, I am not aware of, that can allow one to use
  different keyboard layout on same VT ?

- Is it ok to add new ioctl to old legacy code ? I added those ioctl
  the old way in order to match the header style. Maybe it is better to
  use the __IO* macros ?

- Should key_down bitmap be really input specific (i.e. PATCH 3/4) ?

- I am not quite sure about the meaning of keymap_count. IIUC, it is a
  counter of used keymap function arrays statically or dynamically
  allocated. If it is not the case, the modificiation in kc_setent() that
  decrements keymap_count even if a statically keymap function is removed
  with "K_NOSUCHMAP" (in PATCH 2/4) may be wrong ?

- kbd_detach_conf is a bit clumsy because it tries to copy a shared sparse
  pointer array without using GFP_ATOMIC.

- Is this patchset even a sensible idea ?

Remi Pommarel (4):
  drivers/tty/vt/keyboard.c: refactor getting/setting a keymap entry
  drivers/tty/vt/keyboard.c: add keyboard config for each vt's input
  drivers/tty/vt/keyboard.c: Make key_down[] bitmap input dependent
  drivers/tty/vt: add ioctl to manage input specific keyboard configs

 drivers/tty/vt/keyboard.c | 531 ++
 drivers/tty/vt/vt_ioctl.c |   9 +
 fs/compat_ioctl.c |   3 +
 include/linux/vt_kern.h   |   4 +
 include/uapi/linux/kd.h   |   9 +
 5 files changed, 452 insertions(+), 104 deletions(-)

-- 
2.18.0



[RFC PATCH 3/4] drivers/tty/vt/keyboard.c: Make key_down[] bitmap input dependent

2018-08-22 Thread Remi Pommarel
A kbd_handle input can have a specific keyboard config that makes
keycode to keysym mapping array different from another one. Because
key_down[] bitmap stores currently pressed key as keycode, it should be
associated with an input keymap in order to retrieve the associated
keysym.

Allocating this array in each input allows to retrieve its associated
keymap.

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 46 +++
 1 file changed, 32 insertions(+), 14 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 4f09331ad5c3..7272e1828838 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -122,6 +122,7 @@ struct kbd_handle {
struct kref ref;
struct kbd_conf *conf;
struct input_handle handle;
+   unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];/* keyboard key bitmap */
 };
 #define hdl_to_kbd_handle(h) (container_of(h, struct kbd_handle, handle))
 
@@ -140,7 +141,6 @@ static const int NR_TYPES = ARRAY_SIZE(max_vals);
 static struct input_handler kbd_handler;
 static DEFINE_SPINLOCK(kbd_event_lock);
 static DEFINE_SPINLOCK(led_lock);
-static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap 
*/
 static unsigned char shift_down[NR_SHIFT]; /* shift state 
counters.. */
 static bool dead_key_next;
 static int npadch = -1;/* -1 or number 
assembled on pad */
@@ -378,20 +378,18 @@ static void to_utf8(struct vc_data *vc, uint c)
 
 /*
  * Called after returning from RAW mode or when changing consoles - recompute
- * shift_down[] and shift_state from key_down[] maybe called when keymap is
- * undefined, so that shiftkey release is seen. The caller must hold the
- * kbd_event_lock.
+ * shift_down[] and shift_state from each input's key_down[] maybe called when
+ * keymap is undefined, so that shiftkey release is seen. The caller must hold
+ * the kbd_event_lock.
  */
 
-static void do_compute_shiftstate(void)
+static int do_compute_input_shiftstate(struct input_handle *handle, void *data)
 {
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
unsigned int k, sym, val;
 
-   shift_state = 0;
-   memset(shift_down, 0, sizeof(shift_down));
-
-   for_each_set_bit(k, key_down, min(NR_KEYS, KEY_CNT)) {
-   sym = U(key_maps[0][k]);
+   for_each_set_bit(k, kh->key_down, min(NR_KEYS, KEY_CNT)) {
+   sym = U(kh->conf->maps[0][k]);
if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
continue;
 
@@ -402,6 +400,15 @@ static void do_compute_shiftstate(void)
shift_down[val]++;
shift_state |= BIT(val);
}
+   return 0;
+}
+
+static void do_compute_shiftstate(void)
+{
+   shift_state = 0;
+   memset(shift_down, 0, sizeof(shift_down));
+   input_handler_for_each_handle(_handler, NULL,
+   do_compute_input_shiftstate);
 }
 
 /* We still have to export this method to vt.c */
@@ -1278,6 +1285,17 @@ static int sparc_l1_a_state;
 extern void sun_do_break(void);
 #endif
 
+static int is_alt_down(struct input_handle *handle, void *data)
+{
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
+
+   if (test_bit(KEY_LEFTALT, kh->key_down) ||
+   test_bit(KEY_RIGHTALT, kh->key_down))
+   return 1;
+
+   return 0;
+}
+
 static int emulate_raw(struct vc_data *vc, unsigned int keycode,
   unsigned char up_flag)
 {
@@ -1308,8 +1326,8 @@ static int emulate_raw(struct vc_data *vc, unsigned int 
keycode,
 * pressing PrtSc/SysRq alone, but simply 0x54
 * when pressing Alt+PrtSc/SysRq.
 */
-   if (test_bit(KEY_LEFTALT, key_down) ||
-   test_bit(KEY_RIGHTALT, key_down)) {
+   if (input_handler_for_each_handle(_handler, NULL,
+   is_alt_down)) {
put_queue(vc, 0x54 | up_flag);
} else {
put_queue(vc, 0xe0);
@@ -1424,9 +1442,9 @@ static void kbd_keycode(struct kbd_handle *kh, unsigned 
int keycode, int down,
}
 
if (down)
-   set_bit(keycode, key_down);
+   set_bit(keycode, kh->key_down);
else
-   clear_bit(keycode, key_down);
+   clear_bit(keycode, kh->key_down);
 
if (rep &&
(!vc_kbd_mode(kbd, VC_REPEAT) ||
-- 
2.18.0



[RFC PATCH 3/4] drivers/tty/vt/keyboard.c: Make key_down[] bitmap input dependent

2018-08-22 Thread Remi Pommarel
A kbd_handle input can have a specific keyboard config that makes
keycode to keysym mapping array different from another one. Because
key_down[] bitmap stores currently pressed key as keycode, it should be
associated with an input keymap in order to retrieve the associated
keysym.

Allocating this array in each input allows to retrieve its associated
keymap.

Signed-off-by: Remi Pommarel 
Tested-by: Elie Roudninski 
---
 drivers/tty/vt/keyboard.c | 46 +++
 1 file changed, 32 insertions(+), 14 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 4f09331ad5c3..7272e1828838 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -122,6 +122,7 @@ struct kbd_handle {
struct kref ref;
struct kbd_conf *conf;
struct input_handle handle;
+   unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];/* keyboard key bitmap */
 };
 #define hdl_to_kbd_handle(h) (container_of(h, struct kbd_handle, handle))
 
@@ -140,7 +141,6 @@ static const int NR_TYPES = ARRAY_SIZE(max_vals);
 static struct input_handler kbd_handler;
 static DEFINE_SPINLOCK(kbd_event_lock);
 static DEFINE_SPINLOCK(led_lock);
-static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap 
*/
 static unsigned char shift_down[NR_SHIFT]; /* shift state 
counters.. */
 static bool dead_key_next;
 static int npadch = -1;/* -1 or number 
assembled on pad */
@@ -378,20 +378,18 @@ static void to_utf8(struct vc_data *vc, uint c)
 
 /*
  * Called after returning from RAW mode or when changing consoles - recompute
- * shift_down[] and shift_state from key_down[] maybe called when keymap is
- * undefined, so that shiftkey release is seen. The caller must hold the
- * kbd_event_lock.
+ * shift_down[] and shift_state from each input's key_down[] maybe called when
+ * keymap is undefined, so that shiftkey release is seen. The caller must hold
+ * the kbd_event_lock.
  */
 
-static void do_compute_shiftstate(void)
+static int do_compute_input_shiftstate(struct input_handle *handle, void *data)
 {
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
unsigned int k, sym, val;
 
-   shift_state = 0;
-   memset(shift_down, 0, sizeof(shift_down));
-
-   for_each_set_bit(k, key_down, min(NR_KEYS, KEY_CNT)) {
-   sym = U(key_maps[0][k]);
+   for_each_set_bit(k, kh->key_down, min(NR_KEYS, KEY_CNT)) {
+   sym = U(kh->conf->maps[0][k]);
if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
continue;
 
@@ -402,6 +400,15 @@ static void do_compute_shiftstate(void)
shift_down[val]++;
shift_state |= BIT(val);
}
+   return 0;
+}
+
+static void do_compute_shiftstate(void)
+{
+   shift_state = 0;
+   memset(shift_down, 0, sizeof(shift_down));
+   input_handler_for_each_handle(_handler, NULL,
+   do_compute_input_shiftstate);
 }
 
 /* We still have to export this method to vt.c */
@@ -1278,6 +1285,17 @@ static int sparc_l1_a_state;
 extern void sun_do_break(void);
 #endif
 
+static int is_alt_down(struct input_handle *handle, void *data)
+{
+   struct kbd_handle *kh = hdl_to_kbd_handle(handle);
+
+   if (test_bit(KEY_LEFTALT, kh->key_down) ||
+   test_bit(KEY_RIGHTALT, kh->key_down))
+   return 1;
+
+   return 0;
+}
+
 static int emulate_raw(struct vc_data *vc, unsigned int keycode,
   unsigned char up_flag)
 {
@@ -1308,8 +1326,8 @@ static int emulate_raw(struct vc_data *vc, unsigned int 
keycode,
 * pressing PrtSc/SysRq alone, but simply 0x54
 * when pressing Alt+PrtSc/SysRq.
 */
-   if (test_bit(KEY_LEFTALT, key_down) ||
-   test_bit(KEY_RIGHTALT, key_down)) {
+   if (input_handler_for_each_handle(_handler, NULL,
+   is_alt_down)) {
put_queue(vc, 0x54 | up_flag);
} else {
put_queue(vc, 0xe0);
@@ -1424,9 +1442,9 @@ static void kbd_keycode(struct kbd_handle *kh, unsigned 
int keycode, int down,
}
 
if (down)
-   set_bit(keycode, key_down);
+   set_bit(keycode, kh->key_down);
else
-   clear_bit(keycode, key_down);
+   clear_bit(keycode, kh->key_down);
 
if (rep &&
(!vc_kbd_mode(kbd, VC_REPEAT) ||
-- 
2.18.0



Re: [PATCH v3 0/4] Add PWM clock support for bcm2835

2015-12-23 Thread Remi Pommarel
On Sun, Dec 06, 2015 at 05:22:45PM +0100, Remi Pommarel wrote:
> Hi,
> 
> This patchset adds support for pwm clock. At boot, this clock does not have a
> default parent nor a default rate set. Thus we should be able to change its
> parent to get this clock working. The current clock implementation is using a
> mux to select the parent, but these clocks need to add a password (0x5a) in
> higher register bits when changing parent. So a generic mux cannot be used
> here.
> 
> The two first patches fix the clock parent selection, while the last ones are
> actually adding the pwm clock registration.
> 
> Changes since v1:
>   - determine_rate now based its parent selection upon divided rate
> instead of the parent one
>   - bcm2835_clock_choose_div has been modified to produce an avarage rate
> lower or equal to the requested one
>   - devicetree modifications have removed to be send in another patch
> 
> Changes since v2:
>   - Remove useless variable and include
>   - Make bcm2835_clock_choose_div() divisor round up ability optional
>   - Set rate in bcm2835_determine_rate()
>   - Add device tree modification in a separate patch
> 
> 
> Remi Pommarel (4):
>   clk: bcm2835: add a round up ability to the clock divisor
>   clk: bcm2835: Support for clock parent selection
>   clk: bcm2835: Add PWM clock support
>   clk: bcm2835: Add PWM clock support to the device tree
> 
>  arch/arm/boot/dts/bcm2835-rpi.dtsi  |   4 +
>  arch/arm/boot/dts/bcm2835.dtsi  |   9 +++
>  drivers/clk/bcm/clk-bcm2835.c   | 155 
> +++-
>  include/dt-bindings/clock/bcm2835.h |   3 +-
>  4 files changed, 116 insertions(+), 55 deletions(-)
> 

Gently ping.

Patches 0 to 3 are reviewed by Eric, and can eventually be pushed on clk
tree.

Patch 4 has been sent on devicetree mailinglist for review
(http://www.spinics.net/lists/devicetree/msg108070.html), waiting for
previous patches to be pushed.

Thanks

-- 
Remi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v3 0/4] Add PWM clock support for bcm2835

2015-12-23 Thread Remi Pommarel
On Sun, Dec 06, 2015 at 05:22:45PM +0100, Remi Pommarel wrote:
> Hi,
> 
> This patchset adds support for pwm clock. At boot, this clock does not have a
> default parent nor a default rate set. Thus we should be able to change its
> parent to get this clock working. The current clock implementation is using a
> mux to select the parent, but these clocks need to add a password (0x5a) in
> higher register bits when changing parent. So a generic mux cannot be used
> here.
> 
> The two first patches fix the clock parent selection, while the last ones are
> actually adding the pwm clock registration.
> 
> Changes since v1:
>   - determine_rate now based its parent selection upon divided rate
> instead of the parent one
>   - bcm2835_clock_choose_div has been modified to produce an avarage rate
> lower or equal to the requested one
>   - devicetree modifications have removed to be send in another patch
> 
> Changes since v2:
>   - Remove useless variable and include
>   - Make bcm2835_clock_choose_div() divisor round up ability optional
>   - Set rate in bcm2835_determine_rate()
>   - Add device tree modification in a separate patch
> 
> 
> Remi Pommarel (4):
>   clk: bcm2835: add a round up ability to the clock divisor
>   clk: bcm2835: Support for clock parent selection
>   clk: bcm2835: Add PWM clock support
>   clk: bcm2835: Add PWM clock support to the device tree
> 
>  arch/arm/boot/dts/bcm2835-rpi.dtsi  |   4 +
>  arch/arm/boot/dts/bcm2835.dtsi  |   9 +++
>  drivers/clk/bcm/clk-bcm2835.c   | 155 
> +++-
>  include/dt-bindings/clock/bcm2835.h |   3 +-
>  4 files changed, 116 insertions(+), 55 deletions(-)
> 

Gently ping.

Patches 0 to 3 are reviewed by Eric, and can eventually be pushed on clk
tree.

Patch 4 has been sent on devicetree mailinglist for review
(http://www.spinics.net/lists/devicetree/msg108070.html), waiting for
previous patches to be pushed.

Thanks

-- 
Remi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v3 4/4] clk: bcm2835: Add PWM clock support to the device tree

2015-12-15 Thread Remi Pommarel
On Mon, Dec 07, 2015 at 08:09:47PM -0800, Eric Anholt wrote:
> Stefan Wahren  writes:
> 
> > Hi Remi,
> >
> > Am 07.12.2015 um 19:17 schrieb Remi Pommarel:
> >> Hi Stefan,
> >>
> >> On Sun, Dec 06, 2015 at 10:16:25PM +0100, Stefan Wahren wrote:
> >>> Hi Remi,
> >>>
> >>> please send this patch to devicet...@vger.kernel.org.
> >>
> >> Ok, just to be sure I understand the process here. I should resend a new
> >> version of the whole patchset including the devicetree mailing list as
> >> recipent. Then the first 3 patches will eventually get pushed by a clock
> >> subsystem maintainer. And finally this last patch will be pushed by a
> >> devicetree maintainer.
> >>
> >> Am I right here ?
> >
> > sorry for the confusion. I mean that you send a copy to 
> > devicet...@vger.kernel.org so subscribers have a chance to review.
> >
> > I'm not sure but according to your subject you suggest that this dts 
> > patch should go through clock subsystem which isn't optimal. This should 
> > be better applied by Stephen or Eric.
> 
> It would be applied by me, but that's for me to worry about, not the
> patch submitter.  The subject prefix would be "ARM: bcm2835: ", but
> that's trivial for me to fix when applying, not the kind of thing worth
> asking for a respin for.

Thanks for review.

I'll submit dt patch to devicet...@vger.kernel.org for review. Is it better
to submit the whole patchset (patch 1 to 4) to provide some context for the
device tree patch or just this patch alone ?

Best Regards,

-- 
Remi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v3 4/4] clk: bcm2835: Add PWM clock support to the device tree

2015-12-15 Thread Remi Pommarel
On Mon, Dec 07, 2015 at 08:09:47PM -0800, Eric Anholt wrote:
> Stefan Wahren <i...@lategoodbye.de> writes:
> 
> > Hi Remi,
> >
> > Am 07.12.2015 um 19:17 schrieb Remi Pommarel:
> >> Hi Stefan,
> >>
> >> On Sun, Dec 06, 2015 at 10:16:25PM +0100, Stefan Wahren wrote:
> >>> Hi Remi,
> >>>
> >>> please send this patch to devicet...@vger.kernel.org.
> >>
> >> Ok, just to be sure I understand the process here. I should resend a new
> >> version of the whole patchset including the devicetree mailing list as
> >> recipent. Then the first 3 patches will eventually get pushed by a clock
> >> subsystem maintainer. And finally this last patch will be pushed by a
> >> devicetree maintainer.
> >>
> >> Am I right here ?
> >
> > sorry for the confusion. I mean that you send a copy to 
> > devicet...@vger.kernel.org so subscribers have a chance to review.
> >
> > I'm not sure but according to your subject you suggest that this dts 
> > patch should go through clock subsystem which isn't optimal. This should 
> > be better applied by Stephen or Eric.
> 
> It would be applied by me, but that's for me to worry about, not the
> patch submitter.  The subject prefix would be "ARM: bcm2835: ", but
> that's trivial for me to fix when applying, not the kind of thing worth
> asking for a respin for.

Thanks for review.

I'll submit dt patch to devicet...@vger.kernel.org for review. Is it better
to submit the whole patchset (patch 1 to 4) to provide some context for the
device tree patch or just this patch alone ?

Best Regards,

-- 
Remi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v3 4/4] clk: bcm2835: Add PWM clock support to the device tree

2015-12-07 Thread Remi Pommarel
Hi Stefan,

On Sun, Dec 06, 2015 at 10:16:25PM +0100, Stefan Wahren wrote:
> Hi Remi,
> 
> please send this patch to devicet...@vger.kernel.org.

Ok, just to be sure I understand the process here. I should resend a new
version of the whole patchset including the devicetree mailing list as
recipent. Then the first 3 patches will eventually get pushed by a clock
subsystem maintainer. And finally this last patch will be pushed by a
devicetree maintainer.

Am I right here ?

> 
> Am 06.12.2015 um 17:22 schrieb Remi Pommarel:
> >Signed-off-by: Remi Pommarel 
> >---
> >  arch/arm/boot/dts/bcm2835-rpi.dtsi | 4 
> >  arch/arm/boot/dts/bcm2835.dtsi | 9 +
> >  2 files changed, 13 insertions(+)
> >
> >diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi 
> >b/arch/arm/boot/dts/bcm2835-rpi.dtsi
> >index 3572f03..55801e0 100644
> >--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
> >+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
> >@@ -60,3 +60,7 @@
> > status = "okay";
> > bus-width = <4>;
> >  };
> >+
> >+ {
> >+status = "okay";
> >+};
> >diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
> >index aef64de..641f7f4 100644
> >--- a/arch/arm/boot/dts/bcm2835.dtsi
> >+++ b/arch/arm/boot/dts/bcm2835.dtsi
> >@@ -149,6 +149,15 @@
> > status = "disabled";
> > };
> >
> >+pwm: pwm@7e20c000 {
> >+compatible = "brcm,bcm2835-pwm";
> >+reg = <0x7e20c000 0x28>;
> >+clocks = < BCM2835_CLOCK_PWM>;
> 
> Looks like #pwm-cells is missing.
> 

Yes will do. Thank you.

Regards

-- 
Remi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v3 4/4] clk: bcm2835: Add PWM clock support to the device tree

2015-12-07 Thread Remi Pommarel
Hi Stefan,

On Sun, Dec 06, 2015 at 10:16:25PM +0100, Stefan Wahren wrote:
> Hi Remi,
> 
> please send this patch to devicet...@vger.kernel.org.

Ok, just to be sure I understand the process here. I should resend a new
version of the whole patchset including the devicetree mailing list as
recipent. Then the first 3 patches will eventually get pushed by a clock
subsystem maintainer. And finally this last patch will be pushed by a
devicetree maintainer.

Am I right here ?

> 
> Am 06.12.2015 um 17:22 schrieb Remi Pommarel:
> >Signed-off-by: Remi Pommarel <r...@triplefau.lt>
> >---
> >  arch/arm/boot/dts/bcm2835-rpi.dtsi | 4 
> >  arch/arm/boot/dts/bcm2835.dtsi | 9 +
> >  2 files changed, 13 insertions(+)
> >
> >diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi 
> >b/arch/arm/boot/dts/bcm2835-rpi.dtsi
> >index 3572f03..55801e0 100644
> >--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
> >+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
> >@@ -60,3 +60,7 @@
> > status = "okay";
> > bus-width = <4>;
> >  };
> >+
> >+ {
> >+status = "okay";
> >+};
> >diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
> >index aef64de..641f7f4 100644
> >--- a/arch/arm/boot/dts/bcm2835.dtsi
> >+++ b/arch/arm/boot/dts/bcm2835.dtsi
> >@@ -149,6 +149,15 @@
> > status = "disabled";
> > };
> >
> >+pwm: pwm@7e20c000 {
> >+compatible = "brcm,bcm2835-pwm";
> >+reg = <0x7e20c000 0x28>;
> >+clocks = < BCM2835_CLOCK_PWM>;
> 
> Looks like #pwm-cells is missing.
> 

Yes will do. Thank you.

Regards

-- 
Remi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3 2/4] clk: bcm2835: Support for clock parent selection

2015-12-06 Thread Remi Pommarel
Some bcm2835 clocks used by hardware (like "PWM" or "H264") can have multiple
parent clocks. These clocks divide the rate of a parent which can be selected by
setting the proper bits in the clock control register.

Previously all these parents where handled by a mux clock. But a mux clock
cannot be used because updating clock control register to select parent needs a
password to be xor'd with the parent index.

This patch get rid of mux clock and make these clocks handle their own parent,
allowing them to select the one to use.

Signed-off-by: Remi Pommarel 
---
 drivers/clk/bcm/clk-bcm2835.c | 122 ++
 1 file changed, 77 insertions(+), 45 deletions(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 9e881ee..6e4dd6f 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1199,16 +1199,6 @@ static long bcm2835_clock_rate_from_divisor(struct 
bcm2835_clock *clock,
return temp;
 }
 
-static long bcm2835_clock_round_rate(struct clk_hw *hw,
-unsigned long rate,
-unsigned long *parent_rate)
-{
-   struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
-   u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate, false);
-
-   return bcm2835_clock_rate_from_divisor(clock, *parent_rate, div);
-}
-
 static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw,
unsigned long parent_rate)
 {
@@ -1280,13 +1270,75 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
return 0;
 }
 
+static int bcm2835_clock_determine_rate(struct clk_hw *hw,
+   struct clk_rate_request *req)
+{
+   struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+   struct clk_hw *parent, *best_parent = NULL;
+   unsigned long rate, best_rate = 0;
+   unsigned long prate, best_prate = 0;
+   size_t i;
+   u32 div;
+
+   /*
+* Select parent clock that results in the closest but lower rate
+*/
+   for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
+   parent = clk_hw_get_parent_by_index(hw, i);
+   if (!parent)
+   continue;
+   prate = clk_hw_get_rate(parent);
+   div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
+   rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
+   if (rate > best_rate && rate <= req->rate) {
+   best_parent = parent;
+   best_prate = prate;
+   best_rate = rate;
+   }
+   }
+
+   if (!best_parent)
+   return -EINVAL;
+
+   req->best_parent_hw = best_parent;
+   req->best_parent_rate = best_prate;
+
+   req->rate = best_rate;
+
+   return 0;
+}
+
+static int bcm2835_clock_set_parent(struct clk_hw *hw, u8 index)
+{
+   struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+   struct bcm2835_cprman *cprman = clock->cprman;
+   const struct bcm2835_clock_data *data = clock->data;
+   u8 src = (index << CM_SRC_SHIFT) & CM_SRC_MASK;
+
+   cprman_write(cprman, data->ctl_reg, src);
+   return 0;
+}
+
+static u8 bcm2835_clock_get_parent(struct clk_hw *hw)
+{
+   struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+   struct bcm2835_cprman *cprman = clock->cprman;
+   const struct bcm2835_clock_data *data = clock->data;
+   u32 src = cprman_read(cprman, data->ctl_reg);
+
+   return (src & CM_SRC_MASK) >> CM_SRC_SHIFT;
+}
+
+
 static const struct clk_ops bcm2835_clock_clk_ops = {
.is_prepared = bcm2835_clock_is_on,
.prepare = bcm2835_clock_on,
.unprepare = bcm2835_clock_off,
.recalc_rate = bcm2835_clock_get_rate,
.set_rate = bcm2835_clock_set_rate,
-   .round_rate = bcm2835_clock_round_rate,
+   .determine_rate = bcm2835_clock_determine_rate,
+   .set_parent = bcm2835_clock_set_parent,
+   .get_parent = bcm2835_clock_get_parent,
 };
 
 static int bcm2835_vpu_clock_is_on(struct clk_hw *hw)
@@ -1302,7 +1354,9 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
.is_prepared = bcm2835_vpu_clock_is_on,
.recalc_rate = bcm2835_clock_get_rate,
.set_rate = bcm2835_clock_set_rate,
-   .round_rate = bcm2835_clock_round_rate,
+   .determine_rate = bcm2835_clock_determine_rate,
+   .set_parent = bcm2835_clock_set_parent,
+   .get_parent = bcm2835_clock_get_parent,
 };
 
 static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman,
@@ -1396,45 +1450,23 @@ static struct clk *bcm2835_register_clock(struct 
bcm2835_cprman *cprman,
 {
struct bcm2835_clock *clock;
struct clk_init_data init;
-   const char *parent;
+   const char *parents[1 << CM_SR

[PATCH v3 4/4] clk: bcm2835: Add PWM clock support to the device tree

2015-12-06 Thread Remi Pommarel
Signed-off-by: Remi Pommarel 
---
 arch/arm/boot/dts/bcm2835-rpi.dtsi | 4 
 arch/arm/boot/dts/bcm2835.dtsi | 9 +
 2 files changed, 13 insertions(+)

diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi 
b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index 3572f03..55801e0 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -60,3 +60,7 @@
status = "okay";
bus-width = <4>;
 };
+
+ {
+   status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
index aef64de..641f7f4 100644
--- a/arch/arm/boot/dts/bcm2835.dtsi
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -149,6 +149,15 @@
status = "disabled";
};
 
+   pwm: pwm@7e20c000 {
+   compatible = "brcm,bcm2835-pwm";
+   reg = <0x7e20c000 0x28>;
+   clocks = < BCM2835_CLOCK_PWM>;
+   assigned-clocks = < BCM2835_CLOCK_PWM>;
+   assigned-clock-rates = <1000>;
+   status = "disabled";
+   };
+
sdhci: sdhci@7e30 {
compatible = "brcm,bcm2835-sdhci";
reg = <0x7e30 0x100>;
-- 
2.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3 1/4] clk: bcm2835: add a round up ability to the clock divisor

2015-12-06 Thread Remi Pommarel
Make bcm2835_clock_choose_div to optionally round up the chosen MASH divisor
so that the resulting average rate will not be higher than the requested one.

Signed-off-by: Remi Pommarel 
---
 drivers/clk/bcm/clk-bcm2835.c | 22 --
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 39bf582..9e881ee 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1148,22 +1148,24 @@ static int bcm2835_clock_is_on(struct clk_hw *hw)
 
 static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
unsigned long rate,
-   unsigned long parent_rate)
+   unsigned long parent_rate,
+   bool round_up)
 {
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
const struct bcm2835_clock_data *data = clock->data;
-   u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
+   u32 unused_frac_mask =
+   GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
+   u64 rem;
u32 div;
 
-   do_div(temp, rate);
+   rem = do_div(temp, rate);
div = temp;
 
-   /* Round and mask off the unused bits */
-   if (unused_frac_mask != 0) {
-   div += unused_frac_mask >> 1;
-   div &= ~unused_frac_mask;
-   }
+   /* Round up and mask off the unused bits */
+   if (round_up && ((div & unused_frac_mask) != 0 || rem != 0))
+   div += unused_frac_mask + 1;
+   div &= ~unused_frac_mask;
 
/* Clamp to the limits. */
div = max(div, unused_frac_mask + 1);
@@ -1202,7 +1204,7 @@ static long bcm2835_clock_round_rate(struct clk_hw *hw,
 unsigned long *parent_rate)
 {
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
-   u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate);
+   u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate, false);
 
return bcm2835_clock_rate_from_divisor(clock, *parent_rate, div);
 }
@@ -1271,7 +1273,7 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
struct bcm2835_cprman *cprman = clock->cprman;
const struct bcm2835_clock_data *data = clock->data;
-   u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate);
+   u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false);
 
cprman_write(cprman, data->div_reg, div);
 
-- 
2.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3 3/4] clk: bcm2835: Add PWM clock support

2015-12-06 Thread Remi Pommarel
Register the pwm clock for bcm2835.

Signed-off-by: Remi Pommarel 
---
 drivers/clk/bcm/clk-bcm2835.c   | 13 +
 include/dt-bindings/clock/bcm2835.h |  3 ++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 6e4dd6f..015e687 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -807,6 +807,16 @@ static const struct bcm2835_clock_data 
bcm2835_clock_emmc_data = {
.frac_bits = 8,
 };
 
+static const struct bcm2835_clock_data bcm2835_clock_pwm_data = {
+   .name = "pwm",
+   .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
+   .parents = bcm2835_clock_per_parents,
+   .ctl_reg = CM_PWMCTL,
+   .div_reg = CM_PWMDIV,
+   .int_bits = 12,
+   .frac_bits = 12,
+};
+
 struct bcm2835_pll {
struct clk_hw hw;
struct bcm2835_cprman *cprman;
@@ -1584,6 +1594,9 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
  cprman->regs + CM_PERIICTL, CM_GATE_BIT,
  0, >regs_lock);
 
+   clks[BCM2835_CLOCK_PWM] =
+   bcm2835_register_clock(cprman, _clock_pwm_data);
+
return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
   >onecell);
 }
diff --git a/include/dt-bindings/clock/bcm2835.h 
b/include/dt-bindings/clock/bcm2835.h
index d323efa..61f1d20 100644
--- a/include/dt-bindings/clock/bcm2835.h
+++ b/include/dt-bindings/clock/bcm2835.h
@@ -43,5 +43,6 @@
 #define BCM2835_CLOCK_TSENS27
 #define BCM2835_CLOCK_EMMC 28
 #define BCM2835_CLOCK_PERI_IMAGE   29
+#define BCM2835_CLOCK_PWM  30
 
-#define BCM2835_CLOCK_COUNT30
+#define BCM2835_CLOCK_COUNT31
-- 
2.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3 0/4] Add PWM clock support for bcm2835

2015-12-06 Thread Remi Pommarel
Hi,

This patchset adds support for pwm clock. At boot, this clock does not have a
default parent nor a default rate set. Thus we should be able to change its
parent to get this clock working. The current clock implementation is using a
mux to select the parent, but these clocks need to add a password (0x5a) in
higher register bits when changing parent. So a generic mux cannot be used
here.

The two first patches fix the clock parent selection, while the last ones are
actually adding the pwm clock registration.

Changes since v1:
- determine_rate now based its parent selection upon divided rate
  instead of the parent one
- bcm2835_clock_choose_div has been modified to produce an avarage rate
  lower or equal to the requested one
- devicetree modifications have removed to be send in another patch

Changes since v2:
- Remove useless variable and include
- Make bcm2835_clock_choose_div() divisor round up ability optional
- Set rate in bcm2835_determine_rate()
- Add device tree modification in a separate patch


Remi Pommarel (4):
  clk: bcm2835: add a round up ability to the clock divisor
  clk: bcm2835: Support for clock parent selection
  clk: bcm2835: Add PWM clock support
  clk: bcm2835: Add PWM clock support to the device tree

 arch/arm/boot/dts/bcm2835-rpi.dtsi  |   4 +
 arch/arm/boot/dts/bcm2835.dtsi  |   9 +++
 drivers/clk/bcm/clk-bcm2835.c   | 155 +++-
 include/dt-bindings/clock/bcm2835.h |   3 +-
 4 files changed, 116 insertions(+), 55 deletions(-)

-- 
2.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3 0/4] Add PWM clock support for bcm2835

2015-12-06 Thread Remi Pommarel
Hi,

This patchset adds support for pwm clock. At boot, this clock does not have a
default parent nor a default rate set. Thus we should be able to change its
parent to get this clock working. The current clock implementation is using a
mux to select the parent, but these clocks need to add a password (0x5a) in
higher register bits when changing parent. So a generic mux cannot be used
here.

The two first patches fix the clock parent selection, while the last ones are
actually adding the pwm clock registration.

Changes since v1:
- determine_rate now based its parent selection upon divided rate
  instead of the parent one
- bcm2835_clock_choose_div has been modified to produce an avarage rate
  lower or equal to the requested one
- devicetree modifications have removed to be send in another patch

Changes since v2:
- Remove useless variable and include
- Make bcm2835_clock_choose_div() divisor round up ability optional
- Set rate in bcm2835_determine_rate()
- Add device tree modification in a separate patch


Remi Pommarel (4):
  clk: bcm2835: add a round up ability to the clock divisor
  clk: bcm2835: Support for clock parent selection
  clk: bcm2835: Add PWM clock support
  clk: bcm2835: Add PWM clock support to the device tree

 arch/arm/boot/dts/bcm2835-rpi.dtsi  |   4 +
 arch/arm/boot/dts/bcm2835.dtsi  |   9 +++
 drivers/clk/bcm/clk-bcm2835.c   | 155 +++-
 include/dt-bindings/clock/bcm2835.h |   3 +-
 4 files changed, 116 insertions(+), 55 deletions(-)

-- 
2.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3 3/4] clk: bcm2835: Add PWM clock support

2015-12-06 Thread Remi Pommarel
Register the pwm clock for bcm2835.

Signed-off-by: Remi Pommarel <r...@triplefau.lt>
---
 drivers/clk/bcm/clk-bcm2835.c   | 13 +
 include/dt-bindings/clock/bcm2835.h |  3 ++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 6e4dd6f..015e687 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -807,6 +807,16 @@ static const struct bcm2835_clock_data 
bcm2835_clock_emmc_data = {
.frac_bits = 8,
 };
 
+static const struct bcm2835_clock_data bcm2835_clock_pwm_data = {
+   .name = "pwm",
+   .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
+   .parents = bcm2835_clock_per_parents,
+   .ctl_reg = CM_PWMCTL,
+   .div_reg = CM_PWMDIV,
+   .int_bits = 12,
+   .frac_bits = 12,
+};
+
 struct bcm2835_pll {
struct clk_hw hw;
struct bcm2835_cprman *cprman;
@@ -1584,6 +1594,9 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
  cprman->regs + CM_PERIICTL, CM_GATE_BIT,
  0, >regs_lock);
 
+   clks[BCM2835_CLOCK_PWM] =
+   bcm2835_register_clock(cprman, _clock_pwm_data);
+
return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
   >onecell);
 }
diff --git a/include/dt-bindings/clock/bcm2835.h 
b/include/dt-bindings/clock/bcm2835.h
index d323efa..61f1d20 100644
--- a/include/dt-bindings/clock/bcm2835.h
+++ b/include/dt-bindings/clock/bcm2835.h
@@ -43,5 +43,6 @@
 #define BCM2835_CLOCK_TSENS27
 #define BCM2835_CLOCK_EMMC 28
 #define BCM2835_CLOCK_PERI_IMAGE   29
+#define BCM2835_CLOCK_PWM  30
 
-#define BCM2835_CLOCK_COUNT30
+#define BCM2835_CLOCK_COUNT31
-- 
2.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3 1/4] clk: bcm2835: add a round up ability to the clock divisor

2015-12-06 Thread Remi Pommarel
Make bcm2835_clock_choose_div to optionally round up the chosen MASH divisor
so that the resulting average rate will not be higher than the requested one.

Signed-off-by: Remi Pommarel <r...@triplefau.lt>
---
 drivers/clk/bcm/clk-bcm2835.c | 22 --
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 39bf582..9e881ee 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1148,22 +1148,24 @@ static int bcm2835_clock_is_on(struct clk_hw *hw)
 
 static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
unsigned long rate,
-   unsigned long parent_rate)
+   unsigned long parent_rate,
+   bool round_up)
 {
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
const struct bcm2835_clock_data *data = clock->data;
-   u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
+   u32 unused_frac_mask =
+   GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
+   u64 rem;
u32 div;
 
-   do_div(temp, rate);
+   rem = do_div(temp, rate);
div = temp;
 
-   /* Round and mask off the unused bits */
-   if (unused_frac_mask != 0) {
-   div += unused_frac_mask >> 1;
-   div &= ~unused_frac_mask;
-   }
+   /* Round up and mask off the unused bits */
+   if (round_up && ((div & unused_frac_mask) != 0 || rem != 0))
+   div += unused_frac_mask + 1;
+   div &= ~unused_frac_mask;
 
/* Clamp to the limits. */
div = max(div, unused_frac_mask + 1);
@@ -1202,7 +1204,7 @@ static long bcm2835_clock_round_rate(struct clk_hw *hw,
 unsigned long *parent_rate)
 {
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
-   u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate);
+   u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate, false);
 
return bcm2835_clock_rate_from_divisor(clock, *parent_rate, div);
 }
@@ -1271,7 +1273,7 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
struct bcm2835_cprman *cprman = clock->cprman;
const struct bcm2835_clock_data *data = clock->data;
-   u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate);
+   u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false);
 
cprman_write(cprman, data->div_reg, div);
 
-- 
2.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3 2/4] clk: bcm2835: Support for clock parent selection

2015-12-06 Thread Remi Pommarel
Some bcm2835 clocks used by hardware (like "PWM" or "H264") can have multiple
parent clocks. These clocks divide the rate of a parent which can be selected by
setting the proper bits in the clock control register.

Previously all these parents where handled by a mux clock. But a mux clock
cannot be used because updating clock control register to select parent needs a
password to be xor'd with the parent index.

This patch get rid of mux clock and make these clocks handle their own parent,
allowing them to select the one to use.

Signed-off-by: Remi Pommarel <r...@triplefau.lt>
---
 drivers/clk/bcm/clk-bcm2835.c | 122 ++
 1 file changed, 77 insertions(+), 45 deletions(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 9e881ee..6e4dd6f 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1199,16 +1199,6 @@ static long bcm2835_clock_rate_from_divisor(struct 
bcm2835_clock *clock,
return temp;
 }
 
-static long bcm2835_clock_round_rate(struct clk_hw *hw,
-unsigned long rate,
-unsigned long *parent_rate)
-{
-   struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
-   u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate, false);
-
-   return bcm2835_clock_rate_from_divisor(clock, *parent_rate, div);
-}
-
 static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw,
unsigned long parent_rate)
 {
@@ -1280,13 +1270,75 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
return 0;
 }
 
+static int bcm2835_clock_determine_rate(struct clk_hw *hw,
+   struct clk_rate_request *req)
+{
+   struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+   struct clk_hw *parent, *best_parent = NULL;
+   unsigned long rate, best_rate = 0;
+   unsigned long prate, best_prate = 0;
+   size_t i;
+   u32 div;
+
+   /*
+* Select parent clock that results in the closest but lower rate
+*/
+   for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
+   parent = clk_hw_get_parent_by_index(hw, i);
+   if (!parent)
+   continue;
+   prate = clk_hw_get_rate(parent);
+   div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
+   rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
+   if (rate > best_rate && rate <= req->rate) {
+   best_parent = parent;
+   best_prate = prate;
+   best_rate = rate;
+   }
+   }
+
+   if (!best_parent)
+   return -EINVAL;
+
+   req->best_parent_hw = best_parent;
+   req->best_parent_rate = best_prate;
+
+   req->rate = best_rate;
+
+   return 0;
+}
+
+static int bcm2835_clock_set_parent(struct clk_hw *hw, u8 index)
+{
+   struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+   struct bcm2835_cprman *cprman = clock->cprman;
+   const struct bcm2835_clock_data *data = clock->data;
+   u8 src = (index << CM_SRC_SHIFT) & CM_SRC_MASK;
+
+   cprman_write(cprman, data->ctl_reg, src);
+   return 0;
+}
+
+static u8 bcm2835_clock_get_parent(struct clk_hw *hw)
+{
+   struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+   struct bcm2835_cprman *cprman = clock->cprman;
+   const struct bcm2835_clock_data *data = clock->data;
+   u32 src = cprman_read(cprman, data->ctl_reg);
+
+   return (src & CM_SRC_MASK) >> CM_SRC_SHIFT;
+}
+
+
 static const struct clk_ops bcm2835_clock_clk_ops = {
.is_prepared = bcm2835_clock_is_on,
.prepare = bcm2835_clock_on,
.unprepare = bcm2835_clock_off,
.recalc_rate = bcm2835_clock_get_rate,
.set_rate = bcm2835_clock_set_rate,
-   .round_rate = bcm2835_clock_round_rate,
+   .determine_rate = bcm2835_clock_determine_rate,
+   .set_parent = bcm2835_clock_set_parent,
+   .get_parent = bcm2835_clock_get_parent,
 };
 
 static int bcm2835_vpu_clock_is_on(struct clk_hw *hw)
@@ -1302,7 +1354,9 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
.is_prepared = bcm2835_vpu_clock_is_on,
.recalc_rate = bcm2835_clock_get_rate,
.set_rate = bcm2835_clock_set_rate,
-   .round_rate = bcm2835_clock_round_rate,
+   .determine_rate = bcm2835_clock_determine_rate,
+   .set_parent = bcm2835_clock_set_parent,
+   .get_parent = bcm2835_clock_get_parent,
 };
 
 static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman,
@@ -1396,45 +1450,23 @@ static struct clk *bcm2835_register_clock(struct 
bcm2835_cprman *cprman,
 {
struct bcm2835_clock *clock;
struct clk_init_data init;
-   const char *parent;
+   const char *p

[PATCH v3 4/4] clk: bcm2835: Add PWM clock support to the device tree

2015-12-06 Thread Remi Pommarel
Signed-off-by: Remi Pommarel <r...@triplefau.lt>
---
 arch/arm/boot/dts/bcm2835-rpi.dtsi | 4 
 arch/arm/boot/dts/bcm2835.dtsi | 9 +
 2 files changed, 13 insertions(+)

diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi 
b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index 3572f03..55801e0 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -60,3 +60,7 @@
status = "okay";
bus-width = <4>;
 };
+
+ {
+   status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
index aef64de..641f7f4 100644
--- a/arch/arm/boot/dts/bcm2835.dtsi
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -149,6 +149,15 @@
status = "disabled";
};
 
+   pwm: pwm@7e20c000 {
+   compatible = "brcm,bcm2835-pwm";
+   reg = <0x7e20c000 0x28>;
+   clocks = < BCM2835_CLOCK_PWM>;
+   assigned-clocks = < BCM2835_CLOCK_PWM>;
+   assigned-clock-rates = <1000>;
+   status = "disabled";
+   };
+
sdhci: sdhci@7e30 {
compatible = "brcm,bcm2835-sdhci";
reg = <0x7e30 0x100>;
-- 
2.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2 2/3] clk: bcm2835: Support for clock parent selection

2015-12-04 Thread Remi Pommarel
On Thu, Dec 03, 2015 at 04:37:07PM -0800, Eric Anholt wrote:
> Remi Pommarel  writes:
> 
> > On Wed, Nov 18, 2015 at 10:30:17AM -0800, Eric Anholt wrote:
> >
> > [...]
> >
> >> > +static int bcm2835_clock_determine_rate(struct clk_hw *hw,
> >> > +struct clk_rate_request *req)
> >> > +{
> >> > +struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
> >> > +struct clk_hw *parent, *best_parent = NULL;
> >> > +struct clk_rate_request parent_req;
> >> > +unsigned long rate, best_rate = 0;
> >> > +unsigned long prate, best_prate = 0;
> >> > +size_t i;
> >> > +u32 div;
> >> > +
> >> > +/*
> >> > + * Select parent clock that results in the closest but lower 
> >> > rate
> >> > + */
> >> > +for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
> >> > +parent = clk_hw_get_parent_by_index(hw, i);
> >> > +if (!parent)
> >> > +continue;
> >> > +parent_req = *req;
> >> 
> >> parent_req appears dead, so it should be removed.
> >
> > Yes, will do thanks.
> >
> >> > +prate = clk_hw_get_rate(parent);
> >> > +div = bcm2835_clock_choose_div(hw, req->rate, prate);
> >> > +rate = bcm2835_clock_rate_from_divisor(clock, prate, 
> >> > div);
> >> > +if (rate > best_rate && rate <= req->rate) {
> >> > +best_parent = parent;
> >> > +best_prate = prate;
> >> > +best_rate = rate;
> >> > +}
> >> > +}
> >> > +
> >> > +if (!best_parent)
> >> > +return -EINVAL;
> >> > +
> >> > +req->best_parent_hw = best_parent;
> >> > +req->best_parent_rate = best_prate;
> >> 
> >> I think you're supposed to req->rate = best_rate, here, too.  With these
> >> two fixes,
> >
> > I did not set req->rate to best_rate in order to avoid rounding down
> > twice the actual clock rate.
> >
> > Indeed with patch 1 from this patchset bcm2835_clock_choose_div()
> > chooses a divisor that produces a rate lower or equal to the requested
> > one. As we call bcm2835_clock_choose_div() twice when using
> > clk_set_rate() (once with ->determine_rate() and once with ->set_rate()),
> > if I set req->rate in bcm2835_clock_determine_rate to the rounded down
> > one, the final rate will likely be again rounded down in
> > bcm2835_clock_set_rate().
> 
> If we pass bcm2835_clock_rate_from_divisor(bcm2835_clock_choose_div()),
> to bcm2835_clock_choose_div(), will it actually give a different divisor
> than the first call?  (That seems like an unfortunate problem in our
> implementation, if so).

Unfortunately yes. Because we want the divided rate to be lower or equal
to the expected one, I round up the div each time the div_64() produces a
reminder. Thus calling bcm2835_clock_choose_div() with
bcm2835_clock_rate_from_divisor(bcm2835_clock_choose_div()) will still
likely see a reminder from div_64().

> 
> I'd be willing to go along with this, but if so I'd like a comment
> explaining why we aren't setting the field that we should pretty
> obviously be setting.

I can either put a comment here explaining why we do not update
req->rate or do as the patch attached at the end.

This patch adds an argument to bcm2835_clock_choose_div() to switch on or
off the div round up. Then bcm2835_clock_determine_rate() could choose
the appropriate divisor that produces the highest lower rate while
bcm2835_clock_set_rate() can actually set the divisor which will remain
the same.

On second though I prefer the second solution. What do you think ?

Thanks.

Best Regards,

-- 
Remi

-->8--
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 08ae4f6..1b0803c 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1158,7 +1158,8 @@ static int bcm2835_clock_is_on(struct clk_hw *hw)

 static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
unsigned long rate,
-   unsigned long parent_rate)
+   unsigned long parent_rate,
+   int ro

Re: [PATCH v2 2/3] clk: bcm2835: Support for clock parent selection

2015-12-04 Thread Remi Pommarel
On Thu, Dec 03, 2015 at 04:37:07PM -0800, Eric Anholt wrote:
> Remi Pommarel <r...@triplefau.lt> writes:
> 
> > On Wed, Nov 18, 2015 at 10:30:17AM -0800, Eric Anholt wrote:
> >
> > [...]
> >
> >> > +static int bcm2835_clock_determine_rate(struct clk_hw *hw,
> >> > +struct clk_rate_request *req)
> >> > +{
> >> > +struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
> >> > +struct clk_hw *parent, *best_parent = NULL;
> >> > +struct clk_rate_request parent_req;
> >> > +unsigned long rate, best_rate = 0;
> >> > +unsigned long prate, best_prate = 0;
> >> > +size_t i;
> >> > +u32 div;
> >> > +
> >> > +/*
> >> > + * Select parent clock that results in the closest but lower 
> >> > rate
> >> > + */
> >> > +for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
> >> > +parent = clk_hw_get_parent_by_index(hw, i);
> >> > +if (!parent)
> >> > +continue;
> >> > +parent_req = *req;
> >> 
> >> parent_req appears dead, so it should be removed.
> >
> > Yes, will do thanks.
> >
> >> > +prate = clk_hw_get_rate(parent);
> >> > +div = bcm2835_clock_choose_div(hw, req->rate, prate);
> >> > +rate = bcm2835_clock_rate_from_divisor(clock, prate, 
> >> > div);
> >> > +if (rate > best_rate && rate <= req->rate) {
> >> > +best_parent = parent;
> >> > +best_prate = prate;
> >> > +best_rate = rate;
> >> > +}
> >> > +}
> >> > +
> >> > +if (!best_parent)
> >> > +return -EINVAL;
> >> > +
> >> > +req->best_parent_hw = best_parent;
> >> > +req->best_parent_rate = best_prate;
> >> 
> >> I think you're supposed to req->rate = best_rate, here, too.  With these
> >> two fixes,
> >
> > I did not set req->rate to best_rate in order to avoid rounding down
> > twice the actual clock rate.
> >
> > Indeed with patch 1 from this patchset bcm2835_clock_choose_div()
> > chooses a divisor that produces a rate lower or equal to the requested
> > one. As we call bcm2835_clock_choose_div() twice when using
> > clk_set_rate() (once with ->determine_rate() and once with ->set_rate()),
> > if I set req->rate in bcm2835_clock_determine_rate to the rounded down
> > one, the final rate will likely be again rounded down in
> > bcm2835_clock_set_rate().
> 
> If we pass bcm2835_clock_rate_from_divisor(bcm2835_clock_choose_div()),
> to bcm2835_clock_choose_div(), will it actually give a different divisor
> than the first call?  (That seems like an unfortunate problem in our
> implementation, if so).

Unfortunately yes. Because we want the divided rate to be lower or equal
to the expected one, I round up the div each time the div_64() produces a
reminder. Thus calling bcm2835_clock_choose_div() with
bcm2835_clock_rate_from_divisor(bcm2835_clock_choose_div()) will still
likely see a reminder from div_64().

> 
> I'd be willing to go along with this, but if so I'd like a comment
> explaining why we aren't setting the field that we should pretty
> obviously be setting.

I can either put a comment here explaining why we do not update
req->rate or do as the patch attached at the end.

This patch adds an argument to bcm2835_clock_choose_div() to switch on or
off the div round up. Then bcm2835_clock_determine_rate() could choose
the appropriate divisor that produces the highest lower rate while
bcm2835_clock_set_rate() can actually set the divisor which will remain
the same.

On second though I prefer the second solution. What do you think ?

Thanks.

Best Regards,

-- 
Remi

-->8--
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 08ae4f6..1b0803c 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1158,7 +1158,8 @@ static int bcm2835_clock_is_on(struct clk_hw *hw)

 static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
unsigned long rate,
-   unsigned long parent_rate)
+   unsigned long parent_rate,
+

Re: [PATCH v2 1/3] clk: bcm2835: Always round up clock divisor

2015-12-02 Thread Remi Pommarel
Hi Eric

On Wed, Nov 18, 2015 at 07:11:41PM -0100, Remi Pommarel wrote:
> On Wed, Nov 18, 2015 at 10:25:45AM -0800, Eric Anholt wrote:
> > Remi Pommarel  writes:
> > 
> > > Make bcm2835_clock_choose_div always round up the chosen MASH divisor so 
> > > that
> > > the resulting average rate will not be higher than the requested one.
> > >
> > > Signed-off-by: Remi Pommarel 
> > > ---
> > >  drivers/clk/bcm/clk-bcm2835.c | 15 ---
> > >  1 file changed, 8 insertions(+), 7 deletions(-)
> > >
> > > diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
> > > index 39bf582..1237716 100644
> > > --- a/drivers/clk/bcm/clk-bcm2835.c
> > > +++ b/drivers/clk/bcm/clk-bcm2835.c
> > > @@ -1152,18 +1152,19 @@ static u32 bcm2835_clock_choose_div(struct clk_hw 
> > > *hw,
> > >  {
> > >   struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
> > >   const struct bcm2835_clock_data *data = clock->data;
> > > - u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
> > > + u32 unused_frac_mask =
> > > + GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
> > >   u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
> > > + u64 rem;
> > >   u32 div;
> > >  
> > > - do_div(temp, rate);
> > > + rem = do_div(temp, rate);
> > >   div = temp;
> > >  
> > > - /* Round and mask off the unused bits */
> > > - if (unused_frac_mask != 0) {
> > > - div += unused_frac_mask >> 1;
> > > - div &= ~unused_frac_mask;
> > > - }
> > > + /* Round up and mask off the unused bits */
> > > + if ((div & unused_frac_mask) != 0 || rem != 0)
> > > + div += unused_frac_mask + 1;
> > > + div &= ~unused_frac_mask;
> > 
> > Suppose we've got 8 of our 12 frac bits populated.  You've added a ">>
> > 1" to the unused_frac_mask, so it's only 0x7 instead of 0xf.  When you
> > say "round up", you add 0x8 (the high bit of the unused mask") then and
> > with ~0x7.  If you started with 0x1 in the low bits of div, you'd end up
> > with 0x8, so you've set an unused bit instead of actually rounding up.
> > 
> > Did my logic work, here?  I think you just want to drop the ">>1" in
> > unused_frac_mask.
> 
> I don't think so.
> 
> If we have 8 of our 12 frac bits populated GENMASK(12 - 8, 0) will be 0x1f
> because GENMASK(4, 0) generates a mask from bit at position 0 to bit at
> position 4 inclusively (which is the fifth bit). So GENMASK(4, 0) >> 1 will
> be 0xf which is what we want here.

Does my logic seems sensible to you or am I missing something ? I just
want to be sure we agree before I send another version for this
patchset.

Thanks.

Best Regards

-- 
Remi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2 1/3] clk: bcm2835: Always round up clock divisor

2015-12-02 Thread Remi Pommarel
Hi Eric

On Wed, Nov 18, 2015 at 07:11:41PM -0100, Remi Pommarel wrote:
> On Wed, Nov 18, 2015 at 10:25:45AM -0800, Eric Anholt wrote:
> > Remi Pommarel <r...@triplefau.lt> writes:
> > 
> > > Make bcm2835_clock_choose_div always round up the chosen MASH divisor so 
> > > that
> > > the resulting average rate will not be higher than the requested one.
> > >
> > > Signed-off-by: Remi Pommarel <r...@triplefau.lt>
> > > ---
> > >  drivers/clk/bcm/clk-bcm2835.c | 15 ---
> > >  1 file changed, 8 insertions(+), 7 deletions(-)
> > >
> > > diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
> > > index 39bf582..1237716 100644
> > > --- a/drivers/clk/bcm/clk-bcm2835.c
> > > +++ b/drivers/clk/bcm/clk-bcm2835.c
> > > @@ -1152,18 +1152,19 @@ static u32 bcm2835_clock_choose_div(struct clk_hw 
> > > *hw,
> > >  {
> > >   struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
> > >   const struct bcm2835_clock_data *data = clock->data;
> > > - u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
> > > + u32 unused_frac_mask =
> > > + GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
> > >   u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
> > > + u64 rem;
> > >   u32 div;
> > >  
> > > - do_div(temp, rate);
> > > + rem = do_div(temp, rate);
> > >   div = temp;
> > >  
> > > - /* Round and mask off the unused bits */
> > > - if (unused_frac_mask != 0) {
> > > - div += unused_frac_mask >> 1;
> > > - div &= ~unused_frac_mask;
> > > - }
> > > + /* Round up and mask off the unused bits */
> > > + if ((div & unused_frac_mask) != 0 || rem != 0)
> > > + div += unused_frac_mask + 1;
> > > + div &= ~unused_frac_mask;
> > 
> > Suppose we've got 8 of our 12 frac bits populated.  You've added a ">>
> > 1" to the unused_frac_mask, so it's only 0x7 instead of 0xf.  When you
> > say "round up", you add 0x8 (the high bit of the unused mask") then and
> > with ~0x7.  If you started with 0x1 in the low bits of div, you'd end up
> > with 0x8, so you've set an unused bit instead of actually rounding up.
> > 
> > Did my logic work, here?  I think you just want to drop the ">>1" in
> > unused_frac_mask.
> 
> I don't think so.
> 
> If we have 8 of our 12 frac bits populated GENMASK(12 - 8, 0) will be 0x1f
> because GENMASK(4, 0) generates a mask from bit at position 0 to bit at
> position 4 inclusively (which is the fifth bit). So GENMASK(4, 0) >> 1 will
> be 0xf which is what we want here.

Does my logic seems sensible to you or am I missing something ? I just
want to be sure we agree before I send another version for this
patchset.

Thanks.

Best Regards

-- 
Remi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2 0/3] Add PWM clock support for bcm2835

2015-11-29 Thread Remi Pommarel
On Sun, Nov 29, 2015 at 10:22:40PM +0100, Stefan Wahren wrote:
> Hi Remi,
> 
> Am 29.11.2015 um 01:31 schrieb Remi Pommarel:
> >Hi Stefan,
> >
> >On Sat, Nov 28, 2015 at 09:52:07PM +0100, Stefan Wahren wrote:
> >>i applied the series including the devicetree modification, but it
> >>doesn't work for me.
> >>
> >>First of all i get an ugly division by zero warning from the pwm
> >>driver. The pwm driver still assume a fixed clock and doesn't handle
> >>the error cases of clk_get_rate(). I attached a patch at the end.
> >
> >Yes the devicetree patch from patchset version one does not work with
> >this version.
> 
> thanks. I successfully tested the pwm with the led pwm driver.
> 

Good news, thank you.

> >I haven't sent the modified devicetree because Eric said
> >it is better to send it in a separate patchset. If you want to test it I
> >attached the working devicetree patch at the end.
> 
> I don't think that he said that. He wanted you to send the
> devicetree changes as a separate patch. So it should be okay if it's
> part of the same patchset.
> 

I could have misunderstood him, sorry about that. I will send a
devicetree separated patch with the next version if Eric agrees with the
GENMASK logic used in my first patch.

Best Regards,

-- 
Remi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2 0/3] Add PWM clock support for bcm2835

2015-11-29 Thread Remi Pommarel
On Sun, Nov 29, 2015 at 10:22:40PM +0100, Stefan Wahren wrote:
> Hi Remi,
> 
> Am 29.11.2015 um 01:31 schrieb Remi Pommarel:
> >Hi Stefan,
> >
> >On Sat, Nov 28, 2015 at 09:52:07PM +0100, Stefan Wahren wrote:
> >>i applied the series including the devicetree modification, but it
> >>doesn't work for me.
> >>
> >>First of all i get an ugly division by zero warning from the pwm
> >>driver. The pwm driver still assume a fixed clock and doesn't handle
> >>the error cases of clk_get_rate(). I attached a patch at the end.
> >
> >Yes the devicetree patch from patchset version one does not work with
> >this version.
> 
> thanks. I successfully tested the pwm with the led pwm driver.
> 

Good news, thank you.

> >I haven't sent the modified devicetree because Eric said
> >it is better to send it in a separate patchset. If you want to test it I
> >attached the working devicetree patch at the end.
> 
> I don't think that he said that. He wanted you to send the
> devicetree changes as a separate patch. So it should be okay if it's
> part of the same patchset.
> 

I could have misunderstood him, sorry about that. I will send a
devicetree separated patch with the next version if Eric agrees with the
GENMASK logic used in my first patch.

Best Regards,

-- 
Remi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2 0/3] Add PWM clock support for bcm2835

2015-11-28 Thread Remi Pommarel
Hi Stefan,

On Sat, Nov 28, 2015 at 09:52:07PM +0100, Stefan Wahren wrote:
> i applied the series including the devicetree modification, but it
> doesn't work for me.
> 
> First of all i get an ugly division by zero warning from the pwm
> driver. The pwm driver still assume a fixed clock and doesn't handle
> the error cases of clk_get_rate(). I attached a patch at the end.

Yes the devicetree patch from patchset version one does not work with
this version. I haven't sent the modified devicetree because Eric said
it is better to send it in a separate patchset. If you want to test it I
attached the working devicetree patch at the end.

But, yes, that would be nice if pwm driver was protected from this
division by zero.

> 
> The reason in my case why clk_get_rate() returns zero is that the
> pwm clock is orphan ( pwm is listed under
> /sys/kernel/debug/clk_orphan_summary ).
> 
> My suspicion is it has something to do with the clock manager driver.
> The bcm2835_clock_per_parents contains only 8 entries. But according to
> BCM2835-ARM-Peripherals.pdf [1] CM_GP0CTL SRC page 107 has 16
> entries. The upper 8 entries are all mapped to GND. It looks to me
> that the driver doesn't take care of this and so the pwm clock isn't
> able to determine it's parent.
> 

In fact, default parent for pwm after boot up is GND (CM_GP0CTL SRC ==
0). Which means that the default pwm clock rate is 0. The clock appears
to be orphan because in the bcm2835 clock driver, the GND clock is not
registered.

So, IMHO, we have to set the default pwm rate from the devicetree, using
assigned-clock-rates. That what does the following dts patch.

This patch also set the gpio pin 18 to proper alternate function in order
to be able to get pwm output from this gpio.

Thanks

-- 
Remi

-->8--
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts 
b/arch/arm/boot/dts/bcm2835-rpi-b.dts
index ff6b2d1..478aa79 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
@@ -13,5 +13,10 @@
 };
 
  {
-   pinctrl-0 = <  >;
+   pinctrl-0 = <   >;
+
+   gpiopwm: pwm {
+   brcm,pins = <18>;
+   brcm,function = ;
+   };
 };
diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi 
b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index 3572f03..55801e0 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -60,3 +60,7 @@
status = "okay";
bus-width = <4>;
 };
+
+ {
+   status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
index aef64de..567bd35 100644
--- a/arch/arm/boot/dts/bcm2835.dtsi
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -149,6 +149,15 @@
status = "disabled";
};
 
+   pwm: pwm@7e20c000 {
+   compatible = "brcm,bcm2835-pwm";
+   reg = <0x7e20c000 0x28>;
+   clocks = < BCM2835_CLOCK_PWM>;
+   assigned-clocks = < BCM2835_CLOCK_PWM>;
+   assigned-clock-rates = <960>;
+   status = "disabled";
+   };
+
sdhci: sdhci@7e30 {
compatible = "brcm,bcm2835-sdhci";
reg = <0x7e30 0x100>;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2 0/3] Add PWM clock support for bcm2835

2015-11-28 Thread Remi Pommarel
Hi Stefan,

On Sat, Nov 28, 2015 at 09:52:07PM +0100, Stefan Wahren wrote:
> i applied the series including the devicetree modification, but it
> doesn't work for me.
> 
> First of all i get an ugly division by zero warning from the pwm
> driver. The pwm driver still assume a fixed clock and doesn't handle
> the error cases of clk_get_rate(). I attached a patch at the end.

Yes the devicetree patch from patchset version one does not work with
this version. I haven't sent the modified devicetree because Eric said
it is better to send it in a separate patchset. If you want to test it I
attached the working devicetree patch at the end.

But, yes, that would be nice if pwm driver was protected from this
division by zero.

> 
> The reason in my case why clk_get_rate() returns zero is that the
> pwm clock is orphan ( pwm is listed under
> /sys/kernel/debug/clk_orphan_summary ).
> 
> My suspicion is it has something to do with the clock manager driver.
> The bcm2835_clock_per_parents contains only 8 entries. But according to
> BCM2835-ARM-Peripherals.pdf [1] CM_GP0CTL SRC page 107 has 16
> entries. The upper 8 entries are all mapped to GND. It looks to me
> that the driver doesn't take care of this and so the pwm clock isn't
> able to determine it's parent.
> 

In fact, default parent for pwm after boot up is GND (CM_GP0CTL SRC ==
0). Which means that the default pwm clock rate is 0. The clock appears
to be orphan because in the bcm2835 clock driver, the GND clock is not
registered.

So, IMHO, we have to set the default pwm rate from the devicetree, using
assigned-clock-rates. That what does the following dts patch.

This patch also set the gpio pin 18 to proper alternate function in order
to be able to get pwm output from this gpio.

Thanks

-- 
Remi

-->8--
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts 
b/arch/arm/boot/dts/bcm2835-rpi-b.dts
index ff6b2d1..478aa79 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
@@ -13,5 +13,10 @@
 };
 
  {
-   pinctrl-0 = <  >;
+   pinctrl-0 = <   >;
+
+   gpiopwm: pwm {
+   brcm,pins = <18>;
+   brcm,function = ;
+   };
 };
diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi 
b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index 3572f03..55801e0 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -60,3 +60,7 @@
status = "okay";
bus-width = <4>;
 };
+
+ {
+   status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
index aef64de..567bd35 100644
--- a/arch/arm/boot/dts/bcm2835.dtsi
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -149,6 +149,15 @@
status = "disabled";
};
 
+   pwm: pwm@7e20c000 {
+   compatible = "brcm,bcm2835-pwm";
+   reg = <0x7e20c000 0x28>;
+   clocks = < BCM2835_CLOCK_PWM>;
+   assigned-clocks = < BCM2835_CLOCK_PWM>;
+   assigned-clock-rates = <960>;
+   status = "disabled";
+   };
+
sdhci: sdhci@7e30 {
compatible = "brcm,bcm2835-sdhci";
reg = <0x7e30 0x100>;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2 3/3] clk: bcm2835: Add PWM clock support

2015-11-18 Thread Remi Pommarel
On Wed, Nov 18, 2015 at 10:32:55AM -0800, Eric Anholt wrote:
> Remi Pommarel  writes:
> 
> > Register the pwm clock for bcm2835.
> >
> > Signed-off-by: Remi Pommarel 
> > ---
> >  drivers/clk/bcm/clk-bcm2835.c   | 14 ++
> >  include/dt-bindings/clock/bcm2835.h |  3 ++-
> >  2 files changed, 16 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
> > index 2b01a53..db378f3 100644
> > --- a/drivers/clk/bcm/clk-bcm2835.c
> > +++ b/drivers/clk/bcm/clk-bcm2835.c
> > @@ -39,6 +39,7 @@
> >  
> >  #include 
> >  #include 
> > +#include 
> 
> Stray new #include?  With that dropped (assuming it's unnecessary),

Good catch, will remove this. Thanks !

> 
> Reviewed-by: Eric Anholt 
> 

-- 
Remi Pommarel
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2 2/3] clk: bcm2835: Support for clock parent selection

2015-11-18 Thread Remi Pommarel
On Wed, Nov 18, 2015 at 10:30:17AM -0800, Eric Anholt wrote:

[...]

> > +static int bcm2835_clock_determine_rate(struct clk_hw *hw,
> > +   struct clk_rate_request *req)
> > +{
> > +   struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
> > +   struct clk_hw *parent, *best_parent = NULL;
> > +   struct clk_rate_request parent_req;
> > +   unsigned long rate, best_rate = 0;
> > +   unsigned long prate, best_prate = 0;
> > +   size_t i;
> > +   u32 div;
> > +
> > +   /*
> > +* Select parent clock that results in the closest but lower rate
> > +*/
> > +   for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
> > +   parent = clk_hw_get_parent_by_index(hw, i);
> > +   if (!parent)
> > +   continue;
> > +   parent_req = *req;
> 
> parent_req appears dead, so it should be removed.

Yes, will do thanks.

> > +   prate = clk_hw_get_rate(parent);
> > +   div = bcm2835_clock_choose_div(hw, req->rate, prate);
> > +   rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
> > +   if (rate > best_rate && rate <= req->rate) {
> > +   best_parent = parent;
> > +   best_prate = prate;
> > +   best_rate = rate;
> > +   }
> > +   }
> > +
> > +   if (!best_parent)
> > +   return -EINVAL;
> > +
> > +   req->best_parent_hw = best_parent;
> > +   req->best_parent_rate = best_prate;
> 
> I think you're supposed to req->rate = best_rate, here, too.  With these
> two fixes,

I did not set req->rate to best_rate in order to avoid rounding down
twice the actual clock rate.

Indeed with patch 1 from this patchset bcm2835_clock_choose_div()
chooses a divisor that produces a rate lower or equal to the requested
one. As we call bcm2835_clock_choose_div() twice when using
clk_set_rate() (once with ->determine_rate() and once with ->set_rate()),
if I set req->rate in bcm2835_clock_determine_rate to the rounded down
one, the final rate will likely be again rounded down in
bcm2835_clock_set_rate().

Thanks,

-- 
Rémi Pommarel
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2 1/3] clk: bcm2835: Always round up clock divisor

2015-11-18 Thread Remi Pommarel
Hi,

On Wed, Nov 18, 2015 at 10:25:45AM -0800, Eric Anholt wrote:
> Remi Pommarel  writes:
> 
> > Make bcm2835_clock_choose_div always round up the chosen MASH divisor so 
> > that
> > the resulting average rate will not be higher than the requested one.
> >
> > Signed-off-by: Remi Pommarel 
> > ---
> >  drivers/clk/bcm/clk-bcm2835.c | 15 ---
> >  1 file changed, 8 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
> > index 39bf582..1237716 100644
> > --- a/drivers/clk/bcm/clk-bcm2835.c
> > +++ b/drivers/clk/bcm/clk-bcm2835.c
> > @@ -1152,18 +1152,19 @@ static u32 bcm2835_clock_choose_div(struct clk_hw 
> > *hw,
> >  {
> > struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
> > const struct bcm2835_clock_data *data = clock->data;
> > -   u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
> > +   u32 unused_frac_mask =
> > +   GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
> > u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
> > +   u64 rem;
> > u32 div;
> >  
> > -   do_div(temp, rate);
> > +   rem = do_div(temp, rate);
> > div = temp;
> >  
> > -   /* Round and mask off the unused bits */
> > -   if (unused_frac_mask != 0) {
> > -   div += unused_frac_mask >> 1;
> > -   div &= ~unused_frac_mask;
> > -   }
> > +   /* Round up and mask off the unused bits */
> > +   if ((div & unused_frac_mask) != 0 || rem != 0)
> > +   div += unused_frac_mask + 1;
> > +   div &= ~unused_frac_mask;
> 
> Suppose we've got 8 of our 12 frac bits populated.  You've added a ">>
> 1" to the unused_frac_mask, so it's only 0x7 instead of 0xf.  When you
> say "round up", you add 0x8 (the high bit of the unused mask") then and
> with ~0x7.  If you started with 0x1 in the low bits of div, you'd end up
> with 0x8, so you've set an unused bit instead of actually rounding up.
> 
> Did my logic work, here?  I think you just want to drop the ">>1" in
> unused_frac_mask.

I don't think so.

If we have 8 of our 12 frac bits populated GENMASK(12 - 8, 0) will be 0x1f
because GENMASK(4, 0) generates a mask from bit at position 0 to bit at
position 4 inclusively (which is the fifth bit). So GENMASK(4, 0) >> 1 will
be 0xf which is what we want here.

Thanks,

-- 
Remi Pommarel
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2 1/3] clk: bcm2835: Always round up clock divisor

2015-11-18 Thread Remi Pommarel
Hi,

On Wed, Nov 18, 2015 at 10:25:45AM -0800, Eric Anholt wrote:
> Remi Pommarel <r...@triplefau.lt> writes:
> 
> > Make bcm2835_clock_choose_div always round up the chosen MASH divisor so 
> > that
> > the resulting average rate will not be higher than the requested one.
> >
> > Signed-off-by: Remi Pommarel <r...@triplefau.lt>
> > ---
> >  drivers/clk/bcm/clk-bcm2835.c | 15 ---
> >  1 file changed, 8 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
> > index 39bf582..1237716 100644
> > --- a/drivers/clk/bcm/clk-bcm2835.c
> > +++ b/drivers/clk/bcm/clk-bcm2835.c
> > @@ -1152,18 +1152,19 @@ static u32 bcm2835_clock_choose_div(struct clk_hw 
> > *hw,
> >  {
> > struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
> > const struct bcm2835_clock_data *data = clock->data;
> > -   u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
> > +   u32 unused_frac_mask =
> > +   GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
> > u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
> > +   u64 rem;
> > u32 div;
> >  
> > -   do_div(temp, rate);
> > +   rem = do_div(temp, rate);
> > div = temp;
> >  
> > -   /* Round and mask off the unused bits */
> > -   if (unused_frac_mask != 0) {
> > -   div += unused_frac_mask >> 1;
> > -   div &= ~unused_frac_mask;
> > -   }
> > +   /* Round up and mask off the unused bits */
> > +   if ((div & unused_frac_mask) != 0 || rem != 0)
> > +   div += unused_frac_mask + 1;
> > +   div &= ~unused_frac_mask;
> 
> Suppose we've got 8 of our 12 frac bits populated.  You've added a ">>
> 1" to the unused_frac_mask, so it's only 0x7 instead of 0xf.  When you
> say "round up", you add 0x8 (the high bit of the unused mask") then and
> with ~0x7.  If you started with 0x1 in the low bits of div, you'd end up
> with 0x8, so you've set an unused bit instead of actually rounding up.
> 
> Did my logic work, here?  I think you just want to drop the ">>1" in
> unused_frac_mask.

I don't think so.

If we have 8 of our 12 frac bits populated GENMASK(12 - 8, 0) will be 0x1f
because GENMASK(4, 0) generates a mask from bit at position 0 to bit at
position 4 inclusively (which is the fifth bit). So GENMASK(4, 0) >> 1 will
be 0xf which is what we want here.

Thanks,

-- 
Remi Pommarel
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2 2/3] clk: bcm2835: Support for clock parent selection

2015-11-18 Thread Remi Pommarel
On Wed, Nov 18, 2015 at 10:30:17AM -0800, Eric Anholt wrote:

[...]

> > +static int bcm2835_clock_determine_rate(struct clk_hw *hw,
> > +   struct clk_rate_request *req)
> > +{
> > +   struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
> > +   struct clk_hw *parent, *best_parent = NULL;
> > +   struct clk_rate_request parent_req;
> > +   unsigned long rate, best_rate = 0;
> > +   unsigned long prate, best_prate = 0;
> > +   size_t i;
> > +   u32 div;
> > +
> > +   /*
> > +* Select parent clock that results in the closest but lower rate
> > +*/
> > +   for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
> > +   parent = clk_hw_get_parent_by_index(hw, i);
> > +   if (!parent)
> > +   continue;
> > +   parent_req = *req;
> 
> parent_req appears dead, so it should be removed.

Yes, will do thanks.

> > +   prate = clk_hw_get_rate(parent);
> > +   div = bcm2835_clock_choose_div(hw, req->rate, prate);
> > +   rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
> > +   if (rate > best_rate && rate <= req->rate) {
> > +   best_parent = parent;
> > +   best_prate = prate;
> > +   best_rate = rate;
> > +   }
> > +   }
> > +
> > +   if (!best_parent)
> > +   return -EINVAL;
> > +
> > +   req->best_parent_hw = best_parent;
> > +   req->best_parent_rate = best_prate;
> 
> I think you're supposed to req->rate = best_rate, here, too.  With these
> two fixes,

I did not set req->rate to best_rate in order to avoid rounding down
twice the actual clock rate.

Indeed with patch 1 from this patchset bcm2835_clock_choose_div()
chooses a divisor that produces a rate lower or equal to the requested
one. As we call bcm2835_clock_choose_div() twice when using
clk_set_rate() (once with ->determine_rate() and once with ->set_rate()),
if I set req->rate in bcm2835_clock_determine_rate to the rounded down
one, the final rate will likely be again rounded down in
bcm2835_clock_set_rate().

Thanks,

-- 
Rémi Pommarel
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2 3/3] clk: bcm2835: Add PWM clock support

2015-11-18 Thread Remi Pommarel
On Wed, Nov 18, 2015 at 10:32:55AM -0800, Eric Anholt wrote:
> Remi Pommarel <r...@triplefau.lt> writes:
> 
> > Register the pwm clock for bcm2835.
> >
> > Signed-off-by: Remi Pommarel <r...@triplefau.lt>
> > ---
> >  drivers/clk/bcm/clk-bcm2835.c   | 14 ++
> >  include/dt-bindings/clock/bcm2835.h |  3 ++-
> >  2 files changed, 16 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
> > index 2b01a53..db378f3 100644
> > --- a/drivers/clk/bcm/clk-bcm2835.c
> > +++ b/drivers/clk/bcm/clk-bcm2835.c
> > @@ -39,6 +39,7 @@
> >  
> >  #include 
> >  #include 
> > +#include 
> 
> Stray new #include?  With that dropped (assuming it's unnecessary),

Good catch, will remove this. Thanks !

> 
> Reviewed-by: Eric Anholt <e...@anholt.net>
> 

-- 
Remi Pommarel
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2 3/3] clk: bcm2835: Add PWM clock support

2015-11-11 Thread Remi Pommarel
Register the pwm clock for bcm2835.

Signed-off-by: Remi Pommarel 
---
 drivers/clk/bcm/clk-bcm2835.c   | 14 ++
 include/dt-bindings/clock/bcm2835.h |  3 ++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 2b01a53..db378f3 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -39,6 +39,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -807,6 +808,16 @@ static const struct bcm2835_clock_data 
bcm2835_clock_emmc_data = {
.frac_bits = 8,
 };
 
+static const struct bcm2835_clock_data bcm2835_clock_pwm_data = {
+   .name = "pwm",
+   .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
+   .parents = bcm2835_clock_per_parents,
+   .ctl_reg = CM_PWMCTL,
+   .div_reg = CM_PWMDIV,
+   .int_bits = 12,
+   .frac_bits = 12,
+};
+
 struct bcm2835_pll {
struct clk_hw hw;
struct bcm2835_cprman *cprman;
@@ -1583,6 +1594,9 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
  cprman->regs + CM_PERIICTL, CM_GATE_BIT,
  0, >regs_lock);
 
+   clks[BCM2835_CLOCK_PWM] =
+   bcm2835_register_clock(cprman, _clock_pwm_data);
+
return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
   >onecell);
 }
diff --git a/include/dt-bindings/clock/bcm2835.h 
b/include/dt-bindings/clock/bcm2835.h
index d323efa..61f1d20 100644
--- a/include/dt-bindings/clock/bcm2835.h
+++ b/include/dt-bindings/clock/bcm2835.h
@@ -43,5 +43,6 @@
 #define BCM2835_CLOCK_TSENS27
 #define BCM2835_CLOCK_EMMC 28
 #define BCM2835_CLOCK_PERI_IMAGE   29
+#define BCM2835_CLOCK_PWM  30
 
-#define BCM2835_CLOCK_COUNT30
+#define BCM2835_CLOCK_COUNT31
-- 
2.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2 1/3] clk: bcm2835: Always round up clock divisor

2015-11-11 Thread Remi Pommarel
Make bcm2835_clock_choose_div always round up the chosen MASH divisor so that
the resulting average rate will not be higher than the requested one.

Signed-off-by: Remi Pommarel 
---
 drivers/clk/bcm/clk-bcm2835.c | 15 ---
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 39bf582..1237716 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1152,18 +1152,19 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
 {
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
const struct bcm2835_clock_data *data = clock->data;
-   u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
+   u32 unused_frac_mask =
+   GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
+   u64 rem;
u32 div;
 
-   do_div(temp, rate);
+   rem = do_div(temp, rate);
div = temp;
 
-   /* Round and mask off the unused bits */
-   if (unused_frac_mask != 0) {
-   div += unused_frac_mask >> 1;
-   div &= ~unused_frac_mask;
-   }
+   /* Round up and mask off the unused bits */
+   if ((div & unused_frac_mask) != 0 || rem != 0)
+   div += unused_frac_mask + 1;
+   div &= ~unused_frac_mask;
 
/* Clamp to the limits. */
div = max(div, unused_frac_mask + 1);
-- 
2.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2 0/3] Add PWM clock support for bcm2835

2015-11-11 Thread Remi Pommarel
Hi,

This patchset adds support for pwm clock. At boot, this clock does not have a
default parent nor a default rate set. Thus we should be able to change its
parent to get this clock working. The current clock implementation is using a
mux to select the parent, but these clocks need to add a password (0x5a) in
higher register bits when changing parent. So a generic mux cannot be used
here.

The two first patches fix the clock parent selection, while the second one is
actually adding the pwm clock registration.

Changes since v1:
- determine_rate now based its parent selection upon divided rate
  instead of the parent one
- bcm2835_clock_choose_div has been modified to produce an avarage rate
  lower or equal to the requested one
- devicetree modifications have removed to be send in another patch

Remi Pommarel (3):
  clk: bcm2835: Always round up clock divisor
  clk: bcm2835: Support for clock parent selection
  clk: bcm2835: Add PWM clock support

 drivers/clk/bcm/clk-bcm2835.c   | 151 +++-
 include/dt-bindings/clock/bcm2835.h |   3 +-
 2 files changed, 101 insertions(+), 53 deletions(-)

-- 
2.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


  1   2   >