Skip to content

Commit

Permalink
Merge patch series "Add non-coherent DMA support for AX45MP"
Browse files Browse the repository at this point in the history
Prabhakar <[email protected]> says:

From: Lad Prabhakar <[email protected]>

non-coherent DMA support for AX45MP
====================================

On the Andes AX45MP core, cache coherency is a specification option so it
may not be supported. In this case DMA will fail. To get around with this
issue this patch series does the below:

1] Andes alternative ports is implemented as errata which checks if the
IOCP is missing and only then applies to CMO errata. One vendor specific
SBI EXT (ANDES_SBI_EXT_IOCP_SW_WORKAROUND) is implemented as part of
errata.

Below are the configs which Andes port provides (and are selected by
RZ/Five):
      - ERRATA_ANDES
      - ERRATA_ANDES_CMO

OpenSBI patch supporting ANDES_SBI_EXT_IOCP_SW_WORKAROUND SBI is now
part v1.3 release.

2] Andes AX45MP core has a Programmable Physical Memory Attributes (PMA)
block that allows dynamic adjustment of memory attributes in the runtime.
It contains a configurable amount of PMA entries implemented as CSR
registers to control the attributes of memory locations in interest.
OpenSBI configures the PMA regions as required and creates a reserve memory
node and propagates it to the higher boot stack.

Currently OpenSBI (upstream) configures the required PMA region and passes
this a shared DMA pool to Linux.

    reserved-memory {
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;

        pma_resv0@58000000 {
            compatible = "shared-dma-pool";
            reg = <0x0 0x58000000 0x0 0x08000000>;
            no-map;
            linux,dma-default;
        };
    };

The above shared DMA pool gets appended to Linux DTB so the DMA memory
requests go through this region.

3] We provide callbacks to synchronize specific content between memory and
cache.

4] RZ/Five SoC selects the below configs
        - AX45MP_L2_CACHE
        - DMA_GLOBAL_POOL
        - ERRATA_ANDES
        - ERRATA_ANDES_CMO

----------x---------------------x--------------------x---------------x----

* b4-shazam-merge:
  soc: renesas: Kconfig: Select the required configs for RZ/Five SoC
  cache: Add L2 cache management for Andes AX45MP RISC-V core
  dt-bindings: cache: andestech,ax45mp-cache: Add DT binding documentation for L2 cache controller
  riscv: mm: dma-noncoherent: nonstandard cache operations support
  riscv: errata: Add Andes alternative ports
  riscv: asm: vendorid_list: Add Andes Technology to the vendors list

Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Palmer Dabbelt <[email protected]>
  • Loading branch information
palmer-dabbelt committed Sep 8, 2023
2 parents 7f215d0 + 484861e commit c23be91
Show file tree
Hide file tree
Showing 20 changed files with 516 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright (C) 2023 Renesas Electronics Corp.
%YAML 1.2
---
$id: http://devicetree.org/schemas/cache/andestech,ax45mp-cache.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Andestech AX45MP L2 Cache Controller

maintainers:
- Lad Prabhakar <[email protected]>

description:
A level-2 cache (L2C) is used to improve the system performance by providing
a large amount of cache line entries and reasonable access delays. The L2C
is shared between cores, and a non-inclusive non-exclusive policy is used.

select:
properties:
compatible:
contains:
enum:
- andestech,ax45mp-cache

required:
- compatible

properties:
compatible:
items:
- const: andestech,ax45mp-cache
- const: cache

reg:
maxItems: 1

interrupts:
maxItems: 1

cache-line-size:
const: 64

cache-level:
const: 2

cache-sets:
const: 1024

cache-size:
enum: [131072, 262144, 524288, 1048576, 2097152]

cache-unified: true

next-level-cache: true

additionalProperties: false

required:
- compatible
- reg
- interrupts
- cache-line-size
- cache-level
- cache-sets
- cache-size
- cache-unified

examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
cache-controller@2010000 {
compatible = "andestech,ax45mp-cache", "cache";
reg = <0x13400000 0x100000>;
interrupts = <508 IRQ_TYPE_LEVEL_HIGH>;
cache-line-size = <64>;
cache-level = <2>;
cache-sets = <1024>;
cache-size = <262144>;
cache-unified;
};
7 changes: 7 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -20340,6 +20340,13 @@ S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
F: drivers/staging/

STANDALONE CACHE CONTROLLER DRIVERS
M: Conor Dooley <[email protected]>
L: [email protected]
S: Maintained
T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/
F: drivers/cache

STARFIRE/DURALAN NETWORK DRIVER
M: Ion Badulescu <[email protected]>
S: Odd Fixes
Expand Down
7 changes: 7 additions & 0 deletions arch/riscv/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@ config RISCV_DMA_NONCOHERENT
select DMA_BOUNCE_UNALIGNED_KMALLOC if SWIOTLB
select DMA_DIRECT_REMAP

config RISCV_NONSTANDARD_CACHE_OPS
bool
depends on RISCV_DMA_NONCOHERENT
help
This enables function pointer support for non-standard noncoherent
systems to handle cache management.

config AS_HAS_INSN
def_bool $(as-instr,.insn r 51$(comma) 0$(comma) 0$(comma) t0$(comma) t0$(comma) zero)

Expand Down
21 changes: 21 additions & 0 deletions arch/riscv/Kconfig.errata
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
menu "CPU errata selection"

config ERRATA_ANDES
bool "Andes AX45MP errata"
depends on RISCV_ALTERNATIVE
help
All Andes errata Kconfig depend on this Kconfig. Disabling
this Kconfig will disable all Andes errata. Please say "Y"
here if your platform uses Andes CPU cores.

Otherwise, please say "N" here to avoid unnecessary overhead.

config ERRATA_ANDES_CMO
bool "Apply Andes cache management errata"
depends on ERRATA_ANDES && MMU && ARCH_R9A07G043
select RISCV_DMA_NONCOHERENT
default y
help
This will apply the cache management errata to handle the
non-standard handling on non-coherent operations on Andes cores.

If you don't know what to do here, say "Y".

config ERRATA_SIFIVE
bool "SiFive errata"
depends on RISCV_ALTERNATIVE
Expand Down
1 change: 1 addition & 0 deletions arch/riscv/errata/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ ifdef CONFIG_RELOCATABLE
KBUILD_CFLAGS += -fno-pie
endif

obj-$(CONFIG_ERRATA_ANDES) += andes/
obj-$(CONFIG_ERRATA_SIFIVE) += sifive/
obj-$(CONFIG_ERRATA_THEAD) += thead/
1 change: 1 addition & 0 deletions arch/riscv/errata/andes/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
obj-y += errata.o
66 changes: 66 additions & 0 deletions arch/riscv/errata/andes/errata.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Erratas to be applied for Andes CPU cores
*
* Copyright (C) 2023 Renesas Electronics Corporation.
*
* Author: Lad Prabhakar <[email protected]>
*/

#include <linux/memory.h>
#include <linux/module.h>

#include <asm/alternative.h>
#include <asm/cacheflush.h>
#include <asm/errata_list.h>
#include <asm/patch.h>
#include <asm/processor.h>
#include <asm/sbi.h>
#include <asm/vendorid_list.h>

#define ANDESTECH_AX45MP_MARCHID 0x8000000000008a45UL
#define ANDESTECH_AX45MP_MIMPID 0x500UL
#define ANDESTECH_SBI_EXT_ANDES 0x0900031E

#define ANDES_SBI_EXT_IOCP_SW_WORKAROUND 1

