* [GIT PULL 2/3] ARM: dts: exynos: DT for v4.9, second round
From: Arnd Bergmann @ 2016-09-19 15:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474216788-17282-3-git-send-email-krzk@kernel.org>
On Sunday, September 18, 2016 6:39:47 PM CEST Krzysztof Kozlowski wrote:
> Samsung DeviceTree update for v4.9, second round:
> 1. Enable HDMI on Arndale Octa board.
> 2. Update list of clocks for FIMC-IS block on Exynos4x12.
> 3. Remove skeleton.dtsi thus fixing DT compiler warning:
> "Node /memory has a reg or ranges property, but no unit name"
> This is a tree-wide effort by various people. Javier Martinez Canillas did
> it for Exynos and S5PV210.
>
Pulled into next/dt, thanks!
Arnd
^ permalink raw reply
* [PATCH V6 4/5] PCI: thunder: Enable ACPI PCI controller for ThunderX pass2.x silicon version
From: Bjorn Helgaas @ 2016-09-19 15:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473449047-10499-5-git-send-email-tn@semihalf.com>
On Fri, Sep 09, 2016 at 09:24:06PM +0200, 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. Export PEM pci_thunder_pem_ops structure so it is visible to MCFG quirk
> code.
> 2. 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.
Is it really the case that silicon pass2.x has MCFG revision 1, and
silicon pass1.x has MCFG revision 2? That just seems backwards.
> Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
> ---
> drivers/acpi/pci_mcfg.c | 27 +++++++++++++++++++++++++++
> drivers/pci/host/pci-thunder-pem.c | 2 +-
> include/linux/pci-ecam.h | 4 ++++
> 3 files changed, 32 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
> index 2b8acc7..1f73d7b 100644
> --- a/drivers/acpi/pci_mcfg.c
> +++ b/drivers/acpi/pci_mcfg.c
> @@ -51,6 +51,33 @@ struct mcfg_fixup {
>
> static struct mcfg_fixup mcfg_quirks[] = {
> /* { OEM_ID, OEM_TABLE_ID, REV, DOMAIN, BUS_RANGE, cfgres, ops }, */
> +#ifdef CONFIG_PCI_HOST_THUNDER_PEM
> + /* SoC pass2.x */
> + { "CAVIUM", "THUNDERX", 1, 4, MCFG_BUS_ANY, &pci_thunder_pem_ops,
> + DEFINE_RES_MEM(0x88001f000000UL, 0x39 * SZ_16M) },
> + { "CAVIUM", "THUNDERX", 1, 5, MCFG_BUS_ANY, &pci_thunder_pem_ops,
> + DEFINE_RES_MEM(0x884057000000UL, 0x39 * SZ_16M) },
> + { "CAVIUM", "THUNDERX", 1, 6, MCFG_BUS_ANY, &pci_thunder_pem_ops,
> + DEFINE_RES_MEM(0x88808f000000UL, 0x39 * SZ_16M) },
> + { "CAVIUM", "THUNDERX", 1, 7, MCFG_BUS_ANY, &pci_thunder_pem_ops,
> + DEFINE_RES_MEM(0x89001f000000UL, 0x39 * SZ_16M) },
> + { "CAVIUM", "THUNDERX", 1, 8, MCFG_BUS_ANY, &pci_thunder_pem_ops,
> + DEFINE_RES_MEM(0x894057000000UL, 0x39 * SZ_16M) },
> + { "CAVIUM", "THUNDERX", 1, 9, MCFG_BUS_ANY, &pci_thunder_pem_ops,
> + DEFINE_RES_MEM(0x89808f000000UL, 0x39 * SZ_16M) },
> + { "CAVIUM", "THUNDERX", 1, 14, MCFG_BUS_ANY, &pci_thunder_pem_ops,
> + DEFINE_RES_MEM(0x98001f000000UL, 0x39 * SZ_16M) },
> + { "CAVIUM", "THUNDERX", 1, 15, MCFG_BUS_ANY, &pci_thunder_pem_ops,
> + DEFINE_RES_MEM(0x984057000000UL, 0x39 * SZ_16M) },
> + { "CAVIUM", "THUNDERX", 1, 16, MCFG_BUS_ANY, &pci_thunder_pem_ops,
> + DEFINE_RES_MEM(0x98808f000000UL, 0x39 * SZ_16M) },
> + { "CAVIUM", "THUNDERX", 1, 17, MCFG_BUS_ANY, &pci_thunder_pem_ops,
> + DEFINE_RES_MEM(0x99001f000000UL, 0x39 * SZ_16M) },
> + { "CAVIUM", "THUNDERX", 1, 18, MCFG_BUS_ANY, &pci_thunder_pem_ops,
> + DEFINE_RES_MEM(0x994057000000UL, 0x39 * SZ_16M) },
> + { "CAVIUM", "THUNDERX", 1, 19, MCFG_BUS_ANY, &pci_thunder_pem_ops,
> + DEFINE_RES_MEM(0x99808f000000UL, 0x39 * SZ_16M) },
> +#endif
> };
>
> static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
> diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c
> index b048761..d7c10cc 100644
> --- a/drivers/pci/host/pci-thunder-pem.c
> +++ b/drivers/pci/host/pci-thunder-pem.c
> @@ -367,7 +367,7 @@ static int thunder_pem_init(struct pci_config_window *cfg)
> return 0;
> }
>
> -static struct pci_ecam_ops pci_thunder_pem_ops = {
> +struct pci_ecam_ops pci_thunder_pem_ops = {
> .bus_shift = 24,
> .init = thunder_pem_init,
> .pci_ops = {
> diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
> index 7adad20..65505ea 100644
> --- a/include/linux/pci-ecam.h
> +++ b/include/linux/pci-ecam.h
> @@ -58,6 +58,10 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
> int where);
> /* default ECAM ops */
> extern struct pci_ecam_ops pci_generic_ecam_ops;
> +/* ECAM ops for known quirks */
> +#ifdef CONFIG_PCI_HOST_THUNDER_PEM
> +extern struct pci_ecam_ops pci_thunder_pem_ops;
> +#endif
>
> #ifdef CONFIG_PCI_HOST_GENERIC
> /* for DT-based PCI controllers that support ECAM */
> --
> 1.9.1
>
^ permalink raw reply
* [GIT PULL] omap dts updates for v4.9 merge window, part 2
From: Arnd Bergmann @ 2016-09-19 15:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160915172021.6u2zam4yd6vruub4@atomide.com>
On Thursday, September 15, 2016 10:20:22 AM CEST Tony Lindgren wrote:
> Part two of device tree changes for omaps for v4.9 merge window. This
> is mostly usability and non-critical fixes except for the addition of
> beagleboard-x15 rev B1 support:
>
> - Fix omap4 pandaboard SDIO WLAN latencies in idle mode by enabling wakeirq
>
> - Usability fixes for WLAN, USB, LEDs and power button on omap5 boards
>
> - Remove am57xx beagleboard-x15 pinmux configuration as the processor requires
> that it's done in IO isolation in bootloader except for MMC and DCAN
>
> - Add support for beagleboard-x15 rev B1 by moving most of the
> configuration to am57xx-beagle-x15-common.dtsi
>
> - Enable support for more than 2GB of memory for omap5 with LPAE with
> #address-cells
>
> - Fix omap3-gta04 backlight PWM frequency until the PWM driver
>
> - Revert am335x dts changes related to cpufreq as the driver changes
> still have not merged and the dts changes broke cpufreq
Pulled into next/dt, thanks!
Arnd
^ permalink raw reply
* [GIT PULL] DaVinci DTS updates for v4.9 (part 2)
From: Arnd Bergmann @ 2016-09-19 15:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <d231c316-a14b-1534-2bcd-29f0898b0b1c@ti.com>
On Thursday, September 15, 2016 8:14:22 PM CEST Sekhar Nori wrote:
> This pull request adds NAND support to
> DA850 based LCDK board.
>
>
Pulled into next/dt, thanks!
Arnd
^ permalink raw reply
* [GIT PULL] STi DT update for v4.9, round 3
From: Arnd Bergmann @ 2016-09-19 15:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <e51819f2-a354-7153-3b86-a92e99b85213@st.com>
On Friday, September 16, 2016 9:55:01 AM CEST Patrice Chotard wrote:
> Clock improvement for video playback
>
> This serie allows to increase video resolutions and make audio
> adjustment during a video playback for STiH407 family socs.
>
Pulled into next/dt, thanks!
Arnd
^ permalink raw reply
* [PATCH 4/4] drm/sun4i: dotclock: Round to closest clock rate
From: Chen-Yu Tsai @ 2016-09-19 15:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160918191648.GJ17518@lukather>
On Mon, Sep 19, 2016 at 3:16 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi,
>
> On Thu, Sep 15, 2016 at 11:14:02PM +0800, Chen-Yu Tsai wrote:
>> With display pixel clocks we want to have the closest possible clock
>> rate, to minimize timing and refresh rate skews. Whether the actual
>> clock rate is higher or lower than the requested rate is less important.
>>
>> Also check candidates against the requested rate, rather than the
>> ideal parent rate, the varying dividers also influence the difference
>> between the requested rate and the rounded rate.
>>
>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>> ---
>> drivers/gpu/drm/sun4i/sun4i_dotclock.c | 3 ++-
>> 1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
>> index 3eb99784f371..d401156490f3 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c
>> +++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
>> @@ -90,7 +90,8 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
>> goto out;
>> }
>>
>> - if ((rounded < ideal) && (rounded > best_parent)) {
>> + if (abs(rate - rounded / i) <
>> + abs(rate - best_parent / best_div)) {
>
> I'm not sure what you're trying to do here. Why is the divider involved?
Say you want the dotclock at X, so you try Y = 6 ~ 127 for the divider.
Now you're asking the CCF to round (X*Y).
In the original code, you were comparing the result of rounding (X * Y).
if ((rounded < ideal) && (rounded > best_parent)) {
best_parent = rounded;
best_div = i;
}
where ideal = X * Y (i in the code). Given the divider increases in
the loop, you are actually not closing in on the best divider, but the
highest divider that doesn't give a higher rate than the ideal rate.
Including the divider makes it compare the actual dot clock frequency
if a given divider was used.
Does this makes sense? Explaining this kind of makes my head spin...
Regards
ChenYu
>
> Maxime
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
^ permalink raw reply
* [GIT PULL] STi DT update for v4.9
From: Arnd Bergmann @ 2016-09-19 15:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <ede2d2b6-7e0c-f31e-72bd-06aae5838327@st.com>
On Wednesday, September 14, 2016 3:15:22 PM CEST Patrice Chotard wrote:
> STi dts update:
>
> Update gpio-cells and gpio specifier for STiH415/416
> Add PWM capture support for STiH416 and STiH407 family
> Add USB3 support for B2260
> Add HVA support for STiH410
> Add clk_ignore_unused in bootargs of B2260
> Add Flexible Direct Memory Access (FDMA) support for STiH407 family
> Add internal audio codec IP spport for STiH407 family
> Add uniperif player/reader IP blocks for STiH407 family
>
>
Pulled into next/dt, thanks!
Arnd
^ permalink raw reply
* [GIT PULL] Amlogic DT updates for v4.9
From: Arnd Bergmann @ 2016-09-19 15:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <7h1t0mmk3o.fsf@baylibre.com>
On Wednesday, September 14, 2016 11:06:51 AM CEST Kevin Hilman wrote:
> Amlogic DT updates for v4.9
> - add PWM support
>
Pulled into next/dt, thanks!
Arnd
^ permalink raw reply
* next-20160914 build: 2 failures 3 warnings (next-20160914)
From: Grygorii Strashko @ 2016-09-19 15:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474883226.Je8NqnULCh@wuerfel>
On 09/19/2016 02:30 PM, Arnd Bergmann wrote:
> On Monday, September 19, 2016 11:54:29 AM CEST Mark Brown wrote:
>> On Mon, Sep 19, 2016 at 12:31:04PM +0200, Arnd Bergmann wrote:
>>
>>> My guess is that this is indeed the correct fix, but I don't understand
>>> at all what the function does, and Marcin Niestroj said the same thing,
>>> he just copied the code from a driver that is always built-in.
>>
>> Yes, most of the code is copied from regmap-irq. Setting the parent is
>> needed for edge triggered interrupts that don't latch state when
>> disabled but isn't needed in the general case.
>
> I found this in the tps65217 data sheet:
>
> 9.3.7 Interrupt Pin (nINT)
> The interrupt pin is used to signal any event or fault
> condition to the host processor. Whenever a fault or event
> occurs in the IC the corresponding interrupt bit is set in
> the INT register, and the open-drain output is pulled low.
> The nINT pin is released (returns to Hi-Z state) and fault
> bits are cleared when the INT register is read by the
> host. However, if a failure persists, the corresponding
> INT bit remains set and the nINT pin is pulled low again
> after a maximum of 32 ?s.
>
> Interrupt events include pushbutton pressed/released, USB
> and AC voltage status change.
> The MASK bits in the INT register are used to mask events
> from generating interrupts. The MASK settings affect the
> nINT pin only and have no impact on protection and
> monitor circuits themselves. Note that persisting event
> conditions such as ISINK enabled shutdown can cause the
> nINT pin to be pulled low for an extended period of
> time which can keep the host in a loop trying to resolve
> the interrupt. If this behavior is not desired, set the
> corresponding mask bit after receiving the interrupt and
> keep polling the INT register to see when the event
> condition has disappeared. Then unmask the interrupt bit
> again.
>
> Does this tell us if it's needed or not?
>
The irq_set_parent() is required for proper supporting of lazy irq disabling
for threaded nested irqs and allow them to be re-triggered in the following case:
driverX:
disable(nested_irq);
...
parent irq triggered
|- handle_nested_irq()
|- mark nested_irq with IRQS_PENDING
...
driverX:
enable(nested_irq);
|- if IRQS_PENDING -> resend parent_irq [*], because nested threaded irq can't
be resend by itself
[*] if parent_irq is not set the IRQS_PENDING status will be ignored and irq might be lost.
Also, it was "mandatory" to be done before commit 75a06189fc5
"genirq: Prevent resend to interrupts marked IRQ_NESTED_THREAD"
which made setting of parent_irq optional.
So, if is it required or not depends not only on HW, but, rather, on MFD drivers implementation
(Interrupt controller and MFD cell drivers).
--
regards,
-grygorii
^ permalink raw reply
* [GIT PULL] ARM: mvebu: dt for v4.9 (#2)
From: Arnd Bergmann @ 2016-09-19 15:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <87eg4mbiqn.fsf@free-electrons.com>
On Wednesday, September 14, 2016 5:31:44 PM CEST Gregory CLEMENT wrote:
> mvebu dt for 4.9 (part 2)
>
> - convert orion5x based SoC Netgear WNR854T to devicetree
> - remove obsolete orion-gpio binding description
>
>
Pulled into next/dt, thanks!
Arnd
^ permalink raw reply
* [GIT PULL] ARM: at91: dt for 4.9
From: Arnd Bergmann @ 2016-09-19 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160914082812.tmlrrqwkeudcybui@piout.net>
On Wednesday, September 14, 2016 10:28:12 AM CEST Alexandre Belloni wrote:
> DT Changes for 4.9:
> - add ETM and ETB nodes on sama5d2
>
Pulled into next/dt, thanks!
Arnd
^ permalink raw reply
* [PATCH 3/3] i2c: bcm2835: Use ratelimited logging on transfer errors
From: Noralf Trønnes @ 2016-09-19 15:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474298777-5858-1-git-send-email-noralf@tronnes.org>
Writing to an AT24C32 generates on average 2x i2c transfer errors per
32-byte page write. Which amounts to a lot for a 4k write. This is due
to the fact that the chip doesn't respond during it's internal write
cycle when the at24 driver tries and retries the next write.
Reduce this flooding of the log by using dev_err_ratelimited().
Signed-off-by: Noralf Tr?nnes <noralf@tronnes.org>
---
drivers/i2c/busses/i2c-bcm2835.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index b3ce565..dc0a5d5 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -274,7 +274,8 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
(msg->flags & I2C_M_IGNORE_NAK))
return 0;
- dev_err(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err);
+ dev_err_ratelimited(i2c_dev->dev, "i2c transfer failed: %x\n",
+ i2c_dev->msg_err);
if (i2c_dev->msg_err & BCM2835_I2C_S_ERR)
return -EREMOTEIO;
--
2.8.2
^ permalink raw reply related
* [PATCH 2/3] i2c: bcm2835: Add support for combined write-read transfer
From: Noralf Trønnes @ 2016-09-19 15:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474298777-5858-1-git-send-email-noralf@tronnes.org>
Some SMBus protocols use Repeated Start Condition to switch from write
mode to read mode. Devices like MMA8451 won't work without it.
When downstream implemented support for this in i2c-bcm2708, it broke
support for some devices, so a module parameter was added and combined
transfer was disabled by default.
See https://github.com/raspberrypi/linux/issues/599
It doesn't seem to have been any investigation into what the problem
really was. Later there was added a timeout on the polling loop.
One of the devices mentioned to partially stop working was DS1307.
I have run thousands of transfers to a DS1307 (rtc), MMA8451 (accel)
and AT24C32 (eeprom) in parallel without problems.
Signed-off-by: Noralf Tr?nnes <noralf@tronnes.org>
---
drivers/i2c/busses/i2c-bcm2835.c | 107 +++++++++++++++++++++++++++++++++++----
1 file changed, 98 insertions(+), 9 deletions(-)
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index f283b71..b3ce565 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -154,8 +154,39 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
return IRQ_NONE;
}
+/*
+ * Repeated Start Condition (Sr)
+ * The BCM2835 ARM Peripherals datasheet mentions a way to trigger a Sr when it
+ * talks about reading from a slave with 10 bit address. This is achieved by
+ * issuing a write (without enabling interrupts), poll the I2CS.TA flag and
+ * wait for it to be set, and then issue a read.
+ * https://github.com/raspberrypi/linux/issues/254 shows how the firmware does
+ * it and states that it's a workaround for a problem in the state machine.
+ * This is the comment in the firmware code:
+ *
+ * The I2C peripheral samples the values for rw_bit and xfer_count in the
+ * IDLE state if start is set.
+ *
+ * We want to generate a ReSTART not a STOP at the end of the TX phase. In
+ * order to do that we must ensure the state machine goes
+ * RACK1 -> RACK2 -> SRSTRT1 (not RACK1 -> RACK2 -> SSTOP1).
+ *
+ * So, in the RACK2 state when (TX) xfer_count==0 we must therefore have
+ * already set, ready to be sampled:
+ * READ; rw_bit <= I2CC bit 0 - must be "read"
+ * ST; start <= I2CC bit 7 - must be "Go" in order to not issue STOP
+ * DLEN; xfer_count <= I2CDLEN - must be equal to our read amount
+ *
+ * The plan to do this is:
+ * 1. Start the sub-address write, but don't let it finish (keep
+ * xfer_count > 0)
+ * 2. Populate READ, DLEN and ST in preparation for ReSTART read sequence
+ * 3. Let TX finish (write the rest of the data)
+ * 4. Read back data as it arrives
+ */
+
static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
- struct i2c_msg *msg)
+ struct i2c_msg *msg, struct i2c_msg *msg2)
{
u32 c;
unsigned long time_left;
@@ -167,21 +198,70 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR);
- if (msg->flags & I2C_M_RD) {
- c = BCM2835_I2C_C_READ | BCM2835_I2C_C_INTR;
- } else {
- c = BCM2835_I2C_C_INTT;
+ if (!(msg->flags & I2C_M_RD))
bcm2835_fill_txfifo(i2c_dev);
- }
- c |= BCM2835_I2C_C_ST | BCM2835_I2C_C_INTD | BCM2835_I2C_C_I2CEN;
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr);
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len);
- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c);
+
+ if (!msg2) {
+ if (msg->flags & I2C_M_RD)
+ c = BCM2835_I2C_C_READ | BCM2835_I2C_C_INTR;
+ else
+ c = BCM2835_I2C_C_INTT;
+
+ c |= BCM2835_I2C_C_ST | BCM2835_I2C_C_INTD |
+ BCM2835_I2C_C_I2CEN;
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c);
+ } else {
+ unsigned long flags;
+ u32 stat, err = 0;
+
+ local_irq_save(flags);
+
+ /* Start write message */
+ c = BCM2835_I2C_C_ST | BCM2835_I2C_C_I2CEN;
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c);
+
+ /* Wait for the transfer to become active */
+ for (time_left = 100; time_left > 0; time_left--) {
+ stat = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
+
+ err = stat & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR);
+ if (err)
+ break;
+
+ if (stat & BCM2835_I2C_S_TA)
+ break;
+ }
+
+ if (err || !time_left) {
+ i2c_dev->msg_err = err;
+ local_irq_restore(flags);
+ goto error;
+ }
+
+ /* Start read message */
+ i2c_dev->curr_msg = msg2;
+ i2c_dev->msg_buf = msg2->buf;
+ i2c_dev->msg_buf_remaining = msg2->len;
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg2->len);
+
+ c = BCM2835_I2C_C_READ | BCM2835_I2C_C_INTR |
+ BCM2835_I2C_C_INTD | BCM2835_I2C_C_ST |
+ BCM2835_I2C_C_I2CEN;
+
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c);
+
+ local_irq_restore(flags);
+ }
time_left = wait_for_completion_timeout(&i2c_dev->completion,
BCM2835_I2C_TIMEOUT);
+error:
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR);
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, BCM2835_I2C_S_CLKT |
+ BCM2835_I2C_S_ERR | BCM2835_I2C_S_DONE);
if (!time_left) {
dev_err(i2c_dev->dev, "i2c transfer timed out\n");
return -ETIMEDOUT;
@@ -209,8 +289,17 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
int i;
int ret = 0;
+ /* Combined write-read to the same address (smbus) */
+ if (num == 2 && (msgs[0].addr == msgs[1].addr) &&
+ !(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
+ (msgs[0].len <= 16)) {
+ ret = bcm2835_i2c_xfer_msg(i2c_dev, &msgs[0], &msgs[1]);
+
+ return ret ? ret : 2;
+ }
+
for (i = 0; i < num; i++) {
- ret = bcm2835_i2c_xfer_msg(i2c_dev, &msgs[i]);
+ ret = bcm2835_i2c_xfer_msg(i2c_dev, &msgs[i], NULL);
if (ret)
break;
}
--
2.8.2
^ permalink raw reply related
* [PATCH 1/3] i2c: bcm2835: Fix hang for writing messages larger than 16 bytes
From: Noralf Trønnes @ 2016-09-19 15:26 UTC (permalink / raw)
To: linux-arm-kernel
Writing messages larger than the FIFO size results in a hang, rendering
the machine unusable. This is because the RXD status flag is set on the
first interrupt which results in bcm2835_drain_rxfifo() stealing bytes
from the buffer. The controller continues to trigger interrupts waiting
for the missing bytes, but bcm2835_fill_txfifo() has none to give.
In this situation wait_for_completion_timeout() apparently is unable to
stop the madness.
The BCM2835 ARM Peripherals datasheet has this to say about the flags:
TXD: is set when the FIFO has space for at least one byte of data.
RXD: is set when the FIFO contains at least one byte of data.
TXW: is set during a write transfer and the FIFO is less than full.
RXR: is set during a read transfer and the FIFO is or more full.
Implementing the logic from the downstream i2c-bcm2708 driver solved
the hang problem.
Signed-off-by: Noralf Tr?nnes <noralf@tronnes.org>
---
drivers/i2c/busses/i2c-bcm2835.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index d4f3239..f283b71 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -64,6 +64,7 @@ struct bcm2835_i2c_dev {
int irq;
struct i2c_adapter adapter;
struct completion completion;
+ struct i2c_msg *curr_msg;
u32 msg_err;
u8 *msg_buf;
size_t msg_buf_remaining;
@@ -126,14 +127,13 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
return IRQ_HANDLED;
}
- if (val & BCM2835_I2C_S_RXD) {
- bcm2835_drain_rxfifo(i2c_dev);
- if (!(val & BCM2835_I2C_S_DONE))
- return IRQ_HANDLED;
- }
-
if (val & BCM2835_I2C_S_DONE) {
- if (i2c_dev->msg_buf_remaining)
+ if (i2c_dev->curr_msg->flags & I2C_M_RD) {
+ bcm2835_drain_rxfifo(i2c_dev);
+ val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
+ }
+
+ if ((val & BCM2835_I2C_S_RXD) || i2c_dev->msg_buf_remaining)
i2c_dev->msg_err = BCM2835_I2C_S_LEN;
else
i2c_dev->msg_err = 0;
@@ -141,11 +141,16 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
return IRQ_HANDLED;
}
- if (val & BCM2835_I2C_S_TXD) {
+ if (val & BCM2835_I2C_S_TXW) {
bcm2835_fill_txfifo(i2c_dev);
return IRQ_HANDLED;
}
+ if (val & BCM2835_I2C_S_RXR) {
+ bcm2835_drain_rxfifo(i2c_dev);
+ return IRQ_HANDLED;
+ }
+
return IRQ_NONE;
}
@@ -155,6 +160,7 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
u32 c;
unsigned long time_left;
+ i2c_dev->curr_msg = msg;
i2c_dev->msg_buf = msg->buf;
i2c_dev->msg_buf_remaining = msg->len;
reinit_completion(&i2c_dev->completion);
--
2.8.2
^ permalink raw reply related
* [PATCH v3 2/8] scpi: Add alternative legacy structures, functions and macros
From: Sudeep Holla @ 2016-09-19 15:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473262477-18045-3-git-send-email-narmstrong@baylibre.com>
On 07/09/16 16:34, Neil Armstrong wrote:
> In order to support the legacy SCPI protocol variant, add back the structures
> and macros that varies against the final specification.
> Add indirection table for legacy commands.
> Add bitmap field for channel selection
> Add support for legacy in scpi_send_message.
>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
> drivers/firmware/arm_scpi.c | 218 ++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 211 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
> index 9a87687..9ba1020 100644
> --- a/drivers/firmware/arm_scpi.c
> +++ b/drivers/firmware/arm_scpi.c
[..]
> @@ -336,6 +424,39 @@ static void scpi_handle_remote_msg(struct mbox_client *c, void *msg)
> scpi_process_cmd(ch, cmd);
> }
>
> +static void legacy_scpi_process_cmd(struct scpi_chan *ch)
> +{
> + unsigned long flags;
> + struct scpi_xfer *t;
> +
> + spin_lock_irqsave(&ch->rx_lock, flags);
> + if (list_empty(&ch->rx_pending)) {
> + spin_unlock_irqrestore(&ch->rx_lock, flags);
> + return;
> + }
> +
> + t = list_first_entry(&ch->rx_pending, struct scpi_xfer, node);
> + list_del(&t->node);
> +
This is a bad assumption that it will be always first. The legacy SCPI
did support multiple commands at a time and they can be reordered when
SCP responds to them. Except this it's almost same scpi_process_cmd. You
should be able to use it as is if you pass the command.
> + /* check if wait_for_completion is in progress or timed-out */
> + if (t && !completion_done(&t->done)) {
> + struct legacy_scpi_shared_mem *mem = ch->rx_payload;
> + unsigned int len = t->rx_len;
> +
> + t->status = le32_to_cpu(mem->status);
> + memcpy_fromio(t->rx_buf, mem->payload, len);
> + complete(&t->done);
> + }
> + spin_unlock_irqrestore(&ch->rx_lock, flags);
> +}
> +
> +static void legacy_scpi_handle_remote_msg(struct mbox_client *c, void *_msg)
> +{
> + struct scpi_chan *ch = container_of(c, struct scpi_chan, cl);
> +
> + legacy_scpi_process_cmd(ch);
You will get the command in *_msg IIRC. So you can just pass that to
scpi_process_cmd. You can even reuse scpi_handle_remote_msg
diff --git i/drivers/firmware/arm_scpi.c w/drivers/firmware/arm_scpi.c
index edf1a3327041..165f2fc3b627 100644
--- i/drivers/firmware/arm_scpi.c
+++ w/drivers/firmware/arm_scpi.c
@@ -419,7 +419,12 @@ static void scpi_handle_remote_msg(struct
mbox_client *c, void *msg)
{
struct scpi_chan *ch = container_of(c, struct scpi_chan, cl);
struct scpi_shared_mem *mem = ch->rx_payload;
- u32 cmd = le32_to_cpu(mem->command);
+ u32 cmd;
+
+ if (ch->is_legacy)
+ cmd = *(u32 *)msg;
+ else
+ cmd = le32_to_cpu(mem->command);
scpi_process_cmd(ch, cmd);
}
> +}
> +
> static void scpi_tx_prepare(struct mbox_client *c, void *msg)
> {
> unsigned long flags;
> @@ -356,6 +477,21 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg)
> mem->command = cpu_to_le32(t->cmd);
> }
>
> +static void legacy_scpi_tx_prepare(struct mbox_client *c, void *msg)
> +{
> + unsigned long flags;
> + struct scpi_xfer *t = msg;
> + struct scpi_chan *ch = container_of(c, struct scpi_chan, cl);
> +
> + if (t->tx_buf)
> + memcpy_toio(ch->tx_payload, t->tx_buf, t->tx_len);
> + if (t->rx_buf) {
> + spin_lock_irqsave(&ch->rx_lock, flags);
> + list_add_tail(&t->node, &ch->rx_pending);
> + spin_unlock_irqrestore(&ch->rx_lock, flags);
> + }
> +}
Again here the only difference is token addition. I think we should
retain that as it's helpful in debugging and I don't think it will have
any issues. Worst case we can make it conditional but let's check if we
can retain it first.
> @@ -386,15 +522,25 @@ static int scpi_send_message(u8 cmd, void *tx_buf, unsigned int tx_len,
> struct scpi_xfer *msg;
> struct scpi_chan *scpi_chan;
>
> - chan = atomic_inc_return(&scpi_info->next_chan) % scpi_info->num_chans;
> + if (scpi_info->is_legacy)
> + chan = test_bit(cmd, scpi_info->cmd_priority) ? 1 : 0;
> + else
> + chan = atomic_inc_return(&scpi_info->next_chan) %
> + scpi_info->num_chans;
> scpi_chan = scpi_info->channels + chan;
>
> msg = get_scpi_xfer(scpi_chan);
> if (!msg)
> return -ENOMEM;
>
> - msg->slot = BIT(SCPI_SLOT);
> - msg->cmd = PACK_SCPI_CMD(cmd, tx_len);
> + if (scpi_info->is_legacy) {
> + mutex_lock(&scpi_chan->xfers_lock);
Why does legacy need a different locking scheme ?
[...]
> @@ -635,6 +804,24 @@ static int scpi_sensor_get_value(u16 sensor, u64 *val)
> return ret;
> }
>
> +static int legacy_scpi_sensor_get_value(u16 sensor, u64 *val)
> +{
> + __le16 id = cpu_to_le16(sensor);
> + struct sensor_value buf;
> + int ret;
> +
> + ret = check_cmd(CMD_SENSOR_VALUE);
> + if (ret)
> + return ret;
> +
> + ret = scpi_send_message(scpi_info->scpi_cmds[CMD_SENSOR_VALUE],
> + &id, sizeof(id), &buf, sizeof(buf));
> + if (!ret)
> + *val = (u64)le32_to_cpu(buf.lo_val);
> +
This is not needed as it's backward compatible as discussed before.
Any particular reason you retained it here ?
--
Regards,
Sudeep
^ permalink raw reply related
* [PATCH 8/8] crypto: omap-sham: shrink the internal buffer size
From: Tero Kristo @ 2016-09-19 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474298539-23897-1-git-send-email-t-kristo@ti.com>
The current internal buffer size is way too large for crypto core, so
shrink it to be smaller. This makes the buffer to fit into the space
reserved for the export/import buffers also.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
drivers/crypto/omap-sham.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 8eefd79..d0b16e5 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -135,7 +135,7 @@
#define OMAP_ALIGN_MASK (sizeof(u32)-1)
#define OMAP_ALIGNED __attribute__((aligned(sizeof(u32))))
-#define BUFLEN PAGE_SIZE
+#define BUFLEN SHA512_BLOCK_SIZE
#define OMAP_SHA_DMA_THRESHOLD 256
struct omap_sham_dev;
--
1.9.1
^ permalink raw reply related
* [PATCH 7/8] crypto: omap-sham: add support for export/import
From: Tero Kristo @ 2016-09-19 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474298539-23897-1-git-send-email-t-kristo@ti.com>
Now that the driver has been converted to use scatterlists for data
handling, add proper implementation for the export/import stubs also.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
drivers/crypto/omap-sham.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 412559e..8eefd79 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -1418,12 +1418,21 @@ static void omap_sham_cra_exit(struct crypto_tfm *tfm)
static int omap_sham_export(struct ahash_request *req, void *out)
{
- return -ENOTSUPP;
+ struct omap_sham_reqctx *rctx = ahash_request_ctx(req);
+
+ memcpy(out, rctx, sizeof(*rctx) + rctx->bufcnt);
+
+ return 0;
}
static int omap_sham_import(struct ahash_request *req, const void *in)
{
- return -ENOTSUPP;
+ struct omap_sham_reqctx *rctx = ahash_request_ctx(req);
+ const struct omap_sham_reqctx *ctx_in = in;
+
+ memcpy(rctx, in, sizeof(*rctx) + ctx_in->bufcnt);
+
+ return 0;
}
static struct ahash_alg algs_sha1_md5[] = {
@@ -2083,7 +2092,8 @@ static int omap_sham_probe(struct platform_device *pdev)
alg = &dd->pdata->algs_info[i].algs_list[j];
alg->export = omap_sham_export;
alg->import = omap_sham_import;
- alg->halg.statesize = sizeof(struct omap_sham_reqctx);
+ alg->halg.statesize = sizeof(struct omap_sham_reqctx) +
+ BUFLEN;
err = crypto_register_ahash(alg);
if (err)
goto err_algs;
--
1.9.1
^ permalink raw reply related
* [PATCH 6/8] crypto: omap-sham: convert driver logic to use sgs for data xmit
From: Tero Kristo @ 2016-09-19 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474298539-23897-1-git-send-email-t-kristo@ti.com>
Currently, the internal buffer has been used for data transmission. Change
this so that scatterlists are used instead, and change the driver to
actually use the previously introduced helper functions for scatterlist
preparation.
This patch also removes the old buffer handling code which is no longer
needed.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
drivers/crypto/omap-sham.c | 344 ++++++++++-----------------------------------
1 file changed, 74 insertions(+), 270 deletions(-)
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 5c95bf9..412559e 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -116,7 +116,6 @@
#define FLAGS_SGS_ALLOCED 10
/* context flags */
#define FLAGS_FINUP 16
-#define FLAGS_SG 17
#define FLAGS_MODE_SHIFT 18
#define FLAGS_MODE_MASK (SHA_REG_MODE_ALGO_MASK << FLAGS_MODE_SHIFT)
@@ -150,13 +149,11 @@ struct omap_sham_reqctx {
size_t digcnt;
size_t bufcnt;
size_t buflen;
- dma_addr_t dma_addr;
/* walk state */
struct scatterlist *sg;
struct scatterlist sgl[2];
- struct scatterlist sgl_tmp;
- unsigned int offset; /* offset in current sg */
+ int offset; /* offset in current sg */
int sg_len;
unsigned int total; /* total request */
@@ -516,12 +513,14 @@ static int omap_sham_poll_irq_omap4(struct omap_sham_dev *dd)
SHA_REG_IRQSTATUS_INPUT_RDY);
}
-static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
- size_t length, int final)
+static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, size_t length,
+ int final)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
int count, len32, bs32, offset = 0;
- const u32 *buffer = (const u32 *)buf;
+ const u32 *buffer;
+ int mlen;
+ struct sg_mapping_iter mi;
dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n",
ctx->digcnt, length, final);
@@ -531,6 +530,7 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
/* should be non-zero before next lines to disable clocks later */
ctx->digcnt += length;
+ ctx->total -= length;
if (final)
set_bit(FLAGS_FINAL, &dd->flags); /* catch last interrupt */
@@ -540,16 +540,35 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
len32 = DIV_ROUND_UP(length, sizeof(u32));
bs32 = get_block_size(ctx) / sizeof(u32);
+ sg_miter_start(&mi, ctx->sg, ctx->sg_len,
+ SG_MITER_FROM_SG | SG_MITER_ATOMIC);
+
+ mlen = 0;
+
while (len32) {
if (dd->pdata->poll_irq(dd))
return -ETIMEDOUT;
- for (count = 0; count < min(len32, bs32); count++, offset++)
+ for (count = 0; count < min(len32, bs32); count++, offset++) {
+ if (!mlen) {
+ sg_miter_next(&mi);
+ mlen = mi.length;
+ if (!mlen) {
+ pr_err("sg miter failure.\n");
+ return -EINVAL;
+ }
+ offset = 0;
+ buffer = mi.addr;
+ }
omap_sham_write(dd, SHA_REG_DIN(dd, count),
buffer[offset]);
+ mlen -= 4;
+ }
len32 -= min(len32, bs32);
}
+ sg_miter_stop(&mi);
+
return -EINPROGRESS;
}
@@ -561,22 +580,27 @@ static void omap_sham_dma_callback(void *param)
tasklet_schedule(&dd->done_task);
}
-static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
- size_t length, int final, int is_sg)
+static int omap_sham_xmit_dma(struct omap_sham_dev *dd, size_t length,
+ int final)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
struct dma_async_tx_descriptor *tx;
struct dma_slave_config cfg;
- int len32, ret, dma_min = get_block_size(ctx);
+ int ret;
dev_dbg(dd->dev, "xmit_dma: digcnt: %d, length: %d, final: %d\n",
ctx->digcnt, length, final);
+ if (!dma_map_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE)) {
+ dev_err(dd->dev, "dma_map_sg error\n");
+ return -EINVAL;
+ }
+
memset(&cfg, 0, sizeof(cfg));
cfg.dst_addr = dd->phys_base + SHA_REG_DIN(dd, 0);
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cfg.dst_maxburst = dma_min / DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.dst_maxburst = get_block_size(ctx) / DMA_SLAVE_BUSWIDTH_4_BYTES;
ret = dmaengine_slave_config(dd->dma_lch, &cfg);
if (ret) {
@@ -584,31 +608,12 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
return ret;
}
- len32 = DIV_ROUND_UP(length, dma_min) * dma_min;
-
- if (is_sg) {
- /*
- * The SG entry passed in may not have the 'length' member
- * set correctly so use a local SG entry (sgl_tmp) with the
- * proper value for 'length' instead. If this is not done,
- * the dmaengine may try to DMA the incorrect amount of data.
- */
- sg_init_table(&ctx->sgl_tmp, 1);
- sg_assign_page(&ctx->sgl_tmp, sg_page(ctx->sg));
- ctx->sgl_tmp.offset = ctx->sg->offset;
- sg_dma_len(&ctx->sgl_tmp) = len32;
- sg_dma_address(&ctx->sgl_tmp) = sg_dma_address(ctx->sg);
-
- tx = dmaengine_prep_slave_sg(dd->dma_lch, &ctx->sgl_tmp, 1,
- DMA_MEM_TO_DEV,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- } else {
- tx = dmaengine_prep_slave_single(dd->dma_lch, dma_addr, len32,
- DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- }
+ tx = dmaengine_prep_slave_sg(dd->dma_lch, ctx->sg, ctx->sg_len,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!tx) {
- dev_err(dd->dev, "prep_slave_sg/single() failed\n");
+ dev_err(dd->dev, "prep_slave_sg failed\n");
return -EINVAL;
}
@@ -618,6 +623,7 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
dd->pdata->write_ctrl(dd, length, final, 1);
ctx->digcnt += length;
+ ctx->total -= length;
if (final)
set_bit(FLAGS_FINAL, &dd->flags); /* catch last interrupt */
@@ -886,208 +892,13 @@ static int omap_sham_prepare_request(struct ahash_request *req, bool update)
return 0;
}
-static size_t omap_sham_append_buffer(struct omap_sham_reqctx *ctx,
- const u8 *data, size_t length)
-{
- size_t count = min(length, ctx->buflen - ctx->bufcnt);
-
- count = min(count, ctx->total);
- if (count <= 0)
- return 0;
- memcpy(ctx->buffer + ctx->bufcnt, data, count);
- ctx->bufcnt += count;
-
- return count;
-}
-
-static size_t omap_sham_append_sg(struct omap_sham_reqctx *ctx)
-{
- size_t count;
- const u8 *vaddr;
-
- while (ctx->sg) {
- vaddr = kmap_atomic(sg_page(ctx->sg));
- vaddr += ctx->sg->offset;
-
- count = omap_sham_append_buffer(ctx,
- vaddr + ctx->offset,
- ctx->sg->length - ctx->offset);
-
- kunmap_atomic((void *)vaddr);
-
- if (!count)
- break;
- ctx->offset += count;
- ctx->total -= count;
- if (ctx->offset == ctx->sg->length) {
- ctx->sg = sg_next(ctx->sg);
- if (ctx->sg)
- ctx->offset = 0;
- else
- ctx->total = 0;
- }
- }
-
- return 0;
-}
-
-static int omap_sham_xmit_dma_map(struct omap_sham_dev *dd,
- struct omap_sham_reqctx *ctx,
- size_t length, int final)
-{
- int ret;
-
- ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, ctx->buflen,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
- dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen);
- return -EINVAL;
- }
-
- ctx->flags &= ~BIT(FLAGS_SG);
-
- ret = omap_sham_xmit_dma(dd, ctx->dma_addr, length, final, 0);
- if (ret != -EINPROGRESS)
- dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen,
- DMA_TO_DEVICE);
-
- return ret;
-}
-
-static int omap_sham_update_dma_slow(struct omap_sham_dev *dd)
-{
- struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
- unsigned int final;
- size_t count;
-
- omap_sham_append_sg(ctx);
-
- final = (ctx->flags & BIT(FLAGS_FINUP)) && !ctx->total;
-
- dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: %d, final: %d\n",
- ctx->bufcnt, ctx->digcnt, final);
-
- if (final || (ctx->bufcnt == ctx->buflen && ctx->total)) {
- count = ctx->bufcnt;
- ctx->bufcnt = 0;
- return omap_sham_xmit_dma_map(dd, ctx, count, final);
- }
-
- return 0;
-}
-
-/* Start address alignment */
-#define SG_AA(sg) (IS_ALIGNED(sg->offset, sizeof(u32)))
-/* SHA1 block size alignment */
-#define SG_SA(sg, bs) (IS_ALIGNED(sg->length, bs))
-
-static int omap_sham_update_dma_start(struct omap_sham_dev *dd)
-{
- struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
- unsigned int length, final, tail;
- struct scatterlist *sg;
- int ret, bs;
-
- if (!ctx->total)
- return 0;
-
- if (ctx->bufcnt || ctx->offset)
- return omap_sham_update_dma_slow(dd);
-
- /*
- * Don't use the sg interface when the transfer size is less
- * than the number of elements in a DMA frame. Otherwise,
- * the dmaengine infrastructure will calculate that it needs
- * to transfer 0 frames which ultimately fails.
- */
- if (ctx->total < get_block_size(ctx))
- return omap_sham_update_dma_slow(dd);
-
- dev_dbg(dd->dev, "fast: digcnt: %d, bufcnt: %u, total: %u\n",
- ctx->digcnt, ctx->bufcnt, ctx->total);
-
- sg = ctx->sg;
- bs = get_block_size(ctx);
-
- if (!SG_AA(sg))
- return omap_sham_update_dma_slow(dd);
-
- if (!sg_is_last(sg) && !SG_SA(sg, bs))
- /* size is not BLOCK_SIZE aligned */
- return omap_sham_update_dma_slow(dd);
-
- length = min(ctx->total, sg->length);
-
- if (sg_is_last(sg)) {
- if (!(ctx->flags & BIT(FLAGS_FINUP))) {
- /* not last sg must be BLOCK_SIZE aligned */
- tail = length & (bs - 1);
- /* without finup() we need one block to close hash */
- if (!tail)
- tail = bs;
- length -= tail;
- }
- }
-
- if (!dma_map_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE)) {
- dev_err(dd->dev, "dma_map_sg error\n");
- return -EINVAL;
- }
-
- ctx->flags |= BIT(FLAGS_SG);
-
- ctx->total -= length;
- ctx->offset = length; /* offset where to start slow */
-
- final = (ctx->flags & BIT(FLAGS_FINUP)) && !ctx->total;
-
- ret = omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, final, 1);
- if (ret != -EINPROGRESS)
- dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE);
-
- return ret;
-}
-
-static int omap_sham_update_cpu(struct omap_sham_dev *dd)
-{
- struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
- int bufcnt, final;
-
- if (!ctx->total)
- return 0;
-
- omap_sham_append_sg(ctx);
-
- final = (ctx->flags & BIT(FLAGS_FINUP)) && !ctx->total;
-
- dev_dbg(dd->dev, "cpu: bufcnt: %u, digcnt: %d, final: %d\n",
- ctx->bufcnt, ctx->digcnt, final);
-
- if (final || (ctx->bufcnt == ctx->buflen && ctx->total)) {
- bufcnt = ctx->bufcnt;
- ctx->bufcnt = 0;
- return omap_sham_xmit_cpu(dd, ctx->buffer, bufcnt, final);
- }
-
- return 0;
-}
-
static int omap_sham_update_dma_stop(struct omap_sham_dev *dd)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
+ dma_unmap_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE);
- if (ctx->flags & BIT(FLAGS_SG)) {
- dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE);
- if (ctx->sg->length == ctx->offset) {
- ctx->sg = sg_next(ctx->sg);
- if (ctx->sg)
- ctx->offset = 0;
- }
- } else {
- dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen,
- DMA_TO_DEVICE);
- }
+ clear_bit(FLAGS_DMA_ACTIVE, &dd->flags);
return 0;
}
@@ -1148,6 +959,8 @@ static int omap_sham_init(struct ahash_request *req)
ctx->bufcnt = 0;
ctx->digcnt = 0;
+ ctx->total = 0;
+ ctx->offset = 0;
ctx->buflen = BUFLEN;
if (tctx->flags & BIT(FLAGS_HMAC)) {
@@ -1170,14 +983,19 @@ static int omap_sham_update_req(struct omap_sham_dev *dd)
struct ahash_request *req = dd->req;
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
int err;
+ bool final = ctx->flags & BIT(FLAGS_FINUP);
dev_dbg(dd->dev, "update_req: total: %u, digcnt: %d, finup: %d\n",
ctx->total, ctx->digcnt, (ctx->flags & BIT(FLAGS_FINUP)) != 0);
+ if (ctx->total < get_block_size(ctx) ||
+ ctx->total < OMAP_SHA_DMA_THRESHOLD)
+ ctx->flags |= BIT(FLAGS_CPU);
+
if (ctx->flags & BIT(FLAGS_CPU))
- err = omap_sham_update_cpu(dd);
+ err = omap_sham_xmit_cpu(dd, ctx->total, final);
else
- err = omap_sham_update_dma_start(dd);
+ err = omap_sham_xmit_dma(dd, ctx->total, final);
/* wait for dma completion before can take more data */
dev_dbg(dd->dev, "update: err: %d, digcnt: %d\n", err, ctx->digcnt);
@@ -1191,7 +1009,7 @@ static int omap_sham_final_req(struct omap_sham_dev *dd)
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
int err = 0, use_dma = 1;
- if ((ctx->bufcnt <= get_block_size(ctx)) || dd->polling_mode)
+ if ((ctx->total <= get_block_size(ctx)) || dd->polling_mode)
/*
* faster to handle last block with cpu or
* use cpu when dma is not present.
@@ -1199,9 +1017,9 @@ static int omap_sham_final_req(struct omap_sham_dev *dd)
use_dma = 0;
if (use_dma)
- err = omap_sham_xmit_dma_map(dd, ctx, ctx->bufcnt, 1);
+ err = omap_sham_xmit_dma(dd, ctx->total, 1);
else
- err = omap_sham_xmit_cpu(dd, ctx->buffer, ctx->bufcnt, 1);
+ err = omap_sham_xmit_cpu(dd, ctx->total, 1);
ctx->bufcnt = 0;
@@ -1249,6 +1067,17 @@ static void omap_sham_finish_req(struct ahash_request *req, int err)
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
struct omap_sham_dev *dd = ctx->dd;
+ if (test_bit(FLAGS_SGS_COPIED, &dd->flags))
+ free_pages((unsigned long)sg_virt(ctx->sg),
+ get_order(ctx->sg->length));
+
+ if (test_bit(FLAGS_SGS_ALLOCED, &dd->flags))
+ kfree(ctx->sg);
+
+ ctx->sg = NULL;
+
+ dd->flags &= ~(BIT(FLAGS_SGS_ALLOCED) | BIT(FLAGS_SGS_COPIED));
+
if (!err) {
dd->pdata->copy_hash(req, 1);
if (test_bit(FLAGS_FINAL, &dd->flags))
@@ -1300,7 +1129,7 @@ retry:
dd->req = req;
ctx = ahash_request_ctx(req);
- err = omap_sham_prepare_request(NULL, ctx->op == OP_UPDATE);
+ err = omap_sham_prepare_request(req, ctx->op == OP_UPDATE);
if (err)
goto err1;
@@ -1356,34 +1185,15 @@ static int omap_sham_update(struct ahash_request *req)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
struct omap_sham_dev *dd = ctx->dd;
- int bs = get_block_size(ctx);
if (!req->nbytes)
return 0;
- ctx->total = req->nbytes;
- ctx->sg = req->src;
- ctx->offset = 0;
-
- if (ctx->flags & BIT(FLAGS_FINUP)) {
- if ((ctx->digcnt + ctx->bufcnt + ctx->total) < 240) {
- /*
- * OMAP HW accel works only with buffers >= 9
- * will switch to bypass in final()
- * final has the same request and data
- */
- omap_sham_append_sg(ctx);
- return 0;
- } else if ((ctx->bufcnt + ctx->total <= bs) ||
- dd->polling_mode) {
- /*
- * faster to use CPU for short transfers or
- * use cpu when dma is not present.
- */
- ctx->flags |= BIT(FLAGS_CPU);
- }
- } else if (ctx->bufcnt + ctx->total < ctx->buflen) {
- omap_sham_append_sg(ctx);
+ if (ctx->total + req->nbytes < ctx->buflen) {
+ scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, req->src,
+ 0, req->nbytes, 0);
+ ctx->bufcnt += req->nbytes;
+ ctx->total += req->nbytes;
return 0;
}
@@ -1917,12 +1727,8 @@ static void omap_sham_done_task(unsigned long data)
}
if (test_bit(FLAGS_CPU, &dd->flags)) {
- if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags)) {
- /* hash or semi-hash ready */
- err = omap_sham_update_cpu(dd);
- if (err != -EINPROGRESS)
- goto finish;
- }
+ if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags))
+ goto finish;
} else if (test_bit(FLAGS_DMA_READY, &dd->flags)) {
if (test_and_clear_bit(FLAGS_DMA_ACTIVE, &dd->flags)) {
omap_sham_update_dma_stop(dd);
@@ -1934,8 +1740,6 @@ static void omap_sham_done_task(unsigned long data)
if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags)) {
/* hash or semi-hash ready */
clear_bit(FLAGS_DMA_READY, &dd->flags);
- err = omap_sham_update_dma_start(dd);
- if (err != -EINPROGRESS)
goto finish;
}
}
--
1.9.1
^ permalink raw reply related
* [PATCH 5/8] crypto: omap-sham: change the DMA threshold value to a define
From: Tero Kristo @ 2016-09-19 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474298539-23897-1-git-send-email-t-kristo@ti.com>
Currently the threshold value was hardcoded in the driver. Having a define
for it makes it easier to configure.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
drivers/crypto/omap-sham.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 8558989..5c95bf9 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -137,6 +137,7 @@
#define OMAP_ALIGNED __attribute__((aligned(sizeof(u32))))
#define BUFLEN PAGE_SIZE
+#define OMAP_SHA_DMA_THRESHOLD 256
struct omap_sham_dev;
@@ -1435,10 +1436,11 @@ static int omap_sham_final(struct ahash_request *req)
/*
* OMAP HW accel works only with buffers >= 9.
* HMAC is always >= 9 because ipad == block size.
- * If buffersize is less than 240, we use fallback SW encoding,
- * as using DMA + HW in this case doesn't provide any benefit.
+ * If buffersize is less than DMA_THRESHOLD, we use fallback
+ * SW encoding, as using DMA + HW in this case doesn't provide
+ * any benefit.
*/
- if (!ctx->digcnt && ctx->bufcnt < 240)
+ if (!ctx->digcnt && ctx->bufcnt < OMAP_SHA_DMA_THRESHOLD)
return omap_sham_final_shash(req);
else if (ctx->bufcnt)
return omap_sham_enqueue(req, OP_FINAL);
--
1.9.1
^ permalink raw reply related
* [PATCH 4/8] crypto: omap-sham: add support functions for sg based data handling
From: Tero Kristo @ 2016-09-19 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474298539-23897-1-git-send-email-t-kristo@ti.com>
Currently omap-sham uses a huge internal buffer for caching data, and
pushing this out to the DMA as large chunks. This, unfortunately,
doesn't work too well with the export/import functionality required
for ahash algorithms, and must be changed towards more scatterlist
centric approach.
This patch adds support functions for (mostly) scatterlist based data
handling. omap_sham_prepare_request() prepares a scatterlist for DMA
transfer to SHA crypto accelerator. This requires checking the data /
offset / length alignment of the data, splitting the data to SHA block
size granularity, and adding any remaining data back to the buffer.
With this patch, the code doesn't actually go live yet, the support code
will be taken properly into use with additional patches that modify the
SHA driver functionality itself.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
drivers/crypto/omap-sham.c | 263 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 263 insertions(+)
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 33bea52..8558989 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -112,6 +112,8 @@
#define FLAGS_DMA_READY 6
#define FLAGS_AUTO_XOR 7
#define FLAGS_BE32_SHA1 8
+#define FLAGS_SGS_COPIED 9
+#define FLAGS_SGS_ALLOCED 10
/* context flags */
#define FLAGS_FINUP 16
#define FLAGS_SG 17
@@ -151,8 +153,10 @@ struct omap_sham_reqctx {
/* walk state */
struct scatterlist *sg;
+ struct scatterlist sgl[2];
struct scatterlist sgl_tmp;
unsigned int offset; /* offset in current sg */
+ int sg_len;
unsigned int total; /* total request */
u8 buffer[0] OMAP_ALIGNED;
@@ -223,6 +227,7 @@ struct omap_sham_dev {
struct dma_chan *dma_lch;
struct tasklet_struct done_task;
u8 polling_mode;
+ u8 xmit_buf[BUFLEN];
unsigned long flags;
struct crypto_queue queue;
@@ -626,6 +631,260 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
return -EINPROGRESS;
}
+static int omap_sham_copy_sg_lists(struct omap_sham_reqctx *ctx,
+ struct scatterlist *sg, int bs, int new_len)
+{
+ int n = sg_nents(sg);
+ struct scatterlist *tmp;
+ int offset = ctx->offset;
+
+ if (ctx->bufcnt)
+ n++;
+
+ ctx->sg = kmalloc_array(n, sizeof(*sg), GFP_KERNEL);
+ if (!ctx->sg)
+ return -ENOMEM;
+
+ sg_init_table(ctx->sg, n);
+
+ tmp = ctx->sg;
+
+ ctx->sg_len = 0;
+
+ if (ctx->bufcnt) {
+ sg_set_buf(tmp, ctx->dd->xmit_buf, ctx->bufcnt);
+ tmp = sg_next(tmp);
+ ctx->sg_len++;
+ }
+
+ while (sg && new_len) {
+ int len = sg->length - offset;
+
+ if (offset) {
+ offset -= sg->length;
+ if (offset < 0)
+ offset = 0;
+ }
+
+ if (new_len < len)
+ len = new_len;
+
+ if (len > 0) {
+ new_len -= len;
+ sg_set_page(tmp, sg_page(sg), len, sg->offset);
+ if (new_len <= 0)
+ sg_mark_end(tmp);
+ tmp = sg_next(tmp);
+ ctx->sg_len++;
+ }
+
+ sg = sg_next(sg);
+ }
+
+ set_bit(FLAGS_SGS_ALLOCED, &ctx->dd->flags);
+
+ ctx->bufcnt = 0;
+
+ return 0;
+}
+
+static int omap_sham_copy_sgs(struct omap_sham_reqctx *ctx,
+ struct scatterlist *sg, int bs, int new_len)
+{
+ int pages;
+ void *buf;
+ int len;
+
+ len = new_len + ctx->bufcnt;
+
+ pages = get_order(ctx->total);
+
+ buf = (void *)__get_free_pages(GFP_ATOMIC, pages);
+ if (!buf) {
+ pr_err("Couldn't allocate pages for unaligned cases.\n");
+ return -ENOMEM;
+ }
+
+ if (ctx->bufcnt)
+ memcpy(buf, ctx->dd->xmit_buf, ctx->bufcnt);
+
+ scatterwalk_map_and_copy(buf + ctx->bufcnt, sg, ctx->offset,
+ ctx->total - ctx->bufcnt, 0);
+ sg_init_table(ctx->sgl, 1);
+ sg_set_buf(ctx->sgl, buf, len);
+ ctx->sg = ctx->sgl;
+ set_bit(FLAGS_SGS_COPIED, &ctx->dd->flags);
+ ctx->sg_len = 1;
+ ctx->bufcnt = 0;
+ ctx->offset = 0;
+
+ return 0;
+}
+
+static int omap_sham_align_sgs(struct scatterlist *sg,
+ int nbytes, int bs, bool final,
+ struct omap_sham_reqctx *rctx)
+{
+ int n = 0;
+ bool aligned = true;
+ bool list_ok = true;
+ struct scatterlist *sg_tmp = sg;
+ int new_len;
+ int offset = rctx->offset;
+
+ if (!sg || !sg->length || !nbytes)
+ return 0;
+
+ new_len = nbytes;
+
+ if (offset)
+ list_ok = false;
+
+ if (final)
+ new_len = DIV_ROUND_UP(new_len, bs) * bs;
+ else
+ new_len = new_len / bs * bs;
+
+ while (nbytes > 0 && sg_tmp) {
+ n++;
+
+ if (offset < sg_tmp->length) {
+ if (!IS_ALIGNED(offset + sg_tmp->offset, 4)) {
+ aligned = false;
+ break;
+ }
+
+ if (!IS_ALIGNED(sg_tmp->length - offset, bs)) {
+ aligned = false;
+ break;
+ }
+ }
+
+ if (offset) {
+ offset -= sg_tmp->length;
+ if (offset < 0) {
+ nbytes += offset;
+ offset = 0;
+ }
+ } else {
+ nbytes -= sg_tmp->length;
+ }
+
+ sg_tmp = sg_next(sg_tmp);
+
+ if (nbytes < 0) {
+ list_ok = false;
+ break;
+ }
+ }
+
+ if (!aligned)
+ return omap_sham_copy_sgs(rctx, sg, bs, new_len);
+ else if (!list_ok)
+ return omap_sham_copy_sg_lists(rctx, sg, bs, new_len);
+
+ rctx->sg_len = n;
+ rctx->sg = sg;
+
+ return 0;
+}
+
+static int omap_sham_prepare_request(struct ahash_request *req, bool update)
+{
+ struct omap_sham_reqctx *rctx = ahash_request_ctx(req);
+ int bs;
+ int ret;
+ int nbytes;
+ bool final = rctx->flags & BIT(FLAGS_FINUP);
+ int xmit_len, hash_later;
+
+ if (!req)
+ return 0;
+
+ bs = get_block_size(rctx);
+
+ if (update)
+ nbytes = req->nbytes;
+ else
+ nbytes = 0;
+
+ rctx->total = nbytes + rctx->bufcnt;
+
+ if (!rctx->total)
+ return 0;
+
+ if (nbytes && (!IS_ALIGNED(rctx->bufcnt, bs))) {
+ int len = bs - rctx->bufcnt % bs;
+
+ if (len > nbytes)
+ len = nbytes;
+ scatterwalk_map_and_copy(rctx->buffer + rctx->bufcnt, req->src,
+ 0, len, 0);
+ rctx->bufcnt += len;
+ nbytes -= len;
+ rctx->offset = len;
+ }
+
+ if (rctx->bufcnt)
+ memcpy(rctx->dd->xmit_buf, rctx->buffer, rctx->bufcnt);
+
+ ret = omap_sham_align_sgs(req->src, nbytes, bs, final, rctx);
+ if (ret)
+ return ret;
+
+ xmit_len = rctx->total;
+
+ if (!IS_ALIGNED(xmit_len, bs)) {
+ if (final)
+ xmit_len = DIV_ROUND_UP(xmit_len, bs) * bs;
+ else
+ xmit_len = xmit_len / bs * bs;
+ }
+
+ hash_later = rctx->total - xmit_len;
+ if (hash_later < 0)
+ hash_later = 0;
+
+ if (rctx->bufcnt && nbytes) {
+ /* have data from previous operation and current */
+ sg_init_table(rctx->sgl, 2);
+ sg_set_buf(rctx->sgl, rctx->dd->xmit_buf, rctx->bufcnt);
+
+ sg_chain(rctx->sgl, 2, req->src);
+
+ rctx->sg = rctx->sgl;
+
+ rctx->sg_len++;
+ } else if (rctx->bufcnt) {
+ /* have buffered data only */
+ sg_init_table(rctx->sgl, 1);
+ sg_set_buf(rctx->sgl, rctx->dd->xmit_buf, xmit_len);
+
+ rctx->sg = rctx->sgl;
+
+ rctx->sg_len = 1;
+ }
+
+ if (hash_later) {
+ if (req->nbytes) {
+ scatterwalk_map_and_copy(rctx->buffer, req->src,
+ req->nbytes - hash_later,
+ hash_later, 0);
+ } else {
+ memcpy(rctx->buffer, rctx->buffer + xmit_len,
+ hash_later);
+ }
+ rctx->bufcnt = hash_later;
+ } else {
+ rctx->bufcnt = 0;
+ }
+
+ if (!final)
+ rctx->total = xmit_len;
+
+ return 0;
+}
+
static size_t omap_sham_append_buffer(struct omap_sham_reqctx *ctx,
const u8 *data, size_t length)
{
@@ -1040,6 +1299,10 @@ retry:
dd->req = req;
ctx = ahash_request_ctx(req);
+ err = omap_sham_prepare_request(NULL, ctx->op == OP_UPDATE);
+ if (err)
+ goto err1;
+
dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n",
ctx->op, req->nbytes);
--
1.9.1
^ permalink raw reply related
* [PATCH 3/8] crypto: omap-sham: rename sgl to sgl_tmp for deprecation
From: Tero Kristo @ 2016-09-19 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474298539-23897-1-git-send-email-t-kristo@ti.com>
The current usage of sgl will be deprecated, and will be replaced by an
array required by the sg based driver implementation. Rename the existing
variable as sgl_tmp so that it can be removed from the driver easily later.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
drivers/crypto/omap-sham.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 3f2bf98..33bea52 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -151,7 +151,7 @@ struct omap_sham_reqctx {
/* walk state */
struct scatterlist *sg;
- struct scatterlist sgl;
+ struct scatterlist sgl_tmp;
unsigned int offset; /* offset in current sg */
unsigned int total; /* total request */
@@ -583,18 +583,19 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
if (is_sg) {
/*
* The SG entry passed in may not have the 'length' member
- * set correctly so use a local SG entry (sgl) with the
+ * set correctly so use a local SG entry (sgl_tmp) with the
* proper value for 'length' instead. If this is not done,
* the dmaengine may try to DMA the incorrect amount of data.
*/
- sg_init_table(&ctx->sgl, 1);
- sg_assign_page(&ctx->sgl, sg_page(ctx->sg));
- ctx->sgl.offset = ctx->sg->offset;
- sg_dma_len(&ctx->sgl) = len32;
- sg_dma_address(&ctx->sgl) = sg_dma_address(ctx->sg);
-
- tx = dmaengine_prep_slave_sg(dd->dma_lch, &ctx->sgl, 1,
- DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ sg_init_table(&ctx->sgl_tmp, 1);
+ sg_assign_page(&ctx->sgl_tmp, sg_page(ctx->sg));
+ ctx->sgl_tmp.offset = ctx->sg->offset;
+ sg_dma_len(&ctx->sgl_tmp) = len32;
+ sg_dma_address(&ctx->sgl_tmp) = sg_dma_address(ctx->sg);
+
+ tx = dmaengine_prep_slave_sg(dd->dma_lch, &ctx->sgl_tmp, 1,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
} else {
tx = dmaengine_prep_slave_single(dd->dma_lch, dma_addr, len32,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
--
1.9.1
^ permalink raw reply related
* [PATCH 2/8] crypto: omap-sham: align algorithms on word offset
From: Tero Kristo @ 2016-09-19 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474298539-23897-1-git-send-email-t-kristo@ti.com>
OMAP HW generally expects data for DMA to be on word boundary, so make the
SHA driver inform crypto framework of the same preference.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
drivers/crypto/omap-sham.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 74653c9..3f2bf98 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -1368,7 +1368,7 @@ static struct ahash_alg algs_sha1_md5[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_sham_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = OMAP_ALIGN_MASK,
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
@@ -1467,7 +1467,7 @@ static struct ahash_alg algs_sha224_sha256[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA224_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_sham_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = OMAP_ALIGN_MASK,
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
@@ -1489,7 +1489,7 @@ static struct ahash_alg algs_sha224_sha256[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA256_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_sham_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = OMAP_ALIGN_MASK,
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
@@ -1562,7 +1562,7 @@ static struct ahash_alg algs_sha384_sha512[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA384_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_sham_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = OMAP_ALIGN_MASK,
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
@@ -1584,7 +1584,7 @@ static struct ahash_alg algs_sha384_sha512[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA512_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_sham_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = OMAP_ALIGN_MASK,
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
--
1.9.1
^ permalink raw reply related
* [PATCH 1/8] crypto: omap-sham: add context export/import stubs
From: Tero Kristo @ 2016-09-19 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474298539-23897-1-git-send-email-t-kristo@ti.com>
Initially these just return -ENOTSUPP to indicate that they don't
really do anything yet. Some sort of implementation is required
for the driver to at least probe.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
drivers/crypto/omap-sham.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index cf9f617c..74653c9 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -1340,6 +1340,16 @@ static void omap_sham_cra_exit(struct crypto_tfm *tfm)
}
}
+static int omap_sham_export(struct ahash_request *req, void *out)
+{
+ return -ENOTSUPP;
+}
+
+static int omap_sham_import(struct ahash_request *req, const void *in)
+{
+ return -ENOTSUPP;
+}
+
static struct ahash_alg algs_sha1_md5[] = {
{
.init = omap_sham_init,
@@ -1998,8 +2008,13 @@ static int omap_sham_probe(struct platform_device *pdev)
for (i = 0; i < dd->pdata->algs_info_size; i++) {
for (j = 0; j < dd->pdata->algs_info[i].size; j++) {
- err = crypto_register_ahash(
- &dd->pdata->algs_info[i].algs_list[j]);
+ struct ahash_alg *alg;
+
+ alg = &dd->pdata->algs_info[i].algs_list[j];
+ alg->export = omap_sham_export;
+ alg->import = omap_sham_import;
+ alg->halg.statesize = sizeof(struct omap_sham_reqctx);
+ err = crypto_register_ahash(alg);
if (err)
goto err_algs;
--
1.9.1
^ permalink raw reply related
* [PATCH 0/8] crypto: omap-sham: convert to sg based data engine
From: Tero Kristo @ 2016-09-19 15:22 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This series converts the omap-sham buffer handling towards a scatterlist
approach. This avoids the need to have a huge internal buffer within the
driver, and also allows us to properly implement export/import for the
driver. I tried splitting up the changes to some sane patches, but this
was rather difficult due to the fact that this is largely a complete
rewrite of portions of the driver. Patch #6 is a prime example of this
being pretty large, but splitting this up would break bisectability.
Hopefully the patch is still understandable though.
Crypto manager tests work fine at least on omap3/am3/am4/dra7 SoC:s.
(Something is broken with test farm again and could not try omap2/omap4.)
Also tested tcrypt SHA performance on DRA7 and it seems to be working
fine with different buffer sizes.
My test branch is also available here for interested parties:
tree: https://github.com/t-kristo/linux-pm.git
breanch: 4.8-rc1-crypto
-Tero
^ permalink raw reply
* [PATCH 1/4] drm/sun4i: rgb: Declare RGB encoder and connector as MIPI DPI
From: Chen-Yu Tsai @ 2016-09-19 15:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160918191205.GG17518@lukather>
On Mon, Sep 19, 2016 at 3:12 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi,
>
> On Thu, Sep 15, 2016 at 11:13:59PM +0800, Chen-Yu Tsai wrote:
>> The 18 or 24 bit parallel RGB LCD panel interface found on Allwinner
>> SoCs matches the description of MIPI DPI. Declare the RGB encoder and
>> connector as MIPI DPI.
>
> Unfortunately, even it that patch might be true (is there a public
> spec for that standard?), this breaks the user-space, so there's no
Not that I know of. I basically googled the term and looked at other
datasheets and asked on #linux-arm-kernel.
> way we change this.
:(
ChenYu
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox