Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 29 additions & 143 deletions drivers/remoteproc/adi_remoteproc.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Analog Device SHARC Image Loader for SC5XX processors
Expand All @@ -11,13 +11,12 @@
*/

#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/dmaengine.h>
#include <linux/firmware.h>
#include <linux/elf.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_ring.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
Expand All @@ -26,7 +25,6 @@
#include <linux/platform_device.h>
#include <linux/remoteproc.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>

#include <linux/soc/adi/icc.h>
#include <linux/soc/adi/rcu.h>
Expand All @@ -35,22 +33,17 @@
/* location of bootrom that loops idle */
#define SHARC_IDLE_ADDR (0x00090004)

#define SPU_MDMA0_SRC_ID 88
#define SPU_MDMA0_DST_ID 89

#define CORE_INIT_TIMEOUT_MS (2000)
#define CORE_INIT_TIMEOUT msecs_to_jiffies(CORE_INIT_TIMEOUT_MS)

#define MEMORY_COUNT 2

#define ADI_FW_LDR 0
#define ADI_FW_ELF 1

#define NUM_TABLE_ENTRIES 1
/* Resource table for the given remote */

struct bcode_flag_t {
uint32_t bCode:4, /* 0-3 */
u32 bCode:4, /* 0-3 */
bFlag_save:1, /* 4 */
bFlag_aux:1, /* 5 */
bReserved:1, /* 6 */
Expand Down Expand Up @@ -87,6 +80,7 @@
struct sharc_resource_table rsc_table;
} __packed;


Check warning on line 83 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / checks / checks

checkpatch: Please don't use multiple blank lines

Check warning on line 83 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / checks / checks

checkpatch: Please don't use multiple blank lines
#define VRING_ALIGN 0x1000
#define VRING_DEFAULT_SIZE 0x800

Expand Down Expand Up @@ -147,9 +141,6 @@
int core_irq;
int icc_irq;
int icc_irq_flags;
void *mem_virt;
dma_addr_t mem_handle;
size_t fw_size;
unsigned long ldr_load_addr;
int firmware_format;
void __iomem *L1_shared_base;
Expand Down Expand Up @@ -189,7 +180,7 @@