static long ax45mp_iocp_sw_workaround(void)
{
struct sbiret ret;

/*
* ANDES_SBI_EXT_IOCP_SW_WORKAROUND SBI EXT checks if the IOCP is missing and
* cache is controllable only then CMO will be applied to the platform.
*/
ret = sbi_ecall(ANDESTECH_SBI_EXT_ANDES, ANDES_SBI_EXT_IOCP_SW_WORKAROUND,
0, 0, 0, 0, 0, 0);

return ret.error ? 0 : ret.value;
}

static bool errata_probe_iocp(unsigned int stage, unsigned long arch_id, unsigned long impid)
{
if (!IS_ENABLED(CONFIG_ERRATA_ANDES_CMO))
return false;

if (arch_id != ANDESTECH_AX45MP_MARCHID || impid != ANDESTECH_AX45MP_MIMPID)
return false;

if (!ax45mp_iocp_sw_workaround())
return false;

/* Set this just to make core cbo code happy */
riscv_cbom_block_size = 1;
riscv_noncoherent_supported();

return true;
}

void __init_or_module andes_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
unsigned long archid, unsigned long impid,
unsigned int stage)
{
errata_probe_iocp(stage, archid, impid);

/* we have nothing to patch here ATM so just return back */
}
3 changes: 3 additions & 0 deletions arch/riscv/include/asm/alternative.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ struct alt_entry {
u32 patch_id; /* The patch ID (erratum ID or cpufeature ID) */
};

void andes_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
unsigned long archid, unsigned long impid,
unsigned int stage);
void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
unsigned long archid, unsigned long impid,
unsigned int stage);
Expand Down
28 changes: 28 additions & 0 deletions arch/riscv/include/asm/dma-noncoherent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2023 Renesas Electronics Corp.
*/

#ifndef __ASM_DMA_NONCOHERENT_H
#define __ASM_DMA_NONCOHERENT_H

#include <linux/dma-direct.h>

/*
* struct riscv_nonstd_cache_ops - Structure for non-standard CMO function pointers
*
* @wback: Function pointer for cache writeback
* @inv: Function pointer for invalidating cache
* @wback_inv: Function pointer for flushing the cache (writeback + invalidating)
*/
struct riscv_nonstd_cache_ops {
void (*wback)(phys_addr_t paddr, size_t size);
void (*inv)(phys_addr_t paddr, size_t size);
void (*wback_inv)(phys_addr_t paddr, size_t size);
};

extern struct riscv_nonstd_cache_ops noncoherent_cache_ops;

void riscv_noncoherent_register_cache_ops(const struct riscv_nonstd_cache_ops *ops);

#endif /* __ASM_DMA_NONCOHERENT_H */
5 changes: 5 additions & 0 deletions arch/riscv/include/asm/errata_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
#include <asm/hwcap.h>
#include <asm/vendorid_list.h>

#ifdef CONFIG_ERRATA_ANDES
#define ERRATA_ANDESTECH_NO_IOCP 0
#define ERRATA_ANDESTECH_NUMBER 1
#endif

#ifdef CONFIG_ERRATA_SIFIVE
#define ERRATA_SIFIVE_CIP_453 0
#define ERRATA_SIFIVE_CIP_1200 1
Expand Down
1 change: 1 addition & 0 deletions arch/riscv/include/asm/vendorid_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifndef ASM_VENDOR_LIST_H
#define ASM_VENDOR_LIST_H

#define ANDESTECH_VENDOR_ID 0x31e
#define SIFIVE_VENDOR_ID 0x489
#define THEAD_VENDOR_ID 0x5b7

