Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nho/smmu gem integration #23

Merged
merged 5 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
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
47 changes: 31 additions & 16 deletions hw/arm/smmu500.c
Original file line number Diff line number Diff line change
Expand Up @@ -1660,7 +1660,7 @@ static IOMMUTLBEntry smmu_translate(IOMMUMemoryRegion *mr, hwaddr addr,
TBU *tbu = container_of(mr, TBU, iommu);
SMMU500State *s = tbu->smmu;
IOMMUTLBEntry ret = {
.target_as = tbu->as,
.target_as = tbu->target_as,
.translated_addr = addr,
.addr_mask = (1ULL << 12) - 1,
.perm = IOMMU_RW,
Expand Down Expand Up @@ -2199,35 +2199,50 @@ static void smmu500_realize(DeviceState *dev, Error **errp)
for (i = 0; i < s->cfg.num_cb; i++) {
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq.context[i]);
}

for (i = 0; i < MAX_TBU && s->tbu[i].target_mr; i++) {
char *name = g_strdup_printf("smmu-tbu%d", i);

s->tbu[i].target_as = g_new0(AddressSpace, 1);
address_space_init(s->tbu[i].target_as, s->tbu[i].target_mr, NULL);
memory_region_init_iommu(&s->tbu[i].iommu, sizeof(s->tbu[i].iommu),
TYPE_XILINX_SMMU500_IOMMU_MEMORY_REGION,
OBJECT(sbd),
name, UINT64_MAX);
/* Devices connected to s->tbu[i] are responsible for creating and
* initializing the AddressSpace they use when performing DMA
* operations through the tbu[i].iommu IOMMUMemoryRegion
*/
g_free(name);
s->tbu[i].smmu = s;
}

s->num_tbu = i;
}

static void smmu500_init(Object *obj)
{
SMMU500State *s = XILINX_SMMU500(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
int i;

object_property_add_link(obj, "dma", TYPE_MEMORY_REGION,
(Object **)&s->dma_mr,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_STRONG);

/* The SMMU_TBU_MR_PROP_NAME property should be set by the implementation
* of the machine into which the SMMU is being integrated. The index of the
* mr corresponds to the TBU index. Devices connected to a given TBU will
* have their DMA addresses translated into the target MemoryRegion as
* defined by this property.
*/
for (i = 0; i < MAX_TBU; i++) {
char *name = g_strdup_printf("smmu-tbu%d", i);

s->tbu[i].as = g_new0(AddressSpace, 1);
memory_region_init_iommu(&s->tbu[i].iommu, sizeof(s->tbu[i].iommu),
TYPE_XILINX_SMMU500_IOMMU_MEMORY_REGION,
OBJECT(sbd),
name, UINT64_MAX);
address_space_init(s->tbu[i].as,
MEMORY_REGION(&s->tbu[i].iommu),
name);
g_free(name);
s->tbu[i].smmu = s;
char *name = g_strdup_printf(SMMU_TBU_MR_PROP_NAME, i);
object_property_add_link(obj, name, TYPE_MEMORY_REGION,
(Object **)&s->tbu[i].target_mr,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_STRONG);
}

s->num_tbu = MAX_TBU;
}

static void smmu_free_rai(SMMU500State *s, RegisterAccessInfo *rai, int num)
Expand Down
23 changes: 21 additions & 2 deletions hw/arm/xlnx-versal.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,16 @@ static void versal_create_uarts(Versal *s, qemu_irq *pic)
}
}

static void versal_connect_dev_iommu(Versal *s,
DeviceState *dev,
const char *propname,
int tbuId)
{
object_property_set_link(OBJECT(dev), propname,
OBJECT(&s->fpd.smmu.tbu[tbuId].iommu),
&error_abort);
}

static void versal_create_canfds(Versal *s, qemu_irq *pic)
{
int i;
Expand Down Expand Up @@ -255,6 +265,8 @@ static void versal_create_gems(Versal *s, qemu_irq *pic)
for (i = 0; i < ARRAY_SIZE(s->lpd.iou.gem); i++) {
static const int irqs[] = { VERSAL_GEM0_IRQ_0, VERSAL_GEM1_IRQ_0};
static const uint64_t addrs[] = { MM_GEM0, MM_GEM1 };
static const int tbu_ids[] = {VERSAL_GEM0_TBUID, VERSAL_GEM1_TBUID };
static const int stream_ids[] = { VERSAL_GEM0_STREAM_ID, VERSAL_GEM1_STREAM_ID };
char *name = g_strdup_printf("gem%d", i);
DeviceState *dev;
MemoryRegion *mr;
Expand All @@ -266,8 +278,8 @@ static void versal_create_gems(Versal *s, qemu_irq *pic)
object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort);
object_property_set_int(OBJECT(dev), "num-priority-queues", 2,
&error_abort);
object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps),
&error_abort);
object_property_set_int(OBJECT(dev), "stream-id", stream_ids[i], &error_abort);
versal_connect_dev_iommu(s, dev, "dma", tbu_ids[i]);
sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);

mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
Expand Down Expand Up @@ -824,10 +836,17 @@ static void versal_create_smmu(Versal *s, qemu_irq *pic)
{
SysBusDevice *sbd;
MemoryRegion *mr;
int i;

object_initialize_child(OBJECT(s), "mmu-500", &s->fpd.smmu,
TYPE_XILINX_SMMU500);
sbd = SYS_BUS_DEVICE(&s->fpd.smmu);

for (i = 0; i < VERSAL_SMMU_TBUID_MAX; i++) {
char *name = g_strdup_printf(SMMU_TBU_MR_PROP_NAME, i);
object_property_set_link(OBJECT(sbd), name,
OBJECT(&s->mr_ps), &error_abort);
}
sysbus_realize(sbd, &error_fatal);

mr = sysbus_mmio_get_region(sbd, 0);
Expand Down
39 changes: 31 additions & 8 deletions hw/net/cadence_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,15 @@ static hwaddr gem_get_desc_addr(CadenceGEMState *s, bool tx, int q)
return desc_addr;
}

static void gem_set_dma_attrs(CadenceGEMState *s, MemTxAttrs *attrs)
{
/* set memory transaction requester_id attr to stream-id if available */
if (s->stream_id) {
attrs->requester_id = s->stream_id;
attrs->unspecified = 0;
}
}

