Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 2/9] clk: stm32f4: Add PLL_I2S & PLL_SAI for STM32F429/469 boards
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>

From: Gabriel Fernandez <gabriel.fernandez@st.com>

This patch introduces PLL_I2S and PLL_SAI.
Vco clock of these PLLs can be modify by DT (only n multiplicator,
m divider is still fixed by the boot-loader).
Each PLL has 3 dividers. PLL should be off when we modify the rate.

Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
Acked-by: Rob Herring <robh@kernel.org>
---
 drivers/clk/clk-stm32f4.c | 351 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 334 insertions(+), 17 deletions(-)

diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index 5eb05db..c2b62cc 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -28,6 +28,14 @@
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
 
+/*
+ * Include list of clocks wich are not derived from system clock (SYSCLOCK)
+ * The index of these clocks is the secondary index of DT bindings
+ *
+ */
+#include <dt-bindings/clock/stm32f4-clock.h>
+
+#define STM32F4_RCC_CR			0x00
 #define STM32F4_RCC_PLLCFGR		0x04
 #define STM32F4_RCC_CFGR		0x08
 #define STM32F4_RCC_AHB1ENR		0x30
@@ -37,6 +45,8 @@
 #define STM32F4_RCC_APB2ENR		0x44
 #define STM32F4_RCC_BDCR		0x70
 #define STM32F4_RCC_CSR			0x74
