[PATCH] wifi: mt76: mmio_(read|write)_copy byte swap when on Big Endian
Jonas Gorski
jonas.gorski at gmail.com
Tue Oct 28 13:19:53 PDT 2025
Hi,
On Mon, Oct 27, 2025 at 6:19 PM Caleb James DeLisle <cjd at cjdns.fr> wrote:
>
> When on a Big Endian machine, PCI swaps words to/from LE when
> reading/writing them. This presents a problem when we're trying
> to copy an opaque byte array such as firmware or encryption key.
>
> Byte-swapping during copy results in two swaps, but solves the
> problem.
>
> Fixes:
> mt76x2e 0000:02:00.0: ROM patch build: 20141115060606a
> mt76x2e 0000:02:00.0: Firmware Version: 0.0.00
> mt76x2e 0000:02:00.0: Build: 1
> mt76x2e 0000:02:00.0: Build Time: 201607111443____
> mt76x2e 0000:02:00.0: Firmware failed to start
> mt76x2e 0000:02:00.0: probe with driver mt76x2e failed with error -145
>
> Signed-off-by: Caleb James DeLisle <cjd at cjdns.fr>
> ---
> drivers/net/wireless/mediatek/mt76/mmio.c | 34 +++++++++++++++++++++++
> 1 file changed, 34 insertions(+)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c
> index cd2e9737c3bf..776dbaacc8a3 100644
> --- a/drivers/net/wireless/mediatek/mt76/mmio.c
> +++ b/drivers/net/wireless/mediatek/mt76/mmio.c
> @@ -30,15 +30,49 @@ static u32 mt76_mmio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
> return val;
> }
>
> +static void mt76_mmio_write_copy_portable(void __iomem *dst,
> + const u8 *src, int len)
> +{
> + __le32 val;
> + int i = 0;
> +
> + for (i = 0; i < ALIGN(len, 4); i += 4) {
> + memcpy(&val, src + i, sizeof(val));
> + writel(cpu_to_le32(val), dst + i);
> + }
> +}
> +
> static void mt76_mmio_write_copy(struct mt76_dev *dev, u32 offset,
> const void *data, int len)
> {
> + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
> + mt76_mmio_write_copy_portable(dev->mmio.regs + offset, data,
> + len);
> + return;
> + }
> __iowrite32_copy(dev->mmio.regs + offset, data, DIV_ROUND_UP(len, 4));
Maybe just replace this with memcpy_toio() which does no swapping at
all instead of double swapping on BE?
> }
>
> +static void mt76_mmio_read_copy_portable(u8 *dst,
> + const void __iomem *src, int len)
> +{
> + u32 val;
> + int i;
> +
> + for (i = 0; i < ALIGN(len, 4); i += 4) {
> + val = le32_to_cpu(readl(src + i));
> + memcpy(dst + i, &val, sizeof(val));
> + }
> +}
> +
> static void mt76_mmio_read_copy(struct mt76_dev *dev, u32 offset,
> void *data, int len)
> {
> + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
> + mt76_mmio_read_copy_portable(data, dev->mmio.regs + offset,
> + len);
> + return;
> + }
> __ioread32_copy(data, dev->mmio.regs + offset, DIV_ROUND_UP(len, 4));
And memcpy_fromio() here.
Best regards,
Jonas
More information about the Linux-mediatek
mailing list