static hwaddr gem_get_tx_desc_addr(CadenceGEMState *s, int q)
{
return gem_get_desc_addr(s, true, q);
Expand All @@ -1020,11 +1029,15 @@ static hwaddr gem_get_rx_desc_addr(CadenceGEMState *s, int q)
static void gem_get_rx_desc(CadenceGEMState *s, int q)
{
hwaddr desc_addr = gem_get_rx_desc_addr(s, q);
MemTxAttrs memattrs = MEMTXATTRS_UNSPECIFIED;

DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", desc_addr);

/* set mem transaction attrs for DMA */
gem_set_dma_attrs(s, &memattrs);

/* read current descriptor */
address_space_read(&s->dma_as, desc_addr, MEMTXATTRS_UNSPECIFIED,
address_space_read(&s->dma_as, desc_addr, memattrs,
s->rx_desc[q],
sizeof(uint32_t) * gem_get_desc_len(s, true));

Expand All @@ -1045,6 +1058,7 @@ static void gem_get_rx_desc(CadenceGEMState *s, int q)
static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
{
CadenceGEMState *s = qemu_get_nic_opaque(nc);
MemTxAttrs memattrs = MEMTXATTRS_UNSPECIFIED;
unsigned rxbufsize, bytes_to_copy;
unsigned rxbuf_offset;
uint8_t *rxbuf_ptr;
Expand Down Expand Up @@ -1136,6 +1150,9 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
return -1;
}

/* set mem transaction attrs for DMA */
gem_set_dma_attrs(s, &memattrs);

while (bytes_to_copy) {
hwaddr desc_addr;

Expand All @@ -1151,7 +1168,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
/* Copy packet data to emulated DMA buffer */
address_space_write(&s->dma_as, rx_desc_get_buffer(s, s->rx_desc[q]) +
rxbuf_offset,
MEMTXATTRS_UNSPECIFIED, rxbuf_ptr,
memattrs, rxbuf_ptr,
MIN(bytes_to_copy, rxbufsize));
rxbuf_ptr += MIN(bytes_to_copy, rxbufsize);
bytes_to_copy -= MIN(bytes_to_copy, rxbufsize);
Expand Down Expand Up @@ -1189,7 +1206,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)

/* Descriptor write-back. */
desc_addr = gem_get_rx_desc_addr(s, q);
address_space_write(&s->dma_as, desc_addr, MEMTXATTRS_UNSPECIFIED,
address_space_write(&s->dma_as, desc_addr, memattrs,
s->rx_desc[q],
sizeof(uint32_t) * gem_get_desc_len(s, true));

Expand Down Expand Up @@ -1271,6 +1288,7 @@ static void gem_transmit(CadenceGEMState *s)
{
uint32_t desc[DESC_MAX_NUM_WORDS];
hwaddr packet_desc_addr;
MemTxAttrs memattrs = MEMTXATTRS_UNSPECIFIED;
uint8_t *p;
unsigned total_bytes;
int q = 0;
Expand All @@ -1282,6 +1300,9 @@ static void gem_transmit(CadenceGEMState *s)

DB_PRINT("\n");

/* set mem transaction attributes for DMA */
gem_set_dma_attrs(s, &memattrs);

/* The packet we will hand off to QEMU.
* Packets scattered across multiple descriptors are gathered to this
* one contiguous buffer first.
Expand All @@ -1295,7 +1316,7 @@ static void gem_transmit(CadenceGEMState *s)

DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr);
address_space_read(&s->dma_as, packet_desc_addr,
MEMTXATTRS_UNSPECIFIED, desc,
memattrs, desc,
sizeof(uint32_t) * gem_get_desc_len(s, false));
/* Handle all descriptors owned by hardware */
while (tx_desc_get_used(desc) == 0) {
Expand Down Expand Up @@ -1330,7 +1351,7 @@ static void gem_transmit(CadenceGEMState *s)
* contig buffer.
*/
address_space_read(&s->dma_as, tx_desc_get_buffer(s, desc),
MEMTXATTRS_UNSPECIFIED,
memattrs,
p, tx_desc_get_length(desc));
p += tx_desc_get_length(desc);
total_bytes += tx_desc_get_length(desc);
Expand All @@ -1344,11 +1365,11 @@ static void gem_transmit(CadenceGEMState *s)
* the processor.
*/
address_space_read(&s->dma_as, desc_addr,
MEMTXATTRS_UNSPECIFIED, desc_first,
memattrs, desc_first,
sizeof(desc_first));
tx_desc_set_used(desc_first);
address_space_write(&s->dma_as, desc_addr,
MEMTXATTRS_UNSPECIFIED, desc_first,
memattrs, desc_first,
sizeof(desc_first));
/* Advance the hardware current descriptor past this packet */
if (tx_desc_get_wrap(desc)) {
Expand Down Expand Up @@ -1402,7 +1423,7 @@ static void gem_transmit(CadenceGEMState *s)
}
DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr);
address_space_read(&s->dma_as, packet_desc_addr,
MEMTXATTRS_UNSPECIFIED, desc,
memattrs, desc,
sizeof(uint32_t) * gem_get_desc_len(s, false));
}

Expand Down Expand Up @@ -1797,6 +1818,8 @@ static Property gem_properties[] = {
num_type2_screeners, 4),
DEFINE_PROP_UINT16("jumbo-max-len", CadenceGEMState,
jumbo_max_len, 10240),
DEFINE_PROP_UINT16("stream-id", CadenceGEMState,
stream_id, 0),
DEFINE_PROP_LINK("dma", CadenceGEMState, dma_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
DEFINE_PROP_END_OF_LIST(),
Expand Down
6 changes: 5 additions & 1 deletion include/hw/arm/smmu500.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,17 @@ OBJECT_DECLARE_SIMPLE_TYPE(SMMU500State, XILINX_SMMU500)

#define SMMU_R_MAX (2 * MAX_CB * SMMU_PAGESIZE)

/* Per-TBU Memory Region property name */
#define SMMU_TBU_MR_PROP_NAME "mr-%d"

/* Forward declaration */
struct SMMU500State;

typedef struct TBU {
SMMU500State *smmu;
IOMMUMemoryRegion iommu;
AddressSpace *as;
AddressSpace *target_as;
MemoryRegion *target_mr;
} TBU;

typedef struct SMMU500State {
Expand Down
18 changes: 18 additions & 0 deletions include/hw/arm/xlnx-versal.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,4 +357,22 @@ struct Versal {
#define MM_PMC_TRNG_SIZE 0x10000

#define MM_PMC_INT_CSR 0xf1330000

/* MMU-500 TBU device mapping
*
* It is system dependent which devices are connected to which TBU.
* The target DMA address space of each TBU is configured independently
* (see SMMU property SMMU_TBU_MR_PROP_NAME). Devices connected to the
* same TBU will have the same target translation address space.
*/
#define VERSAL_GEM0_TBUID 0x0
#define VERSAL_GEM1_TBUID 0x0
#define VERSAL_SMMU_TBUID_MAX VERSAL_GEM1_TBUID + 1

G_STATIC_ASSERT(VERSAL_SMMU_TBUID_MAX <= MAX_TBU);

/* SMMU Stream ID */
#define VERSAL_GEM0_STREAM_ID 0x234
#define VERSAL_GEM1_STREAM_ID 0x235

#endif
1 change: 1 addition & 0 deletions include/hw/net/cadence_gem.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ struct CadenceGEMState {
uint8_t num_type2_screeners;
uint32_t revision;
uint16_t jumbo_max_len;
uint16_t stream_id;

/* GEM registers backing store */
uint32_t regs[CADENCE_GEM_MAXREG];
Expand Down
Loading