+#define STM32F4_RCC_PLLI2SCFGR		0x84
+#define STM32F4_RCC_PLLSAICFGR		0x88
 
 struct stm32f4_gate_data {
 	u8	offset;
@@ -208,8 +218,6 @@ struct stm32f4_gate_data {
 	{ STM32F4_RCC_APB2ENR, 26,	"ltdc",		"apb2_div" },
 };
 
-enum { SYSTICK, FCLK, CLK_LSI, CLK_LSE, CLK_HSE_RTC, CLK_RTC, END_PRIMARY_CLK };
-
 /*
  * This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx
  * have gate bits associated with them. Its combined hweight is 71.
@@ -324,23 +332,312 @@ static struct clk *clk_register_apb_mul(struct device *dev, const char *name,
 	return clk;
 }
 
-/*
- * Decode current PLL state and (statically) model the state we inherit from
- * the bootloader.
- */
-static void stm32f4_rcc_register_pll(const char *hse_clk, const char *hsi_clk)
+enum {
+	PLL,
+	PLL_I2S,
+	PLL_SAI,
+};
+
+static const struct clk_div_table pll_divp_table[] = {
+	{ 0, 2 }, { 1, 4 }, { 2, 6 }, { 3, 8 }, { 0 }
+};
+
+static const struct clk_div_table pll_divr_table[] = {
+	{ 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 }, { 7, 7 }, { 0 }
+};
+
+struct stm32f4_pll {
+	spinlock_t *lock;
+	struct	clk_gate gate;
+	u8 offset;
+	u8 bit_rdy_idx;
+	u8 status;
+	u8 n_start;
+};
+
+#define to_stm32f4_pll(_gate) container_of(_gate, struct stm32f4_pll, gate)
+
+struct stm32f4_vco_data {
+	const char *vco_name;
+	u8 offset;
+	u8 bit_idx;
+	u8 bit_rdy_idx;
+};
+
+static const struct stm32f4_vco_data  vco_data[] = {
+	{ "vco",     STM32F4_RCC_PLLCFGR,    24, 25 },
+	{ "vco-i2s", STM32F4_RCC_PLLI2SCFGR, 26, 27 },
+	{ "vco-sai", STM32F4_RCC_PLLSAICFGR, 28, 29 },
+};
+
+struct stm32f4_div_data {
+	u8 shift;
+	u8 width;
+	u8 flag_div;
+	const struct clk_div_table *div_table;
+};
+
+#define MAX_PLL_DIV 3
+static const struct stm32f4_div_data  div_data[MAX_PLL_DIV] = {
+	{ 16, 2, 0,			pll_divp_table	},
+	{ 24, 4, CLK_DIVIDER_ONE_BASED, NULL		},
+	{ 28, 3, 0,			pll_divr_table	},
+};
+
+struct stm32f4_pll_data {
+	u8 pll_num;
+	u8 n_start;
+	const char *div_name[MAX_PLL_DIV];
+};
+
+static const struct stm32f4_pll_data stm32f429_pll[MAX_PLL_DIV] = {
+	{ PLL,	   192, { "pll", "pll48",    NULL	} },
+	{ PLL_I2S, 192, { NULL,  "plli2s-q", "plli2s-r" } },
+	{ PLL_SAI,  49, { NULL,  "pllsai-q", "pllsai-r" } },
+};
+
+static const struct stm32f4_pll_data stm32f469_pll[MAX_PLL_DIV] = {
+	{ PLL,	   50, { "pll",	     "pll-q",    NULL	    } },
+	{ PLL_I2S, 50, { "plli2s-p", "plli2s-q", "plli2s-r" } },
+	{ PLL_SAI, 50, { "pllsai-p", "pllsai-q", "pllsai-r" } },
+};
+
+static int stm32f4_pll_is_enabled(struct clk_hw *hw)
+{
+	return clk_gate_ops.is_enabled(hw);
+}
+
+static int stm32f4_pll_enable(struct clk_hw *hw)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	struct stm32f4_pll *pll = to_stm32f4_pll(gate);
+	int ret = 0;
+	unsigned long reg;
+
+	ret = clk_gate_ops.enable(hw);
+
+	ret = readl_relaxed_poll_timeout_atomic(base + STM32F4_RCC_CR, reg,
+			reg & (1 << pll->bit_rdy_idx), 0, 10000);
+
+	return ret;
+}
+
+static void stm32f4_pll_disable(struct clk_hw *hw)
+{
+	clk_gate_ops.disable(hw);
+}
+
+static unsigned long stm32f4_pll_recalc(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	struct stm32f4_pll *pll = to_stm32f4_pll(gate);
+	unsigned long n;
+
+	n = (readl(base + pll->offset) >> 6) & 0x1ff;
+
+	return parent_rate * n;
+}
+
+static long stm32f4_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long *prate)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	struct stm32f4_pll *pll = to_stm32f4_pll(gate);
+	unsigned long n;
+
+	n = rate / *prate;
+
+	if (n < pll->n_start)
+		n = pll->n_start;
+	else if (n > 432)
+		n = 432;
+
+	return *prate * n;
+}
+
+static int stm32f4_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	struct stm32f4_pll *pll = to_stm32f4_pll(gate);
+
+	unsigned long n;
+	unsigned long val;
+	int pll_state;
+
+	pll_state = stm32f4_pll_is_enabled(hw);
+
+	if (pll_state)
+		stm32f4_pll_disable(hw);
+
+	n = rate  / parent_rate;
+
+	val = readl(base + pll->offset) & ~(0x1ff << 6);
+
+	writel(val | ((n & 0x1ff) <<  6), base + pll->offset);
+
+	if (pll_state)
+		stm32f4_pll_enable(hw);
+
+	return 0;
+}
+
+static const struct clk_ops stm32f4_pll_gate_ops = {
+	.enable		= stm32f4_pll_enable,
+	.disable	= stm32f4_pll_disable,
+	.is_enabled	= stm32f4_pll_is_enabled,
+	.recalc_rate	= stm32f4_pll_recalc,
+	.round_rate	= stm32f4_pll_round_rate,
+	.set_rate	= stm32f4_pll_set_rate,
+};
+
+struct stm32f4_pll_div {
+	struct clk_divider div;
+	struct clk_hw *hw_pll;
+};
+
+#define to_pll_div_clk(_div) container_of(_div, struct stm32f4_pll_div, div)
+
+static unsigned long stm32f4_pll_div_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	return clk_divider_ops.recalc_rate(hw, parent_rate);
+}
+
+static long stm32f4_pll_div_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	return clk_divider_ops.round_rate(hw, rate, prate);
+}
+
+static int stm32f4_pll_div_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate)
+{
+	int pll_state, ret;
+
+	struct clk_divider *div = to_clk_divider(hw);
+	struct stm32f4_pll_div *pll_div = to_pll_div_clk(div);
+
+	pll_state = stm32f4_pll_is_enabled(pll_div->hw_pll);
+
+	if (pll_state)
+		stm32f4_pll_disable(pll_div->hw_pll);
+
+	ret = clk_divider_ops.set_rate(hw, rate, parent_rate);
+
+	if (pll_state)
+		stm32f4_pll_enable(pll_div->hw_pll);
+
+	return ret;
+}
+
+const struct clk_ops stm32f4_pll_div_ops = {
+	.recalc_rate = stm32f4_pll_div_recalc_rate,
+	.round_rate = stm32f4_pll_div_round_rate,
+	.set_rate = stm32f4_pll_div_set_rate,
+};
+
+static struct clk_hw *clk_register_pll_div(const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags, const struct clk_div_table *table,
+		struct clk_hw *pll_hw, spinlock_t *lock)
 {
-	unsigned long pllcfgr = readl(base + STM32F4_RCC_PLLCFGR);
+	struct stm32f4_pll_div *pll_div;
+	struct clk_hw *hw;
+	struct clk_init_data init;
+	int ret;
+
+	/* allocate the divider */
+	pll_div = kzalloc(sizeof(*pll_div), GFP_KERNEL);
+	if (!pll_div)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &stm32f4_pll_div_ops;
+	init.flags = flags;
+	init.parent_names = (parent_name ? &parent_name : NULL);
+	init.num_parents = (parent_name ? 1 : 0);
+
+	/* struct clk_divider assignments */
+	pll_div->div.reg = reg;
+	pll_div->div.shift = shift;
+	pll_div->div.width = width;
+	pll_div->div.flags = clk_divider_flags;
+	pll_div->div.lock = lock;
+	pll_div->div.table = table;
+	pll_div->div.hw.init = &init;
+
+	pll_div->hw_pll = pll_hw;
+
+	/* register the clock */
+	hw = &pll_div->div.hw;
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
+		kfree(pll_div);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
+
+static struct clk_hw *stm32f4_rcc_register_pll(const char *pllsrc,
+		const struct stm32f4_pll_data *data,  spinlock_t *lock)
+{
+	struct stm32f4_pll *pll;
+	struct clk_init_data init = { NULL };
+	void __iomem *reg;
+	struct clk_hw *pll_hw;
+	int ret;
+	int i;
+	const struct stm32f4_vco_data *vco;
+
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	vco = &vco_data[data->pll_num];
+
+	init.name = vco->vco_name;
+	init.ops = &stm32f4_pll_gate_ops;
+	init.flags = CLK_SET_RATE_GATE;
+	init.parent_names = &pllsrc;
+	init.num_parents = 1;
+
+	pll->gate.lock = lock;
+	pll->gate.reg = base + STM32F4_RCC_CR;
+	pll->gate.bit_idx = vco->bit_idx;
+	pll->gate.hw.init = &init;
+
+	pll->offset = vco->offset;
+	pll->n_start = data->n_start;
+	pll->bit_rdy_idx = vco->bit_rdy_idx;
+	pll->status = (readl(base + STM32F4_RCC_CR) >> vco->bit_idx) & 0x1;
 
-	unsigned long pllm   = pllcfgr & 0x3f;
-	unsigned long plln   = (pllcfgr >> 6) & 0x1ff;
-	unsigned long pllp   = BIT(((pllcfgr >> 16) & 3) + 1);
-	const char   *pllsrc = pllcfgr & BIT(22) ? hse_clk : hsi_clk;
-	unsigned long pllq   = (pllcfgr >> 24) & 0xf;
+	reg = base + pll->offset;
 
-	clk_register_fixed_factor(NULL, "vco", pllsrc, 0, plln, pllm);
-	clk_register_fixed_factor(NULL, "pll", "vco", 0, 1, pllp);
-	clk_register_fixed_factor(NULL, "pll48", "vco", 0, 1, pllq);
+	pll_hw = &pll->gate.hw;
+	ret = clk_hw_register(NULL, pll_hw);
+	if (ret) {
+		kfree(pll);
+		return ERR_PTR(ret);
+	}
+
+	for (i = 0; i < MAX_PLL_DIV; i++)
+		if (data->div_name[i])
+			clk_register_pll_div(data->div_name[i],
+					vco->vco_name,
+					0,
+					reg,
+					div_data[i].shift,
+					div_data[i].width,
+					div_data[i].flag_div,
+					div_data[i].div_table,
+					pll_hw,
+					lock);
+	return pll_hw;
 }
 
 /*
@@ -615,18 +912,21 @@ struct stm32f4_clk_data {
 	const struct stm32f4_gate_data *gates_data;
 	const u64 *gates_map;
 	int gates_num;
+	const struct stm32f4_pll_data *pll_data;
 };
 
 static const struct stm32f4_clk_data stm32f429_clk_data = {
 	.gates_data	= stm32f429_gates,
 	.gates_map	= stm32f42xx_gate_map,
 	.gates_num	= ARRAY_SIZE(stm32f429_gates),
+	.pll_data	= stm32f429_pll,
 };
 
 static const struct stm32f4_clk_data stm32f469_clk_data = {
 	.gates_data	= stm32f469_gates,
 	.gates_map	= stm32f46xx_gate_map,
 	.gates_num	= ARRAY_SIZE(stm32f469_gates),
+	.pll_data	= stm32f469_pll,
 };
 
 static const struct of_device_id stm32f4_of_match[] = {
@@ -647,6 +947,9 @@ static void __init stm32f4_rcc_init(struct device_node *np)
 	int n;
 	const struct of_device_id *match;
 	const struct stm32f4_clk_data *data;
+	unsigned long pllcfgr;
+	const char *pllsrc;
+	unsigned long pllm;
 
 	base = of_iomap(np, 0);
 	if (!base) {
@@ -677,7 +980,21 @@ static void __init stm32f4_rcc_init(struct device_node *np)
 
 	clk_register_fixed_rate_with_accuracy(NULL, "hsi", NULL, 0,
 			16000000, 160000);
-	stm32f4_rcc_register_pll(hse_clk, "hsi");
+	pllcfgr = readl(base + STM32F4_RCC_PLLCFGR);
+	pllsrc = pllcfgr & BIT(22) ? hse_clk : "hsi";
+	pllm = pllcfgr & 0x3f;
+
+	clk_hw_register_fixed_factor(NULL, "vco_in", pllsrc,
+					       0, 1, pllm);
+
+	stm32f4_rcc_register_pll("vco_in", &data->pll_data[0],
+			&stm32f4_clk_lock);
+
+	clks[PLL_VCO_I2S] = stm32f4_rcc_register_pll("vco_in",
+			&data->pll_data[1], &stm32f4_clk_lock);
+
+	clks[PLL_VCO_SAI] = stm32f4_rcc_register_pll("vco_in",
+			&data->pll_data[2], &stm32f4_clk_lock);
 
 	sys_parents[1] = hse_clk;
 	clk_register_mux_table(
-- 
1.9.1

^ permalink raw reply related

* [PATCH v3 3/9] clk: stm32f4: Add post divisor for I2S & SAI PLLs
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>

From: Gabriel Fernandez <gabriel.fernandez@st.com>

This patch adds post dividers of I2S & SAI PLLs.
These dividers are managed by a dedicated register (RCC_DCKCFGR).
The PLL should be off before a set rate.

Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
 drivers/clk/clk-stm32f4.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index c2b62cc..98856ac 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -47,6 +47,7 @@
 #define STM32F4_RCC_CSR			0x74
 #define STM32F4_RCC_PLLI2SCFGR		0x84
 #define STM32F4_RCC_PLLSAICFGR		0x88
+#define STM32F4_RCC_DCKCFGR		0x8c
 
 struct stm32f4_gate_data {
 	u8	offset;
@@ -357,6 +358,18 @@ struct stm32f4_pll {
 
 #define to_stm32f4_pll(_gate) container_of(_gate, struct stm32f4_pll, gate)
 
+struct stm32f4_pll_post_div_data {
+	u8 pll_num;
+	const char *name;
+	const char *parent;
+	u8 flag;
+	u8 offset;
+	u8 shift;
+	u8 width;
+	u8 flag_div;
+	const struct clk_div_table *div_table;
+};
+
 struct stm32f4_vco_data {
 	const char *vco_name;
 	u8 offset;
@@ -370,6 +383,18 @@ struct stm32f4_vco_data {
 	{ "vco-sai", STM32F4_RCC_PLLSAICFGR, 28, 29 },
 };
 
+#define MAX_POST_DIV 3
+static const struct stm32f4_pll_post_div_data  post_div_data[MAX_POST_DIV] = {
+	{ PLL_I2S, "plli2s-q-div", "plli2s-q", CLK_SET_RATE_PARENT,
+		STM32F4_RCC_DCKCFGR, 0, 5, 0, NULL},
+
+	{ PLL_SAI, "pllsai-q-div", "pllsai-q", CLK_SET_RATE_PARENT,
+		STM32F4_RCC_DCKCFGR, 8, 5, 0, NULL },
+
+	{ PLL_SAI, "pllsai-r-div", "pllsai-r", CLK_SET_RATE_PARENT,
+		STM32F4_RCC_DCKCFGR, 16, 2, CLK_DIVIDER_POWER_OF_TWO},
+};
+
 struct stm32f4_div_data {
 	u8 shift;
 	u8 width;
@@ -996,6 +1021,23 @@ static void __init stm32f4_rcc_init(struct device_node *np)
 	clks[PLL_VCO_SAI] = stm32f4_rcc_register_pll("vco_in",
 			&data->pll_data[2], &stm32f4_clk_lock);
 
+	for (n = 0; n < MAX_POST_DIV; n++) {
+		const struct stm32f4_pll_post_div_data *post_div;
+
+		post_div = &post_div_data[n];
+
+		clk_register_pll_div(post_div->name,
+				post_div->parent,
+				post_div->flag,
+				base + post_div->offset,
+				post_div->shift,
+				post_div->width,
+				post_div->flag_div,
+				post_div->div_table,
+				clks[post_div->pll_num],
+				&stm32f4_clk_lock);
+	}
+
 	sys_parents[1] = hse_clk;
 	clk_register_mux_table(
 	    NULL, "sys", sys_parents, ARRAY_SIZE(sys_parents), 0,
-- 
1.9.1

^ permalink raw reply related

* [PATCH v3 4/9] clk: stm32f4: Add lcd-tft clock
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>

From: Gabriel Fernandez <gabriel.fernandez@st.com>

This patch introduces lcd-tft clock for stm32f4 soc.

Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
 drivers/clk/clk-stm32f4.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)

diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index 98856ac..86244fc 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -933,11 +933,42 @@ static struct clk_hw *stm32_register_cclk(struct device *dev, const char *name,
 	"no-clock", "lse", "lsi", "hse-rtc"
 };
 
+static const char *lcd_parent[1] = { "pllsai-r-div" };
+
+struct stm32_aux_clk {
+	int idx;
+	const char *name;
+	const char * const *parent_names;
+	int num_parents;
+	int offset_mux;
+	u8 shift;
+	u8 mask;
+	int offset_gate;
+	u8 bit_idx;
+	unsigned long flags;
+};
+
 struct stm32f4_clk_data {
 	const struct stm32f4_gate_data *gates_data;
 	const u64 *gates_map;
 	int gates_num;
 	const struct stm32f4_pll_data *pll_data;
+	const struct stm32_aux_clk *aux_clk;
+	int aux_clk_num;
+};
+
+#define NONE -1
+#define NO_IDX  NONE
+#define NO_MUX  NONE
+#define NO_GATE NONE
+
+static const struct stm32_aux_clk stm32f429_aux_clk[] = {
+	{
+		CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
+		NO_MUX, 0, 0,
+		STM32F4_RCC_APB2ENR, 26,
+		CLK_SET_RATE_PARENT
+	},
 };
 
 static const struct stm32f4_clk_data stm32f429_clk_data = {
@@ -945,6 +976,8 @@ struct stm32f4_clk_data {
 	.gates_map	= stm32f42xx_gate_map,
 	.gates_num	= ARRAY_SIZE(stm32f429_gates),
 	.pll_data	= stm32f429_pll,
+	.aux_clk	= stm32f429_aux_clk,
+	.aux_clk_num	= ARRAY_SIZE(stm32f429_aux_clk),
 };
 
 static const struct stm32f4_clk_data stm32f469_clk_data = {
@@ -952,6 +985,8 @@ struct stm32f4_clk_data {
 	.gates_map	= stm32f46xx_gate_map,
 	.gates_num	= ARRAY_SIZE(stm32f469_gates),
 	.pll_data	= stm32f469_pll,
+	.aux_clk	= stm32f429_aux_clk,
+	.aux_clk_num	= ARRAY_SIZE(stm32f429_aux_clk),
 };
 
 static const struct of_device_id stm32f4_of_match[] = {
@@ -966,6 +1001,66 @@ struct stm32f4_clk_data {
 	{}
 };
 
+static struct clk_hw *stm32_register_aux_clk(const char *name,
+		const char * const *parent_names, int num_parents,
+		int offset_mux, u8 shift, u8 mask,
+		int offset_gate, u8 bit_idx,
+		unsigned long flags, spinlock_t *lock)
+{
+	struct clk_hw *hw;
+	struct clk_gate *gate;
+	struct clk_mux *mux = NULL;
+	struct clk_hw *mux_hw = NULL, *gate_hw = NULL;
+	const struct clk_ops *mux_ops = NULL, *gate_ops = NULL;
+
+	if (offset_gate != NO_GATE) {
+		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+		if (!gate) {
+			hw = ERR_PTR(-EINVAL);
+			goto fail;
+		}
+
+		gate->reg = base + offset_gate;
+		gate->bit_idx = bit_idx;
+		gate->flags = 0;
+		gate->lock = lock;
+		gate_hw = &gate->hw;
+		gate_ops = &clk_gate_ops;
+	}
+
+	if (offset_mux != NO_MUX) {
+		mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+		if (!mux) {
+			kfree(gate);
+			hw = ERR_PTR(-EINVAL);
+			goto fail;
+		}
+
+		mux->reg = base + offset_mux;
+		mux->shift = shift;
+		mux->mask = mask;
+		mux->flags = 0;
+		mux_hw = &mux->hw;
+		mux_ops = &clk_mux_ops;
+	}
+
+	if (mux_hw == NULL && gate_hw == NULL)
+		return ERR_PTR(-EINVAL);
+
+	hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
+			mux_hw, mux_ops,
+			NULL, NULL,
+			gate_hw, gate_ops,
+			flags);
+
+	if (IS_ERR(hw)) {
+		kfree(gate);
+		kfree(mux);
+	}
+fail:
+	return hw;
+}
+
 static void __init stm32f4_rcc_init(struct device_node *np)
 {
 	const char *hse_clk;
@@ -1121,6 +1216,28 @@ static void __init stm32f4_rcc_init(struct device_node *np)
 		goto fail;
 	}
 
+	for (n = 0; n < data->aux_clk_num; n++) {
+		const struct stm32_aux_clk *aux_clk;
+		struct clk_hw *hw;
+
+		aux_clk = &data->aux_clk[n];
+
+		hw = stm32_register_aux_clk(aux_clk->name,
+				aux_clk->parent_names, aux_clk->num_parents,
+				aux_clk->offset_mux, aux_clk->shift,
+				aux_clk->mask, aux_clk->offset_gate,
+				aux_clk->bit_idx, aux_clk->flags,
+				&stm32f4_clk_lock);
+
+		if (IS_ERR(hw)) {
+			pr_warn("Unable to register %s clk\n", aux_clk->name);
+			continue;
+		}
+
+		if (aux_clk->idx != NO_IDX)
+			clks[aux_clk->idx] = hw;
+	}
+
 	of_clk_add_hw_provider(np, stm32f4_rcc_lookup_clk, NULL);
 	return;
 fail:
-- 
1.9.1

^ permalink raw reply related

* [PATCH v3 5/9] clk: stm32f4: Add I2S clock
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>

From: Gabriel Fernandez <gabriel.fernandez@st.com>

This patch introduces I2S clock for stm32f4 soc.
The I2S clock could be derived from an external clock or from pll-i2s

Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
 drivers/clk/clk-stm32f4.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index 86244fc..3063b30 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -935,6 +935,8 @@ static struct clk_hw *stm32_register_cclk(struct device *dev, const char *name,
 
 static const char *lcd_parent[1] = { "pllsai-r-div" };
 
+static const char *i2s_parents[2] = { "plli2s-r", NULL };
+
 struct stm32_aux_clk {
 	int idx;
 	const char *name;
@@ -969,6 +971,12 @@ struct stm32f4_clk_data {
 		STM32F4_RCC_APB2ENR, 26,
 		CLK_SET_RATE_PARENT
 	},
+	{
+		CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
+		STM32F4_RCC_CFGR, 23, 1,
+		NO_GATE, 0,
+		CLK_SET_RATE_PARENT
+	},
 };
 
 static const struct stm32f4_clk_data stm32f429_clk_data = {
@@ -1063,7 +1071,7 @@ static struct clk_hw *stm32_register_aux_clk(const char *name,
 
 static void __init stm32f4_rcc_init(struct device_node *np)
 {
-	const char *hse_clk;
+	const char *hse_clk, *i2s_in_clk;
 	int n;
 	const struct of_device_id *match;
 	const struct stm32f4_clk_data *data;
@@ -1098,6 +1106,10 @@ static void __init stm32f4_rcc_init(struct device_node *np)
 
 	hse_clk = of_clk_get_parent_name(np, 0);
 
+	i2s_in_clk = of_clk_get_parent_name(np, 1);
+
+	i2s_parents[1] = i2s_in_clk;
+
 	clk_register_fixed_rate_with_accuracy(NULL, "hsi", NULL, 0,
 			16000000, 160000);
 	pllcfgr = readl(base + STM32F4_RCC_PLLCFGR);
-- 
1.9.1

^ permalink raw reply related

* [PATCH v3 6/9] clk: stm32f4: Add SAI clocks
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>

From: Gabriel Fernandez <gabriel.fernandez@st.com>

This patch introduces SAI clocks for stm32f4 socs.

Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
 drivers/clk/clk-stm32f4.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index 3063b30..02339d1 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -937,6 +937,9 @@ static struct clk_hw *stm32_register_cclk(struct device *dev, const char *name,
 
 static const char *i2s_parents[2] = { "plli2s-r", NULL };
 
+static const char *sai_parents[4] = { "pllsai-q-div", "plli2s-q-div", NULL,
+	"no-clock" };
+
 struct stm32_aux_clk {
 	int idx;
 	const char *name;
@@ -977,6 +980,18 @@ struct stm32f4_clk_data {
 		NO_GATE, 0,
 		CLK_SET_RATE_PARENT
 	},
+	{
+		CLK_SAI1, "sai1-a", sai_parents, ARRAY_SIZE(sai_parents),
+		STM32F4_RCC_DCKCFGR, 20, 3,
+		STM32F4_RCC_APB2ENR, 22,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_SAI2, "sai1-b", sai_parents, ARRAY_SIZE(sai_parents),
+		STM32F4_RCC_DCKCFGR, 22, 3,
+		STM32F4_RCC_APB2ENR, 22,
+		CLK_SET_RATE_PARENT
+	},
 };
 
 static const struct stm32f4_clk_data stm32f429_clk_data = {
@@ -1109,6 +1124,7 @@ static void __init stm32f4_rcc_init(struct device_node *np)
 	i2s_in_clk = of_clk_get_parent_name(np, 1);
 
 	i2s_parents[1] = i2s_in_clk;
+	sai_parents[2] = i2s_in_clk;
 
 	clk_register_fixed_rate_with_accuracy(NULL, "hsi", NULL, 0,
 			16000000, 160000);
-- 
1.9.1

^ permalink raw reply related

* [PATCH v3 7/9] clk: stm32f4: SDIO & 48Mhz clock management for STM32F469 board
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>

From: Gabriel Fernandez <gabriel.fernandez@st.com>

In the stm32f469 soc, the 48Mhz clock could be derived from pll-q or
from pll-sai-p.

The SDIO clock could be also derived from 48Mhz or from sys clock.

Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
 drivers/clk/clk-stm32f4.c | 49 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 46 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index 02339d1..161449d 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -206,7 +206,7 @@ struct stm32f4_gate_data {
 	{ STM32F4_RCC_APB2ENR,  8,	"adc1",		"apb2_div" },
 	{ STM32F4_RCC_APB2ENR,  9,	"adc2",		"apb2_div" },
 	{ STM32F4_RCC_APB2ENR, 10,	"adc3",		"apb2_div" },
-	{ STM32F4_RCC_APB2ENR, 11,	"sdio",		"pll48" },
+	{ STM32F4_RCC_APB2ENR, 11,	"sdio",		"sdmux" },
 	{ STM32F4_RCC_APB2ENR, 12,	"spi1",		"apb2_div" },
 	{ STM32F4_RCC_APB2ENR, 13,	"spi4",		"apb2_div" },
 	{ STM32F4_RCC_APB2ENR, 14,	"syscfg",	"apb2_div" },
@@ -940,6 +940,10 @@ static struct clk_hw *stm32_register_cclk(struct device *dev, const char *name,
 static const char *sai_parents[4] = { "pllsai-q-div", "plli2s-q-div", NULL,
 	"no-clock" };
 
+static const char *pll48_parents[2] = { "pll-q", "pllsai-p" };
+
+static const char *sdmux_parents[2] = { "pll48", "sys" };
+
 struct stm32_aux_clk {
 	int idx;
 	const char *name;
@@ -994,6 +998,45 @@ struct stm32f4_clk_data {
 	},
 };
 
+static const struct stm32_aux_clk stm32f469_aux_clk[] = {
+	{
+		CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
+		NO_MUX, 0, 0,
+		STM32F4_RCC_APB2ENR, 26,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
+		STM32F4_RCC_CFGR, 23, 1,
+		NO_GATE, 0,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_SAI1, "sai1-a", sai_parents, ARRAY_SIZE(sai_parents),
+		STM32F4_RCC_DCKCFGR, 20, 3,
+		STM32F4_RCC_APB2ENR, 22,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_SAI2, "sai1-b", sai_parents, ARRAY_SIZE(sai_parents),
+		STM32F4_RCC_DCKCFGR, 22, 3,
+		STM32F4_RCC_APB2ENR, 22,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		NO_IDX, "pll48", pll48_parents, ARRAY_SIZE(pll48_parents),
+		STM32F4_RCC_DCKCFGR, 27, 1,
+		NO_GATE, 0,
+		0
+	},
+	{
+		NO_IDX, "sdmux", sdmux_parents, ARRAY_SIZE(sdmux_parents),
+		STM32F4_RCC_DCKCFGR, 28, 1,
+		NO_GATE, 0,
+		0
+	},
+};
+
 static const struct stm32f4_clk_data stm32f429_clk_data = {
 	.gates_data	= stm32f429_gates,
 	.gates_map	= stm32f42xx_gate_map,
@@ -1008,8 +1051,8 @@ struct stm32f4_clk_data {
 	.gates_map	= stm32f46xx_gate_map,
 	.gates_num	= ARRAY_SIZE(stm32f469_gates),
 	.pll_data	= stm32f469_pll,
-	.aux_clk	= stm32f429_aux_clk,
-	.aux_clk_num	= ARRAY_SIZE(stm32f429_aux_clk),
+	.aux_clk	= stm32f469_aux_clk,
+	.aux_clk_num	= ARRAY_SIZE(stm32f469_aux_clk),
 };
 
 static const struct of_device_id stm32f4_of_match[] = {
-- 
1.9.1

^ permalink raw reply related

* [PATCH v3 8/9] ARM: dts: stm32f4: Add external I2S clock
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>

From: Gabriel Fernandez <gabriel.fernandez@st.com>

This patch adds an external I2S clock in the DT.
The I2S clock could be derived from an external I2S clock or by I2S pll.

Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
 arch/arm/boot/dts/stm32f429.dtsi | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index e4dae0e..7c7dfbd 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -68,6 +68,12 @@
 			compatible = "fixed-clock";
 			clock-frequency = <32000>;
 		};
+
+		clk_i2s_ckin: i2s-ckin {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <0>;
+		};
 	};
 
 	soc {
@@ -362,7 +368,7 @@
 			#clock-cells = <2>;
 			compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
 			reg = <0x40023800 0x400>;
-			clocks = <&clk_hse>;
+			clocks = <&clk_hse>, <&clk_i2s_ckin>;
 			st,syscfg = <&pwrcfg>;
 		};
 
-- 
1.9.1

^ permalink raw reply related

* [PATCH v3 9/9] ARM: dts: stm32f4: Include auxiliary stm32f4 clock definition
From: gabriel.fernandez at st.com @ 2016-12-01 15:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480606069-5178-1-git-send-email-gabriel.fernandez@st.com>

From: Gabriel Fernandez <gabriel.fernandez@st.com>

This patch include auxiliary clock definition (clocks which are not derived
from system clock.

Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
 arch/arm/boot/dts/stm32f429.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index 7c7dfbd..223dc12 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -48,6 +48,7 @@
 #include "skeleton.dtsi"
 #include "armv7-m.dtsi"
 #include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
+#include <dt-bindings/clock/stm32f4-clock.h>
 
 / {
 	clocks {
-- 
1.9.1

^ permalink raw reply related

* [PATCH 0/5] Meson GXL and GXM USB support
From: Rob Herring @ 2016-12-01 15:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAFBinCC8c2sXgo80LMMg=jqZ2hr8eLM_2g03H1J99m4xxFGYFA@mail.gmail.com>

On Wed, Nov 30, 2016 at 11:49:03PM +0100, Martin Blumenstingl wrote:
> On Wed, Nov 30, 2016 at 11:22 PM, Rob Herring <robh@kernel.org> wrote:
> > On Sun, Nov 27, 2016 at 11:42:02PM +0100, Martin Blumenstingl wrote:
> >> Hello Kishon,
> >>
> >> On Sat, Nov 26, 2016 at 3:56 PM, Martin Blumenstingl
> >> <martin.blumenstingl@googlemail.com> wrote:
> >> > USB support on GXL and GXM differs a lot from Meson8b and GXBB:
> >> > The most obvious change is that GXL and GXM now have one dwc3
> >> > controller and one dwc2 controller (instead of two dwc2 controllers).
> >> > With that there are also new USB PHYs.
> >> >
> >> > Due to lack of hardware I was only able to test this on a board with
> >> > GXM, but as far as I understand the hardware my preparations should be
> >> > correct (so it should also work on GXL).
> >> >
> >> > dwc2 will probably stay unused on most GXM devices since it's limited
> >> > to device mode via some dwc2 hardware configuration register.
> >> >
> >> > dwc3 is probably used on all devices, even if there is more than just
> >> > one USB port. dwc3 has a built-in USB2 hub - on GXL this hub has two
> >> > ports enabled, while on GXM there are three ports enabled (see below
> >
> > This hub is an actual USB hub? If so, then you should probably model the
> > USB bus topology (which we have a binding definition for).
> (the following explanation is based on a) what I found is going on in
> the hardware registers b) reading the vendor drivers - unfortunately
> there are no datasheets available which could give more details).
> lsusb on my GXM gives:
> ...
>  Hub Port Status:
>    Port 1: 0000.0100 power
>    Port 2: 0000.0100 power
>    Port 3: 0000.0100 power
> 
> The layout looks like this:
> dwc3 provides a USB hub with 2 (on GXL) or 3 (on GXM) USB ports.
> Each of the port is driven by a PHY (port 1 = abp at 0x78000, port2 =
> abp at 0x78020, etc...).
> 
> On GXM USB2 PHY port 3 = abp at 0x78040 is connected to the third dwc3 hub port.
> On GXL PHY port 3 = abp at 0x78040 is connected to the dwc2 (I could not
> prove this yet as I don't have access to any GXL hardware).
> 
> So the answer is: we don't have an actual USB hub here (as this hub is
> provided by dwc3), but rather a set of PHYs which is assigned to
> dwc3's hub (if we don't configure *all* PHYs then none of the USB
> ports provided by the dwc3 hub works).
> 
> Could you please point me to the USB bus topology binding (is it the
> one described in usb-device.txt)?

Yes.

> 
> >> > for lsusb output). There are no USB3 ports enabled in the dwc3 hardware
> >> > configuration, meaning that the SoC is limited to high-speed mode.
> >> > On my GXM device the dwc3 hardware configuration forces it into "host
> >> > only" mode.
> >> >
> >> > The SoCs contain two PHY blocks: one USB3 PHY and up to four USB2 PHYs
> >> > (on GXM there are only three enabled, but the registers should support
> >> > up to four).
> >> > The USB3 PHY also handles the OTG interrupts, but since dwc3's hardware
> >> > configuration enforces "host only" mode I was not able to test this. It
> >> > simply takes care of an interrupt and then notifies all related PHYs
> >> > about the new mode.
> >> > The USB2 PHY block is a bit different: I created one PHY driver which
> >> > spans all "PHY ports" because the handling is a bit tricky. It turns
> >> > out that for each available USB port in dwc3's hub the corresponding
> >> > PHY must be enabled (even if there is no physical port - in my case
> >> > port 3 is not connected to anything, but disabling the PHY breaks
> >> > ports 1 and 2 as well).
> >> > I decided not not pass the USB2 PHYs directly to dwc3 due to three
> >> > reasons: 1. the USB3 PHY (which holds a reference to all relevant
> >> > USB2 PHY ports) controls the mode of the USB2 PHY ports (since both
> >> > are used with the same controller and thus it makes sense to keep the
> >> > mode consistent across all ports) 2. the dwc3 driver does not support
> >> > passing multiple USB2 PHYs (only one USB2 and one USB3 PHY can be
> >> > passed to it) 3. it is similar to how the vendor reference driver
> >> > manages the PHYs. Please note that this coupling is not a fixed, this
> >> > is all configurable via devicetree (so if the third USB2 PHY has to
> >> > be passed two the dwc2 controller then this is still possible by
> >> > just moving on PHY reference in the .dts).
> >> after not staring at my own code for 24 hours I realized this:
> >> (I went through quite a few iterations before getting these drivers to work)
> >> I'm basically re-modelling an "USB PHY hub" with my USB3 PHY driver
> >> (there's one "upstream" PHY interface which is passed to dwc3 and
> >> multiple downstream PHYs, each for one port on dwc3's internal hub).
> >> With this approach I could split each of the the USB2s into separate
> >> nodes again (instead of one devicetree node with #phy-cells = <1>) as
> >> the USB3 PHY is taking care of that special "we have to enable all
> >> ports or no port will be usable".
> >>
> >> We could go even one step further: why implement this in the Meson GXL
> >> specific PHY driver - why not implement a generic "phy-hub" driver
> >> (which would be valid whenever the PHY controller has to manage
> >> multiple PHYs at once, but wants to keep them all in a consistent
> >> state).
> >> The devicetree could look like this:
> >>     usb2_phy_hub: phy at 0 {
> >>         compatible = "phy-hub";
> >>         phys = <&other_phy1>, <&other_phy 2>;
> >>     };
> >>
> >> &dwc3 {
> >>      phys = <&usb2_phy_hub>, <&usb3_phy0>;
> >>      phy-names = "usb2-phy", "usb3-phy";
> >> };
> >
> > I'm okay with a hub if it is modeled as a USB hub. Here though, it
> > looks like you are just trying to group things which doesn't need to be
> > in DT.
> I hope my answer above makes things more clear

Yes, I thought there was some heirarchy here, but it seems not.

So you should just list the 3 phys at the controller. The controller 
has 3 ports and you have a phy for each port. The fact that they all 
need to be on/initialized is a quirk and shouldn't mean that you create 
some heirarchy in DT.

> >> The generic phy-hub driver would then implement all phy_ops callbacks
> >> and pass then to each of it's downstream PHYs.
> >
> > You can have generic drivers without a generic binding.
> So you'd rather implement a generic driver which would provide
> functions like of_create_grouped_phy(struct device_node *np) which
> would implement the grouping logic as described (but has no binding
> itself, but rather relies on the actual platform driver taking care of
> creating that binding and re-using generic code)?

Right.

Rob

^ permalink raw reply

* [PATCH] arm64: smp: Prevent raw_smp_processor_id() recursion
From: Robin Murphy @ 2016-12-01 15:55 UTC (permalink / raw)
  To: linux-arm-kernel

Under CONFIG_DEBUG_PREEMPT=y, this_cpu_ptr() ends up calling back into
raw_smp_processor_id(), resulting in some hilariously catastrophic
infinite recursion. In the normal case, we have:

  #define this_cpu_ptr(ptr) raw_cpu_ptr(ptr)

and everything is dandy. However for CONFIG_DEBUG_PREEMPT, this_cpu_ptr()
is defined in terms of my_cpu_offset, wherein the fun begins:

  #define my_cpu_offset per_cpu_offset(smp_processor_id())
  ...
  #define smp_processor_id() debug_smp_processor_id()
  ...
  notrace unsigned int debug_smp_processor_id(void)
  {
  	return check_preemption_disabled("smp_processor_id", "");
  ...
  notrace static unsigned int check_preemption_disabled(const char *what1,
  							const char *what2)
  {
  	int this_cpu = raw_smp_processor_id();

and bang. Use raw_cpu_ptr() directly to avoid that.

Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---

Since I just reproduced this locally to verify Will's suggestion, it
seemed I might as well just write it up as a patch :)

 arch/arm64/include/asm/smp.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index a62db952ffcb..d050d720a1b4 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -41,8 +41,10 @@ DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
  * We don't use this_cpu_read(cpu_number) as that has implicit writes to
  * preempt_count, and associated (compiler) barriers, that we'd like to avoid
  * the expense of. If we're preemptible, the value can be stale at use anyway.
+ * And we can't use this_cpu_ptr() either, as that winds up recursing back
+ * here under CONFIG_DEBUG_PREEMPT=y.
  */
-#define raw_smp_processor_id() (*this_cpu_ptr(&cpu_number))
+#define raw_smp_processor_id() (*raw_cpu_ptr(&cpu_number))
 
 struct seq_file;
 
-- 
2.10.2.dirty

^ permalink raw reply related

* [PATCH v5 net-next 7/7] ARM64: dts: marvell: Add network support for Armada 3700
From: Marcin Wojtas @ 2016-12-01 16:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <f205231e640a2324b8f007073cf54b166a263ed4.1480542157.git-series.gregory.clement@free-electrons.com>

Hi Gregory,

2016-11-30 22:42 GMT+01:00 Gregory CLEMENT <gregory.clement@free-electrons.com>:
> Add neta nodes for network support both in device tree for the SoC and
> the board.
>
> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> ---
>  arch/arm64/boot/dts/marvell/armada-3720-db.dts | 23 +++++++++++++++++++-
>  arch/arm64/boot/dts/marvell/armada-37xx.dtsi   | 23 +++++++++++++++++++-
>  2 files changed, 46 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/marvell/armada-3720-db.dts b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
> index 1372e9a6aaa4..c8b82e4145de 100644
> --- a/arch/arm64/boot/dts/marvell/armada-3720-db.dts
> +++ b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
> @@ -81,3 +81,26 @@
>  &pcie0 {
>         status = "okay";
>  };
> +
> +&mdio {
> +       status = "okay";
> +       phy0: ethernet-phy at 0 {
> +               reg = <0>;
> +       };
> +
> +       phy1: ethernet-phy at 1 {
> +               reg = <1>;
> +       };
> +};
> +
> +&eth0 {
> +       phy-mode = "rgmii-id";
> +       phy = <&phy0>;
> +       status = "okay";
> +};
> +
> +&eth1 {
> +       phy-mode = "rgmii-id";

Should be "sgmii".

Best regards,
Marcin

^ permalink raw reply

* [PATCH v5 net-next 0/7] Support Armada 37xx SoC (ARMv8 64-bits) in mvneta driver
From: Marcin Wojtas @ 2016-12-01 16:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.0270f6d2413a709521fe2c8c17fbebea6f2e78d1.1480542157.git-series.gregory.clement@free-electrons.com>

Hi Gregory,

Checked on a388-gp with and without HWBM, also both ports work on
a3700 (second one after changing to sgmii).

Tested-by: Marcin Wojtas <mw@semihalf.com>

Best regards,
Marcin

2016-11-30 22:42 GMT+01:00 Gregory CLEMENT <gregory.clement@free-electrons.com>:
> Hi,
>
> The Armada 37xx is a new ARMv8 SoC from Marvell using same network
> controller as the older Armada 370/38x/XP SoCs. This series adapts the
> driver in order to be able to use it on this new SoC. The main changes
> are:
>
> - 64-bits support: the first patches allow using the driver on a 64-bit
>   architecture.
>
> - MBUS support: the mbus configuration is different on Armada 37xx
>   from the older SoCs.
>
> - per cpu interrupt: Armada 37xx do not support per cpu interrupt for
>   the NETA IP, the non-per-CPU behavior was added back.
>
> The first patch is an optimization in the rx path in swbm mode.
> The second patch remove unnecessary allocation for HWBM.
> The first item is solved by patches 4 and 5.
> The 2 last items are solved by patch 6.
> In patch 7 the dt support is added.
>
> Beside Armada 37xx, this series have been again tested on Armada XP
> and Armada 38x (with Hardware Buffer Management and with Software
> Buffer Management).
>
> This is the 5th version of the series:
> - 1st version:
> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/469588.html
>
> - 2nd version:
> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/470476.html
>
> - 3rd version:
> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/470901.html
>
> - 4th version:
> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/471039.html
>
> Changelog:
> v4 -> v5:
>  - remove unnecessary cast in patch 3
>
> v3 -> v4:
>  - Adding new patch: "net: mvneta: do not allocate buffer in rxq init
>    with HWBM"
>
>  - Simplify the HWBM case in patch 3 as suggested by Marcin
>
> v2 -> v3:
>  - Adding patch 1 "Optimize rx path for small frame"
>
>  - Fix the kbuild error by moving the "phys_addr += pp->rx_offset_correction;"
>   line from patch 2 to patch 3 where rx_offset_correction is introduced.
>
>  - Move the memory allocation of the buf_virt_addr of the rxq to be
>    called by the probe function in order to avoid a memory leak.
>
> Thanks,
>
> Gregory
>
> Gregory CLEMENT (5):
>   net: mvneta: Optimize rx path for small frame
>   net: mvneta: Do not allocate buffer in rxq init with HWBM
>   net: mvneta: Use cacheable memory to store the rx buffer virtual address
>   net: mvneta: Only disable mvneta_bm for 64-bits
>   ARM64: dts: marvell: Add network support for Armada 3700
>
> Marcin Wojtas (2):
>   net: mvneta: Convert to be 64 bits compatible
>   net: mvneta: Add network support for Armada 3700 SoC
>
>  Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt |   7 +-
>  arch/arm64/boot/dts/marvell/armada-3720-db.dts                    |  23 +++++-
>  arch/arm64/boot/dts/marvell/armada-37xx.dtsi                      |  23 +++++-
>  drivers/net/ethernet/marvell/Kconfig                              |  10 +-
>  drivers/net/ethernet/marvell/mvneta.c                             | 344 +++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
>  5 files changed, 305 insertions(+), 102 deletions(-)
>
> base-commit: 436accebb53021ef7c63535f60bda410aa87c136
> --
> git-series 0.8.10

^ permalink raw reply

* [PATCH v5 net-next 0/7] Support Armada 37xx SoC (ARMv8 64-bits) in mvneta driver
From: Gregory CLEMENT @ 2016-12-01 16:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAPv3WKdWyS0wCVsRKR86qpMx4r8NN9=RmjM9oHFy2mmvaR5PAA@mail.gmail.com>

Hi Marcin,
 
 On jeu., d?c. 01 2016, Marcin Wojtas <mw@semihalf.com> wrote:

> Hi Gregory,
>
> Checked on a388-gp with and without HWBM, also both ports work on
> a3700 (second one after changing to sgmii).
>
> Tested-by: Marcin Wojtas <mw@semihalf.com>

Thanks, I am going to send a new version with tour tested-by and the dts
fix for the second port.

Gregory

>
> Best regards,
> Marcin
>
> 2016-11-30 22:42 GMT+01:00 Gregory CLEMENT <gregory.clement@free-electrons.com>:
>> Hi,
>>
>> The Armada 37xx is a new ARMv8 SoC from Marvell using same network
>> controller as the older Armada 370/38x/XP SoCs. This series adapts the
>> driver in order to be able to use it on this new SoC. The main changes
>> are:
>>
>> - 64-bits support: the first patches allow using the driver on a 64-bit
>>   architecture.
>>
>> - MBUS support: the mbus configuration is different on Armada 37xx
>>   from the older SoCs.
>>
>> - per cpu interrupt: Armada 37xx do not support per cpu interrupt for
>>   the NETA IP, the non-per-CPU behavior was added back.
>>
>> The first patch is an optimization in the rx path in swbm mode.
>> The second patch remove unnecessary allocation for HWBM.
>> The first item is solved by patches 4 and 5.
>> The 2 last items are solved by patch 6.
>> In patch 7 the dt support is added.
>>
>> Beside Armada 37xx, this series have been again tested on Armada XP
>> and Armada 38x (with Hardware Buffer Management and with Software
>> Buffer Management).
>>
>> This is the 5th version of the series:
>> - 1st version:
>> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/469588.html
>>
>> - 2nd version:
>> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/470476.html
>>
>> - 3rd version:
>> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/470901.html
>>
>> - 4th version:
>> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/471039.html
>>
>> Changelog:
>> v4 -> v5:
>>  - remove unnecessary cast in patch 3
>>
>> v3 -> v4:
>>  - Adding new patch: "net: mvneta: do not allocate buffer in rxq init
>>    with HWBM"
>>
>>  - Simplify the HWBM case in patch 3 as suggested by Marcin
>>
>> v2 -> v3:
>>  - Adding patch 1 "Optimize rx path for small frame"
>>
>>  - Fix the kbuild error by moving the "phys_addr += pp->rx_offset_correction;"
>>   line from patch 2 to patch 3 where rx_offset_correction is introduced.
>>
>>  - Move the memory allocation of the buf_virt_addr of the rxq to be
>>    called by the probe function in order to avoid a memory leak.
>>
>> Thanks,
>>
>> Gregory
>>
>> Gregory CLEMENT (5):
>>   net: mvneta: Optimize rx path for small frame
>>   net: mvneta: Do not allocate buffer in rxq init with HWBM
>>   net: mvneta: Use cacheable memory to store the rx buffer virtual address
>>   net: mvneta: Only disable mvneta_bm for 64-bits
>>   ARM64: dts: marvell: Add network support for Armada 3700
>>
>> Marcin Wojtas (2):
>>   net: mvneta: Convert to be 64 bits compatible
>>   net: mvneta: Add network support for Armada 3700 SoC
>>
>>  Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt |   7 +-
>>  arch/arm64/boot/dts/marvell/armada-3720-db.dts                    |  23 +++++-
>>  arch/arm64/boot/dts/marvell/armada-37xx.dtsi                      |  23 +++++-
>>  drivers/net/ethernet/marvell/Kconfig                              |  10 +-
>>  drivers/net/ethernet/marvell/mvneta.c                             | 344 +++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
>>  5 files changed, 305 insertions(+), 102 deletions(-)
>>
>> base-commit: 436accebb53021ef7c63535f60bda410aa87c136
>> --
>> git-series 0.8.10

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply

* [PATCH 4/5] regulator: Add support for TI TWL6032
From: Rob Herring @ 2016-12-01 16:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161126181326.14951-5-Nicolae_Rosia@mentor.com>

On Sat, Nov 26, 2016 at 08:13:25PM +0200, Nicolae Rosia wrote:
> The TWL6032 PMIC is similar to TWL6030, has different
> output names, and regulator control logic.
> It is used on Barnes & Noble Nook HD and HD+.
> 
> Signed-off-by: Nicolae Rosia <Nicolae_Rosia@mentor.com>
> ---
>  .../bindings/regulator/twl6032-regulator.txt       | 109 ++++
>  drivers/regulator/Kconfig                          |   7 +
>  drivers/regulator/Makefile                         |   1 +
>  drivers/regulator/twl6032-regulator.c              | 582 +++++++++++++++++++++
>  4 files changed, 699 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/regulator/twl6032-regulator.txt
>  create mode 100644 drivers/regulator/twl6032-regulator.c
> 
> diff --git a/Documentation/devicetree/bindings/regulator/twl6032-regulator.txt b/Documentation/devicetree/bindings/regulator/twl6032-regulator.txt
> new file mode 100644
> index 0000000..323f5a9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/regulator/twl6032-regulator.txt
> @@ -0,0 +1,109 @@
> +TWL6032 PMIC Voltage Regulator Bindings
> +
> +The parent node must be MFD TWL Core, ti,twl6032.
> +
> +Required properties:
> +- compatible: "ti,twl6032"
> +
> +Optional properties:
> +- regulators node containing regulator childs.

s/childs/children/

regulators node is not a property.

> +
> +The child regulators  must be named after their hardware

extra space             ^

> +counterparts: LDO[1-6], LDOLN, LDOUSB and VANA.
> +
> +Each regulator is defined using the standard binding
> +for regulators as described in ./regulator.txt
> +
> +Example:
> +twl {
> +	compatible = "ti,twl6032";
> +
> +	[...]
> +
> +	pmic {
> +		compatible = "ti,twl6032-regulator";

Not documented.

> +
> +		regulators {

Do you really need pmic node and regulators node?

> +			ldo1: LDO1 {
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <2500000>;
> +
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			ldo2: LDO2 {
> +				regulator-min-microvolt = <1000000>;
> +				regulator-max-microvolt = <3000000>;
> +
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			ldo3: LDO3 {
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-boot-on;
> +
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			ldo4: LDO4 {
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			ldo5: LDO5 {
> +				regulator-min-microvolt = <1200000>;
> +				regulator-max-microvolt = <3000000>;
> +
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			ldo6: LDO6 {
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-always-on;
> +
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			ldo7: LDO7 {
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			ldoln: LDOLN {
> +				regulator-min-microvolt = <1000000>;
> +				regulator-max-microvolt = <3000000>;
> +			};
> +
> +			ldousb: LDOUSB {
> +				regulator-min-microvolt = <1000000>;
> +				regulator-max-microvolt = <3000000>;
> +			};
> +
> +			vana: VANA {
> +				regulator-min-microvolt = <2100000>;
> +				regulator-max-microvolt = <2100000>;
> +				regulator-always-on;
> +			};
> +		};
> +	};
> +
> +	[...]
> +};

^ permalink raw reply

* [PATCH 1/2] Documentation: sample averaging for imx6ul_tsc
From: Rob Herring @ 2016-12-01 16:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480232698-23075-1-git-send-email-guy.shapiro@mobi-wize.com>

On Sun, Nov 27, 2016 at 09:44:57AM +0200, Guy Shapiro wrote:
> The i.MX6UL internal touchscreen controller contains an option to
> average upon samples. This feature reduces noise from the produced
> touch locations.
> 
> This patch introduces a new device tree optional property for this
> feature. It provides control over the amount of averaged samples per
> touch event.
> 
> The property was inspired by a similar property on the
> "brcm,iproc-touchscreen" binding.
> 
> Signed-off-by: Guy Shapiro <guy.shapiro@mobi-wize.com>
> ---
>  .../devicetree/bindings/input/touchscreen/imx6ul_tsc.txt          | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
> index 853dff9..a66069f 100644
> --- a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
> +++ b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
> @@ -17,6 +17,13 @@ Optional properties:
>    This value depends on the touch screen.
>  - pre-charge-time: the touch screen need some time to precharge.
>    This value depends on the touch screen.
> +- average-samples: Number of data samples which are averaged for each read.
> +	Valid values 0-4
> +	0 =  1 sample
> +	1 =  4 samples
> +	2 =  8 samples
> +	3 = 16 samples
> +	4 = 32 samples

Either this needs a vendor prefix or should be documented as a generic 
property. In the latter case, you should use actual number of samples 
(1-32) for the values.

>  
>  Example:
>  	tsc: tsc at 02040000 {
> @@ -32,5 +39,6 @@ Example:
>  		xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
>  		measure-delay-time = <0xfff>;
>  		pre-charge-time = <0xffff>;
> +		average-samples = <4>;
>  		status = "okay";
>  	};
> -- 
> 2.1.4
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v3 2/3] powerpc/reloc64: add support for 32-bit CRC pseudo-symbols
From: Ard Biesheuvel @ 2016-12-01 16:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAKv+Gu_nPdQXxBnEYhYVt02SFbYx_bYtfU9LE8OkL5o0P5suOA@mail.gmail.com>

On 1 December 2016 at 09:45, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> On 1 December 2016 at 09:39, Michael Ellerman <mpe@ellerman.id.au> wrote:
>> Ard Biesheuvel <ard.biesheuvel@linaro.org> writes:
>>> On 25 November 2016 at 11:29, Michael Ellerman <mpe@ellerman.id.au> wrote:
>>>> Ard Biesheuvel <ard.biesheuvel@linaro.org> writes:
>>>>
>>>> [    7.607687] kvm: disagrees about version of symbol module_layout
>>>> [    7.846799] virtio: disagrees about version of symbol module_layout
>>>> [   22.012615] crc32c_vpmsum: disagrees about version of symbol module_layout
>>>> [   22.012959] libcrc32c: disagrees about version of symbol module_layout
>>>>
>>>
>>> Sigh. I suppose your modversions fixes are queued for v4.10? It's
>>> probably best to revisit this after the v4.10 merge window closes
>>> then, just to make sure I'm not aiming for a moving target.
>>
>> Actually they were merged into 4.9-rc7 ish.
>>
>> But I'm still seeing the same as above with this series rebased on top
>> of that, and I'm a bit short on time to debug it ATM.
>>
>> So during the 4.10 cycle is probably the best we can hope for, sorry.
>>
>
> Not a problem. The only question is whether 1/3 of this series fixes
> an actual bug or not, given that the CONFIG_RELOCATABLE workaround has
> been made ppc64 only.
>
> But for the remaining patches, I'm happy to respin after the v4.10
> merge window closes, and get something queued for v4.11
>

Actually, given the uncertain fate of modversions in general, we may
no longer have to bother by the time the v4.11 merge window opens ...

^ permalink raw reply

* [PATCH v2] arm64: mm: Fix memmap to be initialized for the entire section
From: Will Deacon @ 2016-12-01 16:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480530091-1092-1-git-send-email-rrichter@cavium.com>

On Wed, Nov 30, 2016 at 07:21:31PM +0100, Robert Richter wrote:
> On ThunderX systems with certain memory configurations we see the
> following BUG_ON():
> 
>  kernel BUG at mm/page_alloc.c:1848!
> 
> This happens for some configs with 64k page size enabled. The BUG_ON()
> checks if start and end page of a memmap range belongs to the same
> zone.
> 
> The BUG_ON() check fails if a memory zone contains NOMAP regions. In
> this case the node information of those pages is not initialized. This
> causes an inconsistency of the page links with wrong zone and node
> information for that pages. NOMAP pages from node 1 still point to the
> mem zone from node 0 and have the wrong nid assigned.
> 
> The reason for the mis-configuration is a change in pfn_valid() which
> reports pages marked NOMAP as invalid:
> 
>  68709f45385a arm64: only consider memblocks with NOMAP cleared for linear mapping
> 
> This causes pages marked as nomap being no long reassigned to the new
> zone in memmap_init_zone() by calling __init_single_pfn().
> 
> Fixing this by restoring the old behavior of pfn_valid() to use
> memblock_is_memory(). Also changing users of pfn_valid() in arm64 code
> to use memblock_is_map_memory() where necessary. This only affects
> code in ioremap.c. The code in mmu.c still can use the new version of
> pfn_valid().
> 
> As a consequence, pfn_valid() can not be used to check if a physical
> page is RAM. It just checks if there is an underlying memmap with a
> valid struct page. Moreover, for performance reasons the whole memmap
> (with pageblock_nr_pages number of pages) has valid pfns (SPARSEMEM
> config). The memory range is extended to fit the alignment of the
> memmap. Thus, pfn_valid() may return true for pfns that do not map to
> physical memory. Those pages are simply not reported to the mm, they
> are not marked reserved nor added to the list of free pages. Other
> functions such a page_is_ram() or memblock_is_map_ memory() must be
> used to check for memory and if the page can be mapped with the linear
> mapping.
> 
> Since NOMAP mem ranges may need to be mapped with different mem
> attributes (e.g. read-only or non-caching) we can not use linear
> mapping here. The use of memblock_is_memory() in pfn_valid() may not
> break this behaviour. Since commit:
> 
>  e7cd190385d1 arm64: mark reserved memblock regions explicitly in iomem
> 
> NOMAP mem resources are no longer marked as system RAM (IORESOURCE_
> SYSTEM_RAM). Now page_is_ram() and region_intersects() (see
> memremap()) do not detect NOMAP mem as system ram and NOMAP mem is not
> added to the linear mapping as system RAM is.
> 
> v2:
> 
>  * Added Ack
>  * updated description to reflect the discussion
> 
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Robert Richter <rrichter@cavium.com>
> ---
>  arch/arm64/mm/init.c    | 2 +-
>  arch/arm64/mm/ioremap.c | 5 +++--
>  2 files changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> index 212c4d1e2f26..166911f4a2e6 100644
> --- a/arch/arm64/mm/init.c
> +++ b/arch/arm64/mm/init.c
> @@ -147,7 +147,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
>  #ifdef CONFIG_HAVE_ARCH_PFN_VALID
>  int pfn_valid(unsigned long pfn)
>  {
> -	return memblock_is_map_memory(pfn << PAGE_SHIFT);
> +	return memblock_is_memory(pfn << PAGE_SHIFT);
>  }
>  EXPORT_SYMBOL(pfn_valid);
>  #endif
> diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c
> index 01e88c8bcab0..c17c220b0c48 100644
> --- a/arch/arm64/mm/ioremap.c
> +++ b/arch/arm64/mm/ioremap.c
> @@ -21,6 +21,7 @@
>   */
>  
>  #include <linux/export.h>
> +#include <linux/memblock.h>
>  #include <linux/mm.h>
>  #include <linux/vmalloc.h>
>  #include <linux/io.h>
> @@ -55,7 +56,7 @@ static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size,
>  	/*
>  	 * Don't allow RAM to be mapped.
>  	 */
> -	if (WARN_ON(pfn_valid(__phys_to_pfn(phys_addr))))
> +	if (WARN_ON(memblock_is_map_memory(phys_addr)))
>  		return NULL;
>  
>  	area = get_vm_area_caller(size, VM_IOREMAP, caller);
> @@ -96,7 +97,7 @@ EXPORT_SYMBOL(__iounmap);
>  void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size)
>  {
>  	/* For normal memory we already have a cacheable mapping. */
> -	if (pfn_valid(__phys_to_pfn(phys_addr)))
> +	if (memblock_is_map_memory(phys_addr))
>  		return (void __iomem *)__phys_to_virt(phys_addr);

Thanks for sending out the new patch. Whilst I'm still a bit worried about
changing pfn_valid like this, I guess we'll just have to fix up any callers
which suffer from this change.

Acked-by: Will Deacon <will.deacon@arm.com>

I'd like to see this sit in -next for a bit before we send it further.

Will

^ permalink raw reply

* 4.9-rc7 nouveau fails on arm64 64k page kernel but works with 4k
From: Jeremy Linton @ 2016-12-01 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

I placed a 9600GT in a softiron 3k running fedora 25, and the nouveau 
driver failed to claim the device with :

[drm] Initialized
nouveau 0000:01:00.0: NVIDIA G94 (094100a1)
nouveau 0000:01:00.0: bios: version 62.94.0d.00.04
nouveau: probe of 0000:01:00.0 failed with error -22

Which with a little bit of debugging seems to be a failure in:

[77216.692605] [<ffff000001404120>] ttm_bo_validate+0xb0/0x1e8 [ttm]
[77216.698697] [<ffff0000014045ac>] ttm_bo_init+0x354/0x410 [ttm]
[77216.704706] [<ffff0000019d7bd0>] nouveau_bo_new+0x1f4/0x314 [nouveau]
[77216.711308] [<ffff0000019e4620>] nv50_display_create+0x10c/0xa1c 
[nouveau]
[77216.718340] [<ffff0000019df898>] nouveau_display_create+0x50c/0x59c 
[nouveau]
[77216.725632] [<ffff0000019d3e24>] nouveau_drm_load+0x22c/0x8c0 [nouveau]
[77216.732286] [<ffff00000137a1a0>] drm_dev_register+0xc0/0xf0 [drm]
[77216.738409] [<ffff00000137b8a4>] drm_get_pci_dev+0xbc/0x188 [drm]
[77216.744663] [<ffff0000019d35e8>] nouveau_drm_probe+0x180/0x208 [nouveau]
[77216.751354] [<ffff0000084c30dc>] local_pci_probe+0x50/0xb4
[77216.756827] [<ffff0000084c3e40>] pci_device_probe+0xf8/0x148
[77216.762474] [<ffff0000085b6a10>] driver_probe_device+0x284/0x420
[77216.768467] [<ffff0000085b6ccc>] __driver_attach+0x120/0x124
[77216.774115] [<ffff0000085b446c>] bus_for_each_dev+0x6c/0xac
[77216.779673] [<ffff0000085b6204>] driver_attach+0x2c/0x34
[77216.784972] [<ffff0000085b5cb4>] bus_add_driver+0x244/0x2b0
[77216.790531] [<ffff0000085b78e4>] driver_register+0x68/0xfc
[77216.796004] [<ffff0000084c29a8>] __pci_register_driver+0x60/0x6c
[77216.802047] [<ffff00000137bcb8>] drm_pci_init+0x108/0x138 [drm]
[77216.808146] [<ffff000001530158>] nouveau_drm_init+0x158/0x10000 [nouveau]
[77216.814922] [<ffff0000080831a8>] do_one_initcall+0x44/0x128
[77216.820483] [<ffff0000081cad6c>] do_init_module+0x68/0x1e0
[77216.825957] [<ffff000008150d84>] load_module+0xfac/0x12bc
[77216.831343] [<ffff00000815132c>] SyS_finit_module+0xe4/0xf0
[77216.836902] [<ffff000008082b70>] el0_svc_naked+0x24/0x28

By default fedora is using a 64k page kernel, switching to a mainline 
4.9-rc7 kernel using the same configuration the same problem exists 
(there are a couple others, mentioned briefly in the defect). Changing 
the mainline kernel from 64k to 4k pages corrects the problem and a 
terminal display can be seen.

The fedora defect is:
https://bugzilla.redhat.com/show_bug.cgi?id=1400623


Thanks,

^ permalink raw reply

* [PATCH V1 1/2] PCI: thunder: Enable ACPI PCI controller for ThunderX pass2.x silicon version
From: Bjorn Helgaas @ 2016-12-01 16:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <eba92ea8-bdab-9a3a-7b18-caaeac15db5d@semihalf.com>

On Thu, Dec 01, 2016 at 09:49:51AM +0100, Tomasz Nowicki wrote:
> Hi Bjorn,
> 
> On 01.12.2016 01:28, Bjorn Helgaas wrote:
> >Hi Tomasz,
> >
> >On Tue, Nov 15, 2016 at 10:14:57AM +0100, Tomasz Nowicki wrote:
> >>ThunderX PCIe controller to off-chip devices (so-called PEM) is not fully
> >>compliant with ECAM standard. It uses non-standard configuration space
> >>accessors (see pci_thunder_pem_ops) and custom configuration space granulation
> >>(see bus_shift = 24). In order to access configuration space and
> >>probe PEM as ACPI based PCI host controller we need to add MCFG quirk
> >>infrastructure. This involves:
> >>1. thunder_pem_init() ACPI extension so that we can probe PEM-specific
> >>   register ranges analogously to DT
> >>2. Export PEM pci_thunder_pem_ops structure so it is visible to MCFG quirk
> >>   code.
> >>3. New quirk entries for each PEM segment. Each contains platform IDs,
> >>   mentioned pci_thunder_pem_ops and CFG resources.
> >>
> >>Quirk is considered for ThunderX silicon pass2.x only which is identified
> >>via MCFG revision 1.
> >>
> >>Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
> >>---
> >> drivers/acpi/pci_mcfg.c            |  20 +++++++
> >> drivers/pci/host/pci-thunder-pem.c | 107 ++++++++++++++++++++++++++++++++-----
> >> include/linux/pci-ecam.h           |   4 ++
> >> 3 files changed, 117 insertions(+), 14 deletions(-)
> >>
> >>diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
> >>index ac21db3..e4e2b9b 100644
> >>--- a/drivers/acpi/pci_mcfg.c
> >>+++ b/drivers/acpi/pci_mcfg.c
> >>@@ -57,6 +57,26 @@ static struct mcfg_fixup mcfg_quirks[] = {
> >> 	{ "QCOM  ", "QDF2432 ", 1, 5, MCFG_BUS_ANY, &pci_32b_ops },
> >> 	{ "QCOM  ", "QDF2432 ", 1, 6, MCFG_BUS_ANY, &pci_32b_ops },
> >> 	{ "QCOM  ", "QDF2432 ", 1, 7, MCFG_BUS_ANY, &pci_32b_ops },
> >>+#ifdef CONFIG_PCI_HOST_THUNDER_PEM
> >>+#define THUNDER_MCFG_RES(addr, node) \
> >>+	DEFINE_RES_MEM(addr + (node << 44), 0x39 * SZ_16M)
> >>+#define THUNDER_MCFG_QUIRK(rev, node) \
> >>+	{ "CAVIUM", "THUNDERX", rev, 4 + (10 * node), MCFG_BUS_ANY, \
> >>+	  &pci_thunder_pem_ops, THUNDER_MCFG_RES(0x88001f000000UL, node) }, \
> >>+	{ "CAVIUM", "THUNDERX", rev, 5 + (10 * node), MCFG_BUS_ANY, \
> >>+	  &pci_thunder_pem_ops, THUNDER_MCFG_RES(0x884057000000UL, node) }, \
> >>+	{ "CAVIUM", "THUNDERX", rev, 6 + (10 * node), MCFG_BUS_ANY, \
> >>+	  &pci_thunder_pem_ops, THUNDER_MCFG_RES(0x88808f000000UL, node) }, \
> >>+	{ "CAVIUM", "THUNDERX", rev, 7 + (10 * node), MCFG_BUS_ANY, \
> >>+	  &pci_thunder_pem_ops, THUNDER_MCFG_RES(0x89001f000000UL, node) }, \
> >>+	{ "CAVIUM", "THUNDERX", rev, 8 + (10 * node), MCFG_BUS_ANY, \
> >>+	  &pci_thunder_pem_ops, THUNDER_MCFG_RES(0x894057000000UL, node) }, \
> >>+	{ "CAVIUM", "THUNDERX", rev, 9 + (10 * node), MCFG_BUS_ANY, \
> >>+	  &pci_thunder_pem_ops, THUNDER_MCFG_RES(0x89808f000000UL, node) }
> >>+	/* SoC pass2.x */
> >>+	THUNDER_MCFG_QUIRK(1, 0UL),
> >>+	THUNDER_MCFG_QUIRK(1, 1UL),
> >>+#endif
> >
> >I want all these quirks to work without having to enable
> >device-specific config options like CONFIG_PCI_HOST_THUNDER_PEM.
> >
> >I tweaked the preceding MCFG quirk support to wrap it in
> >CONFIG_PCI_QUIRKS.  I also tweaked the qualcomm and hisi patches to
> >move the meat of them to pci/quirks.c.  My work-in-progress is on
> >pci/ecam, but I can't easily build for arm64, so there are likely some
> >issues to be resolved.
> 
> Please see compilation fix patch in [1] for your series.
> 
> >
> >I'm hoping to end up with something like this:
> >https://git.kernel.org/cgit/linux/kernel/git/helgaas/pci.git/commit/?h=pci/ecam&id=51ad4df79a9b7f2a66b346a46b21a785a2937469
> >
> >The problem with ThunderX is that the config accessors are much bigger
> >and I don't really want to duplicate them in both pci/quirks.c and
> >pci-thunder-pem.c.
> >
> >Actually, that raises a question for qualcomm and hisi: in the DT
> >model, we use non-ECAM config accessors in the driver, but in the ACPI
> >model, we use ECAM accessors.  It seems like the accessors should be
> >the same regardless of whether we discover the bridge via DT or ACPI.
> >
> >Anyway, it's almost like we want to build pci-thunder-pem.o if
> >CONFIG_PCI_HOST_THUNDER_PEM || (CONFIG_PCI_QUIRKS && CONFIG_ARM64).
> >I don't know how to express that nicely.
> >
> >I was trying to avoid adding an ecam-quirks.c, but maybe we need to
> >add it and collect all the different accessors there and add #ifdefs
> >inside.
> >
> >Sorry, this is only half-baked, but I just wanted to throw this out in
> >case you have any ideas.
> 
> I agree that pci-thunder-pem.c and pci-thunder-ecam.c are too big to
> be duplicated. The same for new ecam-quirks.c container. So treating
> this as a necessary evil how about:

I discarded my original half-baked ecam-quirks.c idea and instead
tried changing the Makefile and adding some ifdefs in the individual
drivers.  It's not too pretty, but maybe better than ecam-quirks.c?

>  config PCI_HOST_THUNDER_PEM
>  	bool "Cavium Thunder PCIe controller to off-chip devices"
> -	depends on OF && ARM64
> +	depends on ARM64
> +	depends on OF || (ACPI && PCI_QUIRKS)
>  	select PCI_HOST_COMMON
> 
> Moreover, IMO we should select PCI_QUIRKS for ARM64 && ACPI by
> default. Then it becomes:
>  config PCI_HOST_THUNDER_PEM
>  	bool "Cavium Thunder PCIe controller to off-chip devices"
> -	depends on OF && ARM64
> +	depends on ARM64
> +	depends on OF || ACPI
>  	select PCI_HOST_COMMON

Thanks, I think you're right about needing Kconfig changes here.

I incorporated the first one (with "(ACPI && PCI_QUIRKS)") because we
shouldn't offer this Kconfig choice when PCI_QUIRKS is not set.

If we only depend on ACPI here and we decide that ARM64 should *not*
automatically select PCI_QUIRKS, we'll offer this choice even when
PCI_QUIRKS is not set, and that seems wrong.

Making it explicit here removes the non-obvious connection with the
PCI_QUIRKS selection strateg.

Bjorn

^ permalink raw reply

* [LINUX RFC v4 3/4] mtd: spi-nor: add stripe support
From: Cyrille Pitchen @ 2016-12-01 17:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <DA6901612C71B84D91459DE817C418AE26E0B5E2@XAP-PVEXMBX01.xlnx.xilinx.com>

Hi Naga,

Le 30/11/2016 ? 10:17, Naga Sureshkumar Relli a ?crit :
> Hi Cyrille,
> 
>> I have not finished to review the whole series yet but here some first
>> comments:
> 
> Thanks for reviewing these patch series.
> 
>>
>> Le 27/11/2016 ? 09:33, Naga Sureshkumar Relli a ?crit :
>>> This patch adds stripe support and it is needed for GQSPI parallel
>>> configuration mode by:
>>>
>>> - Adding required parameters like stripe and shift to spi_nor
>>>   structure.
>>> - Initializing all added parameters in spi_nor_scan()
>>> - Updating read_sr() and read_fsr() for getting status from both
>>>   flashes
>>> - Increasing page_size, sector_size, erase_size and toatal flash
>>>   size as and when required.
>>> - Dividing address by 2
>>> - Updating spi->master->flags for qspi driver to change CS
>>>
>>> Signed-off-by: Naga Sureshkumar Relli <nagasure@xilinx.com>
>>> ---
>>> Changes for v4:
>>>  - rename isparallel to stripe
>>> Changes for v3:
>>>  - No change
>>> Changes for v2:
>>>  - Splitted to separate MTD layer changes from SPI core changes
>>> ---
>>>  drivers/mtd/spi-nor/spi-nor.c | 130
>> ++++++++++++++++++++++++++++++++----------
>>>  include/linux/mtd/spi-nor.h   |   2 +
>>>  2 files changed, 103 insertions(+), 29 deletions(-)
>>>
>>> diff --git a/drivers/mtd/spi-nor/spi-nor.c
>>> b/drivers/mtd/spi-nor/spi-nor.c index d0fc165..4252239 100644
>>> --- a/drivers/mtd/spi-nor/spi-nor.c
>>> +++ b/drivers/mtd/spi-nor/spi-nor.c
>>> @@ -22,6 +22,7 @@
>>>  #include <linux/of_platform.h>
>>>  #include <linux/spi/flash.h>
>>>  #include <linux/mtd/spi-nor.h>
>>> +#include <linux/spi/spi.h>
>>>
>>>  /* Define max times to check status register before we give up. */
>>>
>>> @@ -89,15 +90,24 @@ static const struct flash_info
>>> *spi_nor_match_id(const char *name);  static int read_sr(struct
>>> spi_nor *nor)  {
>>>  	int ret;
>>> -	u8 val;
>>> +	u8 val[2];
>>>
>>> -	ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1);
>>> -	if (ret < 0) {
>>> -		pr_err("error %d reading SR\n", (int) ret);
>>> -		return ret;
>>> +	if (nor->stripe) {
>>> +		ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val[0], 2);
>>> +		if (ret < 0) {
>>> +			pr_err("error %d reading SR\n", (int) ret);
>>> +			return ret;
>>> +		}
>>> +		val[0] |= val[1];
>> Why '|' rather than '&' ?
>> I guess because of the 'Write In Progress/Busy' bit: when called by
>> spi_nor_sr_ready(), you want to be sure that this 'BUSY' bit is cleared on
>> both memories.
>>
>> But what about when the Status Register is read for purpose other than
>> checking the state of the 'BUSY' bit?
>>
> Yes you are correct, I will change this.
> 
>> What about SPI controllers supporting more than 2 memories in parallel?
>>
>> This solution might fit the ZynqMP controller but doesn't look so generic.
>>
>>> +	} else {
>>> +		ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val[0], 1);
>>> +		if (ret < 0) {
>>> +			pr_err("error %d reading SR\n", (int) ret);
>>> +			return ret;
>>> +		}
>>>  	}
>>>
>>> -	return val;
>>> +	return val[0];
>>>  }
>>>
>>>  /*
>>> @@ -108,15 +118,24 @@ static int read_sr(struct spi_nor *nor)  static
>>> int read_fsr(struct spi_nor *nor)  {
>>>  	int ret;
>>> -	u8 val;
>>> +	u8 val[2];
>>>
>>> -	ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1);
>>> -	if (ret < 0) {
>>> -		pr_err("error %d reading FSR\n", ret);
>>> -		return ret;
>>> +	if (nor->stripe) {
>>> +		ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val[0], 2);
>>> +		if (ret < 0) {
>>> +			pr_err("error %d reading FSR\n", ret);
>>> +			return ret;
>>> +		}
>>> +		val[0] &= val[1];
>> Same comment here: why '&' rather than '|'?
>> Surely because of the the 'READY' bit which should be set for both memories.
> I will update this also.
>>
>>> +	} else {
>>> +		ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val[0], 1);
>>> +		if (ret < 0) {
>>> +			pr_err("error %d reading FSR\n", ret);
>>> +			return ret;
>>> +		}
>>>  	}
>>>
>>> -	return val;
>>> +	return val[0];
>>>  }
>>>
>>>  /*
>>> @@ -290,9 +309,16 @@ static int spi_nor_wait_till_ready(struct spi_nor
>> *nor)
>>>   */
>>>  static int erase_chip(struct spi_nor *nor)  {
>>> +	u32 ret;
>>> +
>>>  	dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >> 10));
>>>
>>> -	return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0);
>>> +	ret = nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	return ret;
>>> +
>>
>> 	if (ret)
>> 		return ret;
>> 	else
>> 		return ret;
>>
>> This chunk should be removed, it doesn't ease the patch review ;)
> Ok, I will remove.
>>
>>>  }
>>>
>>>  static int spi_nor_lock_and_prep(struct spi_nor *nor, enum
>>> spi_nor_ops ops) @@ -349,7 +375,7 @@ static int
>>> spi_nor_erase_sector(struct spi_nor *nor, u32 addr)  static int
>>> spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)  {
>>>  	struct spi_nor *nor = mtd_to_spi_nor(mtd);
>>> -	u32 addr, len;
>>> +	u32 addr, len, offset;
>>>  	uint32_t rem;
>>>  	int ret;
>>>
>>> @@ -399,9 +425,13 @@ static int spi_nor_erase(struct mtd_info *mtd,
>> struct erase_info *instr)
>>>  	/* "sector"-at-a-time erase */
>>>  	} else {
>>>  		while (len) {
>>> +
>>>  			write_enable(nor);
>>> +			offset = addr;
>>> +			if (nor->stripe)
>>> +				offset /= 2;
>>
>> I guess this should be /= 4 for controllers supporting 4 memories in parallel.
>> Shouldn't you use nor->shift and define shift as an unsigned int instead of a
>> bool?
>> offset >>= nor->shift;
>>
> Yes we can use this shift, I will update
> 
>> Anyway, by tuning the address here in spi-nor.c rather than in the SPI
>> controller driver, you impose a model to support parallel memories that
>> might not be suited to other controllers.
> 
> For this ZynqMP GQSPI controller parallel configuration, globally spi-nor should know about this stripe feature
> And based on that address has to change.
> As I mentioned in cover letter, this controller in parallel configuration will work with even addresses only.
> i.e. Before creating address format(m25p_addr2cmd) in mtd layer, spi-nor should change that address based on stripe option.
> 
> I am updating this offset based on stripe option, and stripe option will update by reading dt property in nor_scan().
> So the controller which doesn't support, then the stripe will be zero.
> Or Can you please suggest any other way?
> 
>>
>>>
>>> -			ret = spi_nor_erase_sector(nor, addr);
>>> +			ret = spi_nor_erase_sector(nor, offset);
>>>  			if (ret)
>>>  				goto erase_err;
>>>
>>> @@ -525,6 +555,8 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs,
>> uint64_t len)
>>>  	bool use_top;
>>>  	int ret;
>>>
>>> +	ofs = ofs >> nor->shift;
>>> +
>>>  	status_old = read_sr(nor);
>>>  	if (status_old < 0)
>>>  		return status_old;
>>> @@ -610,6 +642,8 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs,
>> uint64_t len)
>>>  	bool use_top;
>>>  	int ret;
>>>
>>> +	ofs = ofs >> nor->shift;
>>> +
>>>  	status_old = read_sr(nor);
>>>  	if (status_old < 0)
>>>  		return status_old;
>>> @@ -709,6 +743,8 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t
>> ofs, uint64_t len)
>>>  	if (ret)
>>>  		return ret;
>>>
>>> +	ofs = ofs >> nor->shift;
>>> +
>>>  	ret = nor->flash_lock(nor, ofs, len);
>>>
>>>  	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); @@ -
>> 724,6 +760,8
>>> @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t
>> len)
>>>  	if (ret)
>>>  		return ret;
>>>
>>> +	ofs = ofs >> nor->shift;
>>> +
>>>  	ret = nor->flash_unlock(nor, ofs, len);
>>>
>>>  	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); @@ -
>> 1018,6 +1056,9
>>> @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
>>>  	u8			id[SPI_NOR_MAX_ID_LEN];
>>>  	const struct flash_info	*info;
>>>
>>> +	nor->spi->master->flags &= ~(SPI_MASTER_BOTH_CS |
>>> +					SPI_MASTER_DATA_STRIPE);
>>> +
>>>  	tmp = nor->read_reg(nor, SPINOR_OP_RDID, id,
>> SPI_NOR_MAX_ID_LEN);
>>>  	if (tmp < 0) {
>>>  		dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
>> @@ -1041,6
>>> +1082,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from,
>>> size_t len,  {
>>>  	struct spi_nor *nor = mtd_to_spi_nor(mtd);
>>>  	int ret;
>>> +	u32 offset = from;
>>>
>>>  	dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
>>>
>>> @@ -1049,7 +1091,13 @@ static int spi_nor_read(struct mtd_info *mtd,
>> loff_t from, size_t len,
>>>  		return ret;
>>>
>>>  	while (len) {
>>> -		ret = nor->read(nor, from, len, buf);
>>> +
>>> +		offset = from;
>>> +
>>> +		if (nor->stripe)
>>> +			offset /= 2;
>>> +
>>> +		ret = nor->read(nor, offset, len, buf);
>>>  		if (ret == 0) {
>>>  			/* We shouldn't see 0-length reads */
>>>  			ret = -EIO;
>>> @@ -1161,6 +1209,7 @@ static int spi_nor_write(struct mtd_info *mtd,
>> loff_t to, size_t len,
>>>  	struct spi_nor *nor = mtd_to_spi_nor(mtd);
>>>  	size_t page_offset, page_remain, i;
>>>  	ssize_t ret;
>>> +	u32 offset;
>>>
>>>  	dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
>>>
>>> @@ -1178,9 +1227,13 @@ static int spi_nor_write(struct mtd_info *mtd,
>> loff_t to, size_t len,
>>>  		/* the size of data remaining on the first page */
>>>  		page_remain = min_t(size_t,
>>>  				    nor->page_size - page_offset, len - i);
>>> +		offset = (to + i);
>>> +
>>> +		if (nor->stripe)
>>> +			offset /= 2;
>>>
>>>  		write_enable(nor);
>>> -		ret = nor->write(nor, to + i, page_remain, buf + i);
>>> +		ret = nor->write(nor, (offset), page_remain, buf + i);
>>>  		if (ret < 0)
>>>  			goto write_err;
>>>  		written = ret;
>>> @@ -1302,22 +1355,22 @@ static int spi_nor_check(struct spi_nor *nor)
>>>
>>>  int spi_nor_scan(struct spi_nor *nor, const char *name, enum
>>> read_mode mode)  {
>>> -	const struct flash_info *info = NULL;
>>> +	struct flash_info *info = NULL;
>>
>> You should not remove the const and should not try to modify members of
>> *info.
>>
>>>  	struct device *dev = nor->dev;
>>>  	struct mtd_info *mtd = &nor->mtd;
>>>  	struct device_node *np = spi_nor_get_flash_node(nor);
>>> -	int ret;
>>> -	int i;
>>> +	struct device_node *np_spi;
>>> +	int ret, i, xlnx_qspi_mode;
>>>
>>>  	ret = spi_nor_check(nor);
>>>  	if (ret)
>>>  		return ret;
>>>
>>>  	if (name)
>>> -		info = spi_nor_match_id(name);
>>> +		info = (struct flash_info *)spi_nor_match_id(name);
>>>  	/* Try to auto-detect if chip name wasn't specified or not found */
>>>  	if (!info)
>>> -		info = spi_nor_read_id(nor);
>>> +		info = (struct flash_info *)spi_nor_read_id(nor);
>>>  	if (IS_ERR_OR_NULL(info))
>>>  		return -ENOENT;
>>>
>> Both spi_nor_match_id() and spi_nor_read_id(), when they succeed, return
>> a pointer to an entry of the spi_nor_ids[] array, which is located in a read-
>> only memory area.
>>
>> Since your patch doesn't remove the const attribute of the spi_nor_ids[], I
>> wonder whether it has been tested. I expect it not to work on most
>> architecture.
>>
>> Anyway spi_nor_ids[] should remain const. Let's take the case of eXecution
>> In Place (XIP) from an external memory: if spi_nor_ids[] is const, it can be
>> read directly from this external (read-only) memory and we never need to
>> copy the array in RAM, so we save some KB of RAM.
>> This is just an example but I guess we can find other reasons to keep this
>> array const.
>>
>>> @@ -1341,7 +1394,7 @@ int spi_nor_scan(struct spi_nor *nor, const char
>> *name, enum read_mode mode)
>>>  			 */
>>>  			dev_warn(dev, "found %s, expected %s\n",
>>>  				 jinfo->name, info->name);
>>> -			info = jinfo;
>>> +			info = (struct flash_info *)jinfo;
>>>  		}
>>>  	}
>>>
>>> @@ -1370,6 +1423,27 @@ int spi_nor_scan(struct spi_nor *nor, const char
>> *name, enum read_mode mode)
>>>  	mtd->size = info->sector_size * info->n_sectors;
>>>  	mtd->_erase = spi_nor_erase;
>>>  	mtd->_read = spi_nor_read;
>>> +#ifdef CONFIG_OF
>>> +	np_spi = of_get_next_parent(np);
>>> +
>>> +	if (of_property_read_u32(np_spi, "xlnx,qspi-mode",
>>> +				&xlnx_qspi_mode) < 0) {
>> This really looks controller specific so should not be placed in the generic spi-
>> nor.c file.
> 
> Const is removed in info struct, because to update info members based parallel configuration.
> As I mentioned above,  for this parallel configuration, mtd and spi-nor should know the details like
> mtd->size, info->sectors, sector_size and page_size.

You can tune the values of nor->mtd.size, nor->mtd.erasesize, nor->page_size
or whatever member of nor/nor.mtd as needed without ever modifying members of
*info.

If you modify *info then spi_nor_scan() is called a 2nd time to probe and
configure SPI memories of the same part but connected to another controller,
the values of the modified members in this *info would not be those expected.
So *info and the spi_nor_ids[] array must remain const.

The *info structure is not used outside spi_nor_scan(); none of spi_nor_read(),
spi_nor_write() and spi_nor_erase() refers to *info hence every relevant value
can be set only nor or nor->mtd members.


Anyway, I think OR'ing or AND'ing values of memory registers depending on
the relevant bit we want to check is not the right solution.
If done in spi-nor.c, there would be a specific case for each memory register
we read, each register bit would have to be handled differently.

spi-nor.c tries to support as much memory parts as possible, it deals with
many registers and bits: Status/Control registers, Quad Enable bits...

If we start to OR or AND each of these register values to support the stripping
mode, spi-nor will become really hard to maintain.

I don't know whether it could be done with the xilinx controller but I thought
about first configuring the two memories independently calling spi_nor_scan()
twice; one call for each memory.

Then the xilinx driver could register only one struct mtd_info, overriding
mtd->_read() [and likely mtd->_write() and mtd->_erase() too] set by
spi_nor_scan() with a xilinx driver custom implementation so this driver
supports its controller stripping mode as it wants.

Of course, this solution assumes that the SPI controller has one dedicated
chip-select line for each memory and not a single chip-select line shared by
both memories. The memories should be configured independently: you can't
assume multiple instances of the very same memory part always return the exact
same value when reading one of their register. Logical AND/OR is not a generic
solution, IMHO.

If the xilinx controller has only one shared chip-select line then let's see
whether 2 GPIO lines could be used as independent chip-select lines.


Best regards,

Cyrille


> So during spi_nor_scan only mtd will update all these details, that's why I have added controller specific check to update those.
> 
> Can you please suggest, any other way to let mtd and spi-nor to know about this configuration without touching the core layers?
> 
> Please let me know, if I missed providing any required info.
> 
>>
>>> +		nor->shift = 0;
>>> +		nor->stripe = 0;
>>> +	} else if (xlnx_qspi_mode == 2) {
>>> +		nor->shift = 1;
>>> +		info->sector_size <<= nor->shift;
>>> +		info->page_size <<= nor->shift;
>> Just don't modify *info members! :)
>>
>>
>>> +		mtd->size <<= nor->shift;
>>> +		nor->stripe = 1;
>>> +		nor->spi->master->flags |= (SPI_MASTER_BOTH_CS |
>>> +						SPI_MASTER_DATA_STRIPE);
>>> +	}
>>> +#else
>>> +	/* Default to single */
>>> +	nor->shift = 0;
>>> +	nor->stripe = 0;
>>> +#endif
>> Best regards,
>>
>> Cyrille
> 
> Thanks,
> Naga Sureshkumar Relli
> 

^ permalink raw reply

* [PATCH v6 net-next 0/7] Support Armada 37xx SoC (ARMv8 64-bits) in mvneta driver
From: Gregory CLEMENT @ 2016-12-01 17:03 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

The Armada 37xx is a new ARMv8 SoC from Marvell using same network
controller as the older Armada 370/38x/XP SoCs. This series adapts the
driver in order to be able to use it on this new SoC. The main changes
are:

- 64-bits support: the first patches allow using the driver on a 64-bit
  architecture.

- MBUS support: the mbus configuration is different on Armada 37xx
  from the older SoCs.

- per cpu interrupt: Armada 37xx do not support per cpu interrupt for
  the NETA IP, the non-per-CPU behavior was added back.

The first patch is an optimization in the rx path in swbm mode.
The second patch remove unnecessary allocation for HWBM.
The first item is solved by patches 4 and 5.
The 2 last items are solved by patch 6.
In patch 7 the dt support is added.

Beside Armada 37xx, this series have been again tested on Armada XP
and Armada 38x (with Hardware Buffer Management and with Software
Buffer Management).

This is the 6th version of the series:
- 1st version:
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/469588.html

- 2nd version:
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/470476.html

- 3rd version:
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/470901.html

- 4th version:
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/471039.html

- 5th version:
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/471478.html

Changelog:
v5 -> v6:
 - Added Tested-by from  Marcin Wojtas on the series
 - Added Reviewed-by from Jisheng Zhang on patch 3
 - Fix eth1 phy mode for Armada 3720 DB board on patch 7

v4 -> v5:
 - remove unnecessary cast in patch 3

v3 -> v4:
 - Adding new patch: "net: mvneta: do not allocate buffer in rxq init
   with HWBM"

 - Simplify the HWBM case in patch 3 as suggested by Marcin

v2 -> v3:
 - Adding patch 1 "Optimize rx path for small frame"

 - Fix the kbuild error by moving the "phys_addr += pp->rx_offset_correction;"
  line from patch 2 to patch 3 where rx_offset_correction is introduced.

 - Move the memory allocation of the buf_virt_addr of the rxq to be
   called by the probe function in order to avoid a memory leak.

Thanks,

Gregory

Gregory CLEMENT (5):
  net: mvneta: Optimize rx path for small frame
  net: mvneta: Do not allocate buffer in rxq init with HWBM
  net: mvneta: Use cacheable memory to store the rx buffer virtual address
  net: mvneta: Only disable mvneta_bm for 64-bits
  ARM64: dts: marvell: Add network support for Armada 3700

Marcin Wojtas (2):
  net: mvneta: Convert to be 64 bits compatible
  net: mvneta: Add network support for Armada 3700 SoC

 Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt |   7 +-
 arch/arm64/boot/dts/marvell/armada-3720-db.dts                    |  23 +++++-
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi                      |  23 +++++-
 drivers/net/ethernet/marvell/Kconfig                              |  10 +-
 drivers/net/ethernet/marvell/mvneta.c                             | 344 +++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
 5 files changed, 305 insertions(+), 102 deletions(-)

base-commit: 436accebb53021ef7c63535f60bda410aa87c136
-- 
git-series 0.8.10

^ permalink raw reply

* [PATCH v6 net-next 1/7] net: mvneta: Optimize rx path for small frame
From: Gregory CLEMENT @ 2016-12-01 17:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.dd374b7aaa358be0211d7ead81129a399fa692f4.1480611779.git-series.gregory.clement@free-electrons.com>

For small frame reuse the phys_addr variable instead of accessing the
uncacheable value in the rx descriptor.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Tested-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvneta.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 87274d4ab102..1b84f746d748 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -1918,7 +1918,7 @@ static int mvneta_rx_swbm(struct mvneta_port *pp, int rx_todo,
 				goto err_drop_frame;
 
 			dma_sync_single_range_for_cpu(dev->dev.parent,
-						      rx_desc->buf_phys_addr,
+						      phys_addr,
 						      MVNETA_MH_SIZE + NET_SKB_PAD,
 						      rx_bytes,
 						      DMA_FROM_DEVICE);
-- 
git-series 0.8.10

^ permalink raw reply related

* [PATCH v6 net-next 2/7] net: mvneta: Do not allocate buffer in rxq init with HWBM
From: Gregory CLEMENT @ 2016-12-01 17:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.dd374b7aaa358be0211d7ead81129a399fa692f4.1480611779.git-series.gregory.clement@free-electrons.com>

For HWBM all buffers are allocated in mvneta_bm_construct() and in runtime
they are put into descriptors by hardware. There is no need to fill them
at this point.

Suggested-by: Marcin Wojtas <mw@semihalf.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Tested-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvneta.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 1b84f746d748..f5319c50f8d9 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -2784,14 +2784,14 @@ static int mvneta_rxq_init(struct mvneta_port *pp,
 		mvneta_rxq_buf_size_set(pp, rxq,
 					MVNETA_RX_BUF_SIZE(pp->pkt_size));
 		mvneta_rxq_bm_disable(pp, rxq);
+		mvneta_rxq_fill(pp, rxq, rxq->size);
 	} else {
 		mvneta_rxq_bm_enable(pp, rxq);
 		mvneta_rxq_long_pool_set(pp, rxq);
 		mvneta_rxq_short_pool_set(pp, rxq);
+		mvneta_rxq_non_occup_desc_add(pp, rxq, rxq->size);
 	}
 
-	mvneta_rxq_fill(pp, rxq, rxq->size);
-
 	return 0;
 }
 
-- 
git-series 0.8.10

^ permalink raw reply related

* [PATCH v6 net-next 3/7] net: mvneta: Use cacheable memory to store the rx buffer virtual address
From: Gregory CLEMENT @ 2016-12-01 17:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.dd374b7aaa358be0211d7ead81129a399fa692f4.1480611779.git-series.gregory.clement@free-electrons.com>

Until now the virtual address of the received buffer were stored in the
cookie field of the rx descriptor. However, this field is 32-bits only
which prevents to use the driver on a 64-bits architecture.

With this patch the virtual address is stored in an array not shared with
the hardware (no more need to use the DMA API). Thanks to this, it is
possible to use cache contrary to the access of the rx descriptor member.

The change is done in the swbm path only because the hwbm uses the cookie
field, this also means that currently the hwbm is not usable in 64-bits.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Reviewed-by: Jisheng Zhang <jszhang@marvell.com>
Tested-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvneta.c | 34 +++++++++++++++++++---------
 1 file changed, 24 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index f5319c50f8d9..92b9af14c352 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -561,6 +561,9 @@ struct mvneta_rx_queue {
 	u32 pkts_coal;
 	u32 time_coal;
 
+	/* Virtual address of the RX buffer */
+	void  **buf_virt_addr;
+
 	/* Virtual address of the RX DMA descriptors array */
 	struct mvneta_rx_desc *descs;
 
@@ -1573,10 +1576,14 @@ static void mvneta_tx_done_pkts_coal_set(struct mvneta_port *pp,
 
 /* Handle rx descriptor fill by setting buf_cookie and buf_phys_addr */
 static void mvneta_rx_desc_fill(struct mvneta_rx_desc *rx_desc,
-				u32 phys_addr, u32 cookie)
+				u32 phys_addr, void *virt_addr,
+				struct mvneta_rx_queue *rxq)
 {
-	rx_desc->buf_cookie = cookie;
+	int i;
+
 	rx_desc->buf_phys_addr = phys_addr;
+	i = rx_desc - rxq->descs;
+	rxq->buf_virt_addr[i] = virt_addr;
 }
 
 /* Decrement sent descriptors counter */
@@ -1781,7 +1788,8 @@ EXPORT_SYMBOL_GPL(mvneta_frag_free);
 
 /* Refill processing for SW buffer management */
 static int mvneta_rx_refill(struct mvneta_port *pp,
-			    struct mvneta_rx_desc *rx_desc)
+			    struct mvneta_rx_desc *rx_desc,
+			    struct mvneta_rx_queue *rxq)
 
 {
 	dma_addr_t phys_addr;
@@ -1799,7 +1807,7 @@ static int mvneta_rx_refill(struct mvneta_port *pp,
 		return -ENOMEM;
 	}
 
-	mvneta_rx_desc_fill(rx_desc, phys_addr, (u32)data);
+	mvneta_rx_desc_fill(rx_desc, phys_addr, data, rxq);
 	return 0;
 }
 
@@ -1861,7 +1869,7 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp,
 
 	for (i = 0; i < rxq->size; i++) {
 		struct mvneta_rx_desc *rx_desc = rxq->descs + i;
-		void *data = (void *)rx_desc->buf_cookie;
+		void *data = rxq->buf_virt_addr[i];
 
 		dma_unmap_single(pp->dev->dev.parent, rx_desc->buf_phys_addr,
 				 MVNETA_RX_BUF_SIZE(pp->pkt_size), DMA_FROM_DEVICE);
@@ -1894,12 +1902,13 @@ static int mvneta_rx_swbm(struct mvneta_port *pp, int rx_todo,
 		unsigned char *data;
 		dma_addr_t phys_addr;
 		u32 rx_status, frag_size;
-		int rx_bytes, err;
+		int rx_bytes, err, index;
 
 		rx_done++;
 		rx_status = rx_desc->status;
 		rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE);
-		data = (unsigned char *)rx_desc->buf_cookie;
+		index = rx_desc - rxq->descs;
+		data = rxq->buf_virt_addr[index];
 		phys_addr = rx_desc->buf_phys_addr;
 
 		if (!mvneta_rxq_desc_is_first_last(rx_status) ||
@@ -1938,7 +1947,7 @@ static int mvneta_rx_swbm(struct mvneta_port *pp, int rx_todo,
 		}
 
 		/* Refill processing */
-		err = mvneta_rx_refill(pp, rx_desc);
+		err = mvneta_rx_refill(pp, rx_desc, rxq);
 		if (err) {
 			netdev_err(dev, "Linux processing - Can't refill\n");
 			rxq->missed++;
@@ -2020,7 +2029,7 @@ static int mvneta_rx_hwbm(struct mvneta_port *pp, int rx_todo,
 		rx_done++;
 		rx_status = rx_desc->status;
 		rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE);
-		data = (unsigned char *)rx_desc->buf_cookie;
+		data = (u8 *)(uintptr_t)rx_desc->buf_cookie;
 		phys_addr = rx_desc->buf_phys_addr;
 		pool_id = MVNETA_RX_GET_BM_POOL_ID(rx_desc);
 		bm_pool = &pp->bm_priv->bm_pools[pool_id];
@@ -2716,7 +2725,7 @@ static int mvneta_rxq_fill(struct mvneta_port *pp, struct mvneta_rx_queue *rxq,
 
 	for (i = 0; i < num; i++) {
 		memset(rxq->descs + i, 0, sizeof(struct mvneta_rx_desc));
-		if (mvneta_rx_refill(pp, rxq->descs + i) != 0) {
+		if (mvneta_rx_refill(pp, rxq->descs + i, rxq) != 0) {
 			netdev_err(pp->dev, "%s:rxq %d, %d of %d buffs  filled\n",
 				__func__, rxq->id, i, num);
 			break;
@@ -3865,6 +3874,11 @@ static int mvneta_init(struct device *dev, struct mvneta_port *pp)
 		rxq->size = pp->rx_ring_size;
 		rxq->pkts_coal = MVNETA_RX_COAL_PKTS;
 		rxq->time_coal = MVNETA_RX_COAL_USEC;
+		rxq->buf_virt_addr = devm_kmalloc(pp->dev->dev.parent,
+						  rxq->size * sizeof(void *),
+						  GFP_KERNEL);
+		if (!rxq->buf_virt_addr)
+			return -ENOMEM;
 	}
 
 	return 0;
-- 
git-series 0.8.10

^ permalink raw reply related

* [PATCH v6 net-next 4/7] net: mvneta: Convert to be 64 bits compatible
From: Gregory CLEMENT @ 2016-12-01 17:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.dd374b7aaa358be0211d7ead81129a399fa692f4.1480611779.git-series.gregory.clement@free-electrons.com>

From: Marcin Wojtas <mw@semihalf.com>

Prepare the mvneta driver in order to be usable on the 64 bits platform
such as the Armada 3700.

[gregory.clement at free-electrons.com]: this patch was extract from a larger
one to ease review and maintenance.

Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Tested-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvneta.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 92b9af14c352..8ef03fb69bcd 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -296,6 +296,12 @@
 /* descriptor aligned size */
 #define MVNETA_DESC_ALIGNED_SIZE	32
 
+/* Number of bytes to be taken into account by HW when putting incoming data
+ * to the buffers. It is needed in case NET_SKB_PAD exceeds maximum packet
+ * offset supported in MVNETA_RXQ_CONFIG_REG(q) registers.
+ */
+#define MVNETA_RX_PKT_OFFSET_CORRECTION		64
+
 #define MVNETA_RX_PKT_SIZE(mtu) \
 	ALIGN((mtu) + MVNETA_MH_SIZE + MVNETA_VLAN_TAG_LEN + \
 	      ETH_HLEN + ETH_FCS_LEN,			     \
@@ -416,6 +422,7 @@ struct mvneta_port {
 	u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)];
 
 	u32 indir[MVNETA_RSS_LU_TABLE_SIZE];
+	u16 rx_offset_correction;
 };
 
 /* The mvneta_tx_desc and mvneta_rx_desc structures describe the
@@ -1807,6 +1814,7 @@ static int mvneta_rx_refill(struct mvneta_port *pp,
 		return -ENOMEM;
 	}
 
+	phys_addr += pp->rx_offset_correction;
 	mvneta_rx_desc_fill(rx_desc, phys_addr, data, rxq);
 	return 0;
 }
@@ -2782,7 +2790,7 @@ static int mvneta_rxq_init(struct mvneta_port *pp,
 	mvreg_write(pp, MVNETA_RXQ_SIZE_REG(rxq->id), rxq->size);
 
 	/* Set Offset */
-	mvneta_rxq_offset_set(pp, rxq, NET_SKB_PAD);
+	mvneta_rxq_offset_set(pp, rxq, NET_SKB_PAD - pp->rx_offset_correction);
 
 	/* Set coalescing pkts and time */
 	mvneta_rx_pkts_coal_set(pp, rxq, rxq->pkts_coal);
@@ -4033,6 +4041,13 @@ static int mvneta_probe(struct platform_device *pdev)
 
 	pp->rxq_def = rxq_def;
 
+	/* Set RX packet offset correction for platforms, whose
+	 * NET_SKB_PAD, exceeds 64B. It should be 64B for 64-bit
+	 * platforms and 0B for 32-bit ones.
+	 */
+	pp->rx_offset_correction =
+		max(0, NET_SKB_PAD - MVNETA_RX_PKT_OFFSET_CORRECTION);
+
 	pp->indir[0] = rxq_def;
 
 	pp->clk = devm_clk_get(&pdev->dev, "core");
-- 
git-series 0.8.10

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox