Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
76 changes: 76 additions & 0 deletions drivers/accel/amdxdna/aie.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
* Copyright (C) 2026, Advanced Micro Devices, Inc.
*/

#include <drm/drm_cache.h>
#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/log2.h>
#include <linux/sizes.h>
#include <linux/slab.h>

#include "aie.h"
#include "amdxdna_mailbox_helper.h"
Expand Down Expand Up @@ -119,3 +124,74 @@ void amdxdna_vbnv_init(struct amdxdna_dev *xdna)
if (!xdna->vbnv)
xdna->vbnv = info->default_vbnv;
}

struct aie_dma_hdl *aie_dma_buf_alloc(struct amdxdna_dev *xdna, u32 size,
enum dma_data_direction dir)
{
struct aie_dma_hdl *hdl;
int order;

size = max_t(u32, size, SZ_8K);
order = get_order(size);
if (order > MAX_PAGE_ORDER)
return ERR_PTR(-EINVAL);

hdl = kzalloc(sizeof(*hdl), GFP_KERNEL);
if (!hdl)
return ERR_PTR(-ENOMEM);

hdl->aligned_size = PAGE_SIZE << order;

if (amdxdna_iova_on(xdna)) {
hdl->vaddr = amdxdna_iommu_alloc(xdna, hdl->aligned_size, &hdl->dma_addr);
if (IS_ERR(hdl->vaddr)) {
int ret = PTR_ERR(hdl->vaddr);

kfree(hdl);
return ERR_PTR(ret);
}
} else {
hdl->vaddr = dma_alloc_noncoherent(xdna->ddev.dev,
hdl->aligned_size,
&hdl->dma_addr, dir,
GFP_KERNEL);
if (!hdl->vaddr) {
kfree(hdl);
return ERR_PTR(-ENOMEM);
}
}

hdl->size = size;
hdl->xdna = xdna;
hdl->dir = dir;

return hdl;
}

void aie_dma_buf_free(struct aie_dma_hdl *hdl)
{
if (!hdl)
return;

if (amdxdna_iova_on(hdl->xdna)) {
amdxdna_iommu_free(hdl->xdna, hdl->aligned_size, hdl->vaddr, hdl->dma_addr);
} else {
dma_free_noncoherent(hdl->xdna->ddev.dev, hdl->aligned_size,
hdl->vaddr, hdl->dma_addr, hdl->dir);
}

memset(hdl, 0, sizeof(*hdl));
kfree(hdl);
}

int aie_dma_buf_clflush(struct aie_dma_hdl *hdl, u32 offset, size_t size)
{
if (!hdl)
return -EINVAL;

if (offset + size > hdl->size)
return -EINVAL;

drm_clflush_virt_range(hdl->vaddr + offset, size ? size : hdl->size);
return 0;
}
29 changes: 29 additions & 0 deletions drivers/accel/amdxdna/aie.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#ifndef _AIE_H_
#define _AIE_H_

#include <linux/dma-mapping.h>

#include "amdxdna_pci_drv.h"
#include "amdxdna_mailbox.h"

Expand Down Expand Up @@ -88,13 +90,40 @@ struct amdxdna_rev_vbnv {
const char *vbnv;
};

/*
* struct aie_dma_hdl - DMA buffer handle for firmware communication
* @xdna: back-pointer to the device
* @dir: DMA data direction
* @vaddr: kernel virtual address
* @dma_addr: device DMA address
* @size: requested buffer size
* @aligned_size: actual allocation size (power-of-2 aligned for FW)
*/
struct aie_dma_hdl {
struct amdxdna_dev *xdna;
enum dma_data_direction dir;
void *vaddr;
dma_addr_t dma_addr;
size_t size;
size_t aligned_size;
};

#define to_dma_addr(hdl, off) ((hdl)->dma_addr + (off))
#define to_cpu_addr(hdl, off) ((hdl)->vaddr + (off))
#define to_buf_size(hdl) ((hdl)->aligned_size)

/* aie.c */
void aie_dump_mgmt_chann_debug(struct aie_device *aie);
void aie_destroy_chann(struct aie_device *aie, struct mailbox_channel **chann);
int aie_send_mgmt_msg_wait(struct aie_device *aie, struct xdna_mailbox_msg *msg);
int aie_check_protocol(struct aie_device *aie, u32 fw_major, u32 fw_minor);
void amdxdna_vbnv_init(struct amdxdna_dev *xdna);

struct aie_dma_hdl *aie_dma_buf_alloc(struct amdxdna_dev *xdna, u32 size,
enum dma_data_direction dir);
void aie_dma_buf_free(struct aie_dma_hdl *hdl);
int aie_dma_buf_clflush(struct aie_dma_hdl *hdl, u32 offset, size_t size);

/* aie_psp.c */
struct psp_device *aiem_psp_create(struct drm_device *ddev, struct psp_config *conf);
int aie_psp_start(struct psp_device *psp);
Expand Down
24 changes: 11 additions & 13 deletions drivers/accel/amdxdna/aie2_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/kthread.h>
#include <linux/kernel.h>

#include "aie.h"
#include "aie2_msg_priv.h"
#include "aie2_pci.h"
#include "amdxdna_error.h"
Expand All @@ -29,9 +30,7 @@ struct async_event {

struct async_events {
struct workqueue_struct *wq;
u8 *buf;
dma_addr_t addr;
u32 size;
struct aie_dma_hdl *dma_buf;
u32 event_cnt;
struct async_event event[] __counted_by(event_cnt);
};
Expand Down Expand Up @@ -338,7 +337,7 @@ void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev)
destroy_workqueue(events->wq);
mutex_lock(&xdna->dev_lock);

aie2_free_msg_buffer(ndev, events->size, events->buf, events->addr);
aie_dma_buf_free(events->dma_buf);
kfree(events);
}

Expand All @@ -354,12 +353,11 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev)
if (!events)
return -ENOMEM;

events->buf = aie2_alloc_msg_buffer(ndev, &total_size, &events->addr);
if (IS_ERR(events->buf)) {
ret = PTR_ERR(events->buf);
events->dma_buf = aie_dma_buf_alloc(xdna, total_size, DMA_FROM_DEVICE);
if (IS_ERR(events->dma_buf)) {
ret = PTR_ERR(events->dma_buf);
goto free_events;
}
events->size = total_size;
events->event_cnt = total_col;

events->wq = alloc_ordered_workqueue("async_wq", 0);
Expand All @@ -374,8 +372,8 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev)

e->ndev = ndev;
e->wq = events->wq;
e->buf = &events->buf[offset];
e->addr = events->addr + offset;
e->buf = to_cpu_addr(events->dma_buf, offset);
e->addr = to_dma_addr(events->dma_buf, offset);
e->size = ASYNC_BUF_SIZE;
e->resp.status = MAX_AIE2_STATUS_CODE;
INIT_WORK(&e->work, aie2_error_worker);
Expand All @@ -387,14 +385,14 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev)

ndev->async_events = events;

XDNA_DBG(xdna, "Async event count %d, buf total size 0x%x",
events->event_cnt, events->size);
XDNA_DBG(xdna, "Async event count %d, buf total size 0x%zx",
events->event_cnt, to_buf_size(events->dma_buf));
return 0;

free_wq:
destroy_workqueue(events->wq);
free_buf:
aie2_free_msg_buffer(ndev, events->size, events->buf, events->addr);
aie_dma_buf_free(events->dma_buf);
free_events:
kfree(events);
return ret;
Expand Down
Loading