if (rproc_data->adi_rsc_table != NULL) {
rproc_data->rpmsg_state = ADI_RP_RPMSG_WAITING;
ret = devm_request_threaded_irq(rproc_data->dev,

Check warning on line 183 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / checks / checks

coccicheck: 8-33 WARNING Threaded IRQ with no primary handler requested without IRQF_ONESHOT (unless it is nested IRQ)

Check warning on line 183 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / checks / checks

coccicheck: 8-33 WARNING Threaded IRQ with no primary handler requested without IRQF_ONESHOT (unless it is nested IRQ)
rproc_data->icc_irq, NULL,
sharc_virtio_irq_threaded_handler,
rproc_data->icc_irq_flags,
Expand Down Expand Up @@ -229,114 +220,52 @@
return hdr->bcode_flag.bFlag_ignore || (hdr->byte_count == 0);
}

static void load_callback(void *p)
{
struct completion *cmp = p;

complete(cmp);
}

/* @todo this needs to return status */
/* @todo the error paths here leak tremendously, this needs further cleanup */
static void ldr_load(struct adi_rproc_data *rproc_data)
static void ldr_load(struct adi_rproc_data *rproc_data, const u8 *fw_data)
{
struct ldr_hdr *block_hdr = NULL;
struct ldr_hdr *next_hdr = NULL;
u8 *virbuf = (u8 *) rproc_data->mem_virt;
dma_addr_t phybuf = rproc_data->mem_handle;
struct ldr_hdr *block_hdr;
const u8 *virbuf = fw_data;
void __iomem *target;
u32 addr;
int offset;
// part of verify buffer code
// int i;
// uint32_t verfied = 0;
// uint8_t *pCompareBuffer;
// uint8_t *pVerifyBuffer;
struct dma_chan *chan = dma_find_channel(DMA_MEMCPY);
struct dma_async_tx_descriptor *tx;
struct completion cmp;

if (!chan) {
dev_err(rproc_data->dev, "Could not find dma memcpy channel\n");
return;
}

init_completion(&cmp);

do {
/* read the header */
block_hdr = (struct ldr_hdr *) virbuf;
offset = sizeof(struct ldr_hdr) + (block_hdr->bcode_flag.bFlag_fill ?
0 : block_hdr->byte_count);
next_hdr = (struct ldr_hdr *) (virbuf + offset);
tx = NULL;
addr = block_hdr->target_addr;

/* Overwrite the ldr_load_addr */
if (block_hdr->bcode_flag.bFlag_first)
rproc_data->ldr_load_addr = (unsigned long)block_hdr->target_addr;
rproc_data->ldr_load_addr = (unsigned long)addr;

if (!is_empty(block_hdr)) {
if (block_hdr->bcode_flag.bFlag_fill) {
tx = dmaengine_prep_dma_memset(chan,
block_hdr->target_addr,
block_hdr->argument,
block_hdr->byte_count, 0);
} else {
tx = dmaengine_prep_dma_memcpy(chan,
block_hdr->target_addr,
phybuf + sizeof(struct ldr_hdr),
block_hdr->byte_count, 0);

// if (rproc_data->verify) {
// @todo implement verification
// pCompareBuffer = virbuf + sizeof(struct ldr_hdr);
// pVerifyBuffer = virbuf + rproc_data->fw_size;
//
// dma_memcpy(phybuf + rproc_data->fw_size,
// block_hdr->target_addr,
// block_hdr->byte_count);
//
// /* check the data */
// for (i = 0; i < block_hdr->byte_count; i++) {
// if (pCompareBuffer[i] != pVerifyBuffer[i]) {
// dev_err(rproc_data->dev,
// "dirty data, compare[%d]:0x%x,"
// "verify[%d]:0x%x\n",
// i, pCompareBuffer[i], i,
// pVerifyBuffer[i]);
// verfied++;
// break;
// }
// }
// }
}

if (!tx) {
dev_err(rproc_data->dev, "Failed to allocate dma transaction\n");
if (addr >= rproc_data->l1_da_range[0] &&
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where this ranges comes from L2 only for vring's or L3. Firmware is loaded to L3

addr < rproc_data->l1_da_range[1])
target = rproc_data->L1_shared_base + addr;
else if (addr >= rproc_data->l2_da_range[0] &&
addr < rproc_data->l2_da_range[1])
target = rproc_data->L2_shared_base +
(addr - rproc_data->l2_da_range[0]);
else {

Check warning on line 249 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / checks / checks

checkpatch: Unbalanced braces around else statement + else {

Check warning on line 249 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / checks / checks

checkpatch: Unbalanced braces around else statement + else {
dev_err(rproc_data->dev,
"Target 0x%08x outside mapped ranges\n", addr);
return;
}

if (is_final(block_hdr) || (is_final(next_hdr) && is_empty(next_hdr))) {
tx->callback = load_callback;
tx->callback_param = &cmp;
}
dmaengine_submit(tx);
dma_async_issue_pending(chan);
if (block_hdr->bcode_flag.bFlag_fill)
memset_io(target, block_hdr->argument,
block_hdr->byte_count);
else
memcpy_toio(target,
virbuf + sizeof(struct ldr_hdr),
block_hdr->byte_count);
}

if (is_final(block_hdr)) {
wait_for_completion(&cmp);
if (is_final(block_hdr))
break;
}

virbuf += offset;
phybuf += offset;
} while (1);

// if (rproc_data->verify) {
// if (verfied == 0)
// dev_err(rproc_data->dev, "success to verify all the data\n");
// else
// dev_err(rproc_data->dev, "fail to verify all the data %d\n", verfied);
// }
}

static int adi_valid_firmware(struct rproc *rproc, const struct firmware *fw)
Expand All @@ -358,40 +287,10 @@
return -EINVAL;
}

void set_spu_securep_msec(u16 n, bool msec);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In comment section
'''
MDMA writes to SHARC L2 memory (0x200xxxxx) are silently rejected at the bus fabric level on ADSP-SC573 and ADSP-SC589. The MDMA engine stalls waiting for a write ACK that never comes (DMA_STAT.RUN=4, IRQERR=0), and the remoteproc driver times out.
''' does it means that SPU is enabled , when transaction is running and actually that error because SPU is enabled by other cores? And isn't this just suppressing error rather fixing underlying issue?

static void enable_spu(void)
{
set_spu_securep_msec(SPU_MDMA0_SRC_ID, true);
set_spu_securep_msec(SPU_MDMA0_DST_ID, true);
}

static void disable_spu(void)
{
set_spu_securep_msec(SPU_MDMA0_SRC_ID, false);
set_spu_securep_msec(SPU_MDMA0_DST_ID, false);
}

static int adi_ldr_load(struct adi_rproc_data *rproc_data,
const struct firmware *fw)
{
rproc_data->fw_size = fw->size;
if (!rproc_data->mem_virt) {
rproc_data->mem_virt = dma_alloc_coherent(rproc_data->dev,
fw->size * MEMORY_COUNT,
&rproc_data->mem_handle,
GFP_KERNEL);
if (rproc_data->mem_virt == NULL) {
dev_err(rproc_data->dev, "Unable to allocate memory\n");
return -ENOMEM;
}
}

memcpy((char *)rproc_data->mem_virt, fw->data, fw->size);

enable_spu();
ldr_load(rproc_data);
disable_spu();

ldr_load(rproc_data, fw->data);
return 0;
}

Expand Down Expand Up @@ -468,14 +367,6 @@
if (ret)
return ret;

if (rproc_data->mem_virt) {
memset(rproc_data->mem_virt, 0, rproc_data->fw_size * MEMORY_COUNT);
dma_free_coherent(rproc_data->dev, rproc_data->fw_size * MEMORY_COUNT,
rproc_data->mem_virt, rproc_data->mem_handle);
rproc_data->mem_virt = NULL;
rproc_data->fw_size = 0;
}

rproc_data->ldr_load_addr = SHARC_IDLE_ADDR;
rproc_data->loaded_rsc_table = NULL;
return ret;
Expand Down Expand Up @@ -518,7 +409,7 @@
struct device *dev = rproc->dev.parent;
void *va;

va = ioremap_wc(mem->dma, mem->len);

Check warning on line 412 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / build_gcc_arm / build

kernel_sparse: incorrect type in assignment (different address spaces)

Check warning on line 412 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / build_gcc_arm / build

kernel_sparse: incorrect type in assignment (different address spaces)
if (!va) {
dev_err(dev, "Unable to map memory carveout %pa+%zx\n", &mem->dma, mem->len);
return -ENOMEM;
Expand All @@ -529,7 +420,7 @@

static int adi_rproc_unmap_carveout(struct rproc *rproc, struct rproc_mem_entry *mem)
{
iounmap(mem->va);

Check warning on line 423 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / build_gcc_arm / build

kernel_sparse: incorrect type in argument 1 (different address spaces)

Check warning on line 423 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / build_gcc_arm / build

kernel_sparse: incorrect type in argument 1 (different address spaces)
return 0;
}

Expand Down Expand Up @@ -786,9 +677,9 @@
return NULL;

if (da >= rproc_data->l1_da_range[0] && da < rproc_data->l1_da_range[1])
ret = L1_shared_base + da;

Check warning on line 680 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / build_gcc_arm / build

kernel_sparse: incorrect type in assignment (different address spaces)

Check warning on line 680 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / build_gcc_arm / build

kernel_sparse: incorrect type in assignment (different address spaces)
else if (da >= rproc_data->l2_da_range[0] && da < rproc_data->l2_da_range[1])
ret = L2_shared_base + (da - rproc_data->l2_da_range[0]);

Check warning on line 682 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / build_gcc_arm / build

kernel_sparse: incorrect type in assignment (different address spaces)

Check warning on line 682 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / build_gcc_arm / build

kernel_sparse: incorrect type in assignment (different address spaces)

return ret;
}
Expand Down Expand Up @@ -894,7 +785,7 @@
goto free_adi_rcu;
}

rproc_data->adi_rsc_table = devm_ioremap_wc(dev,

Check warning on line 788 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / build_gcc_arm / build

kernel_sparse: incorrect type in assignment (different address spaces)

Check warning on line 788 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / build_gcc_arm / build

kernel_sparse: incorrect type in assignment (different address spaces)
rmem->base,
rmem->size);
if (IS_ERR(rproc_data->adi_rsc_table)) {
Expand All @@ -905,7 +796,7 @@

rproc_data->icc_irq = platform_get_irq(pdev, 0);
if (rproc_data->icc_irq <= 0) {
dev_err(dev, "No ICC IRQ specified\n");

Check warning on line 799 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / checks / checks

coccicheck: 3-10 line 799 is redundant because platform_get_irq() already prints an error

Check warning on line 799 in drivers/remoteproc/adi_remoteproc.c

View workflow job for this annotation

GitHub Actions / checks / checks

coccicheck: 3-10 line 799 is redundant because platform_get_irq() already prints an error
ret = -ENOENT;
goto free_adi_rcu;
}
Expand Down Expand Up @@ -971,8 +862,6 @@
rproc_data->tru = adi_tru;
rproc_data->rproc = rproc;
rproc_data->firmware_name = name;
rproc_data->mem_virt = NULL;
rproc_data->fw_size = 0;
rproc_data->ldr_load_addr = SHARC_IDLE_ADDR;
rproc_data->rpmsg_state = ADI_RP_RPMSG_TIMED_OUT;

Expand All @@ -982,8 +871,6 @@
goto free_workqueue;
}

dmaengine_get();

return 0;

free_workqueue:
Expand All @@ -1005,7 +892,6 @@
{
struct adi_rproc_data *rproc_data = platform_get_drvdata(pdev);

dmaengine_put();
put_adi_tru(rproc_data->tru);
put_adi_rcu(rproc_data->rcu);
rproc_del(rproc_data->rproc);
Expand Down
Loading