Expand Down
5 changes: 5 additions & 0 deletions arch/riscv/kernel/alternative.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ static void riscv_fill_cpu_mfr_info(struct cpu_manufacturer_info_t *cpu_mfr_info
#endif

switch (cpu_mfr_info->vendor_id) {
#ifdef CONFIG_ERRATA_ANDES
case ANDESTECH_VENDOR_ID:
cpu_mfr_info->patch_func = andes_errata_patch_func;
break;
#endif
#ifdef CONFIG_ERRATA_SIFIVE
case SIFIVE_VENDOR_ID:
cpu_mfr_info->patch_func = sifive_errata_patch_func;
Expand Down
43 changes: 43 additions & 0 deletions arch/riscv/mm/dma-noncoherent.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,56 @@
#include <linux/dma-map-ops.h>
#include <linux/mm.h>
#include <asm/cacheflush.h>
#include <asm/dma-noncoherent.h>

static bool noncoherent_supported __ro_after_init;
int dma_cache_alignment __ro_after_init = ARCH_DMA_MINALIGN;
EXPORT_SYMBOL_GPL(dma_cache_alignment);

struct riscv_nonstd_cache_ops noncoherent_cache_ops __ro_after_init = {
.wback = NULL,
.inv = NULL,
.wback_inv = NULL,
};

static inline void arch_dma_cache_wback(phys_addr_t paddr, size_t size)
{
void *vaddr = phys_to_virt(paddr);

#ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS
if (unlikely(noncoherent_cache_ops.wback)) {
noncoherent_cache_ops.wback(paddr, size);
return;
}
#endif
ALT_CMO_OP(clean, vaddr, size, riscv_cbom_block_size);
}

static inline void arch_dma_cache_inv(phys_addr_t paddr, size_t size)
{
void *vaddr = phys_to_virt(paddr);

#ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS
if (unlikely(noncoherent_cache_ops.inv)) {
noncoherent_cache_ops.inv(paddr, size);
return;
}
#endif

ALT_CMO_OP(inval, vaddr, size, riscv_cbom_block_size);
}

static inline void arch_dma_cache_wback_inv(phys_addr_t paddr, size_t size)
{
void *vaddr = phys_to_virt(paddr);

#ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS
if (unlikely(noncoherent_cache_ops.wback_inv)) {
noncoherent_cache_ops.wback_inv(paddr, size);
return;
}
#endif

ALT_CMO_OP(flush, vaddr, size, riscv_cbom_block_size);
}

Expand Down Expand Up @@ -97,6 +124,13 @@ void arch_dma_prep_coherent(struct page *page, size_t size)
{
void *flush_addr = page_address(page);

#ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS
if (unlikely(noncoherent_cache_ops.wback_inv)) {
noncoherent_cache_ops.wback_inv(page_to_phys(page), size);
return;
}
#endif

ALT_CMO_OP(flush, flush_addr, size, riscv_cbom_block_size);
}

Expand Down Expand Up @@ -128,3 +162,12 @@ void __init riscv_set_dma_cache_alignment(void)
if (!noncoherent_supported)
dma_cache_alignment = 1;
}

void riscv_noncoherent_register_cache_ops(const struct riscv_nonstd_cache_ops *ops)
{
if (!ops)
return;

noncoherent_cache_ops = *ops;
}
EXPORT_SYMBOL_GPL(riscv_noncoherent_register_cache_ops);
13 changes: 13 additions & 0 deletions arch/riscv/mm/pmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,28 @@
#include <linux/libnvdimm.h>

#include <asm/cacheflush.h>
#include <asm/dma-noncoherent.h>

void arch_wb_cache_pmem(void *addr, size_t size)
{
#ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS
if (unlikely(noncoherent_cache_ops.wback)) {
noncoherent_cache_ops.wback(virt_to_phys(addr), size);
return;
}
#endif
ALT_CMO_OP(clean, addr, size, riscv_cbom_block_size);
}
EXPORT_SYMBOL_GPL(arch_wb_cache_pmem);

void arch_invalidate_pmem(void *addr, size_t size)
{
#ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS
if (unlikely(noncoherent_cache_ops.inv)) {
noncoherent_cache_ops.inv(virt_to_phys(addr), size);
return;
}
#endif
ALT_CMO_OP(inval, addr, size, riscv_cbom_block_size);
}
EXPORT_SYMBOL_GPL(arch_invalidate_pmem);
Loading

0 comments on commit c23be91

Please sign in to comment.