Skip to content

Commit ffe1972

Browse files
hoshinolinajannau
authored andcommitted
media: apple: isp: Remove ioread/iowrite and stop doing raw address translation
Translating IOVAs via the DART and then trying to access physical memory directly is slow and error-prone. We know what surfaces IOVAs are supposed to be part of, so we can use the surface vmap to access the contents. Where we get an IOVA from the firmware, assert that it is within the expected range before accessing it. Since we're using threaded IRQs now, this also lets us get rid of the deferred vmap. Signed-off-by: Asahi Lina <lina@asahilina.net>
1 parent ba38b68 commit ffe1972

9 files changed

Lines changed: 130 additions & 89 deletions

File tree

drivers/media/platform/apple/isp/isp-cam.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ static int isp_ch_load_setfile(struct apple_isp *isp, u32 ch)
323323
return -EINVAL;
324324
}
325325

326-
isp_iowrite(isp, isp->data_surf->iova, (void *)fw->data, setfile->size);
326+
memcpy(isp->data_surf->virt, (void *)fw->data, setfile->size);
327327
release_firmware(fw);
328328

329329
return isp_cmd_ch_set_file_load(isp, ch, isp->data_surf->iova,

drivers/media/platform/apple/isp/isp-cmd.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ static int cisp_send(struct apple_isp *isp, void *args, u32 insize, u32 outsize)
2424
req->arg1 = insize;
2525
req->arg2 = outsize;
2626

27-
isp_iowrite(isp, isp->cmd_iova, args, insize);
27+
memcpy(isp->cmd_virt, args, insize);
2828
err = ipc_chan_send(isp, chan, CISP_TIMEOUT);
2929
if (err) {
3030
u64 opcode;
@@ -45,7 +45,8 @@ static int cisp_send_read(struct apple_isp *isp, void *args, u32 insize,
4545
int err = cisp_send(isp, args, insize, outsize);
4646
if (err)
4747
return err;
48-
isp_ioread(isp, isp->cmd_iova, args, outsize);
48+
49+
memcpy(args, isp->cmd_virt, outsize);
4950
return 0;
5051
}
5152

drivers/media/platform/apple/isp/isp-drv.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct isp_surf {
3232
struct drm_mm_node *mm;
3333
struct list_head head;
3434
u64 size;
35+
u64 type;
3536
u32 num_pages;
3637
struct page **pages;
3738
struct sg_table sgt;
@@ -60,6 +61,7 @@ struct isp_channel {
6061
u32 num;
6162
u64 size;
6263
dma_addr_t iova;
64+
void *virt;
6365
u32 doorbell;
6466
u32 cursor;
6567
spinlock_t lock;
@@ -210,6 +212,8 @@ struct apple_isp {
210212
struct isp_surf *ipc_surf;
211213
struct isp_surf *extra_surf;
212214
struct isp_surf *data_surf;
215+
struct isp_surf *log_surf;
216+
struct isp_surf *bt_surf;
213217
struct list_head gc;
214218
struct workqueue_struct *wq;
215219

@@ -225,6 +229,7 @@ struct apple_isp {
225229

226230
wait_queue_head_t wait;
227231
dma_addr_t cmd_iova;
232+
void *cmd_virt;
228233

229234
unsigned long state;
230235
spinlock_t buf_lock;

drivers/media/platform/apple/isp/isp-fw.c

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/* Copyright 2023 Eileen Yoon <eyn@gmx.com> */
33

4+
#include "isp-fw.h"
5+
6+
#include <asm/io.h>
47
#include <linux/delay.h>
58
#include <linux/pm_runtime.h>
69
#include <linux/types.h>
@@ -38,6 +41,35 @@ static inline void isp_gpio_write32(struct apple_isp *isp, u32 reg, u32 val)
3841
writel(val, isp->gpio + reg);
3942
}
4043

44+
void *apple_isp_translate(struct apple_isp *isp, struct isp_surf *surf,
45+
dma_addr_t iova, size_t size)
46+
{
47+
dma_addr_t end = iova + size;
48+
if (!surf) {
49+
dev_err(isp->dev,
50+
"Failed to translate IPC iova 0x%llx (0x%zx): No surface\n",
51+
(long long)iova, size);
52+
return NULL;
53+
}
54+
55+
if (end < iova || iova < surf->iova ||
56+
end > (surf->iova + surf->size)) {
57+
dev_err(isp->dev,
58+
"Failed to translate IPC iova 0x%llx (0x%zx): Out of bounds\n",
59+
(long long)iova, size);
60+
return NULL;
61+
}
62+
63+
if (!surf->virt) {
64+
dev_err(isp->dev,
65+
"Failed to translate IPC iova 0x%llx (0x%zx): No VMap\n",
66+
(long long)iova, size);
67+
return NULL;
68+
}
69+
70+
return surf->virt + (iova - surf->iova);
71+
}
72+
4173
struct isp_firmware_bootargs {
4274
u32 pad_0[2];
4375
u64 ipc_iova;
@@ -232,13 +264,17 @@ int apple_isp_alloc_firmware_surface(struct apple_isp *isp)
232264
isp_err(isp, "failed to alloc shared surface for ipc\n");
233265
return -ENOMEM;
234266
}
267+
dev_info(isp->dev, "IPC surface iova: 0x%llx\n",
268+
(long long)isp->ipc_surf->iova);
235269

236270
isp->data_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_DATA_SIZE);
237271
if (!isp->data_surf) {
238272
isp_err(isp, "failed to alloc shared surface for data files\n");
239273
isp_free_surface(isp, isp->ipc_surf);
240274
return -ENOMEM;
241275
}
276+
dev_info(isp->dev, "Data surface iova: 0x%llx\n",
277+
(long long)isp->data_surf->iova);
242278

243279
return 0;
244280
}
@@ -258,6 +294,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp)
258294
{
259295
struct isp_firmware_bootargs args;
260296
dma_addr_t args_iova;
297+
void *args_virt;
261298
int err, retries;
262299

263300
u32 num_ipc_chans = isp_gpio_read32(isp, ISP_GPIO_0);
@@ -281,7 +318,9 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp)
281318
}
282319

283320
args_iova = isp->ipc_surf->iova + args_offset + 0x40;
321+
args_virt = isp->ipc_surf->virt + args_offset + 0x40;
284322
isp->cmd_iova = args_iova + sizeof(args) + 0x40;
323+
isp->cmd_virt = args_virt + sizeof(args) + 0x40;
285324

286325
memset(&args, 0, sizeof(args));
287326
args.ipc_iova = isp->ipc_surf->iova;
@@ -295,7 +334,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp)
295334
args.unk7 = 0x1; // 0?
296335
args.unk_iova1 = args_iova + sizeof(args) - 0xc;
297336
args.unk9 = 0x3;
298-
isp_iowrite(isp, args_iova, &args, sizeof(args));
337+
memcpy(args_virt, &args, sizeof(args));
299338

300339
isp_gpio_write32(isp, ISP_GPIO_0, args_iova);
301340
isp_gpio_write32(isp, ISP_GPIO_1, args_iova >> 32);
@@ -355,7 +394,15 @@ static void isp_free_channel_info(struct apple_isp *isp)
355394
static int isp_fill_channel_info(struct apple_isp *isp)
356395
{
357396
u64 table_iova = isp_gpio_read32(isp, ISP_GPIO_0) |
358-
((u64)isp_gpio_read32(isp, ISP_GPIO_1)) << 32;
397+
((u64)isp_gpio_read32(isp, ISP_GPIO_1)) << 32;
398+
void *table_virt = apple_isp_ipc_translate(
399+
isp, table_iova,
400+
sizeof(struct isp_chan_desc) * isp->num_ipc_chans);
401+
402+
if (!table_virt) {
403+
dev_err(isp->dev, "Failed to find channel table\n");
404+
return -EIO;
405+
}
359406

360407
isp->ipc_chans = kcalloc(isp->num_ipc_chans,
361408
sizeof(struct isp_channel *), GFP_KERNEL);
@@ -364,24 +411,31 @@ static int isp_fill_channel_info(struct apple_isp *isp)
364411

365412
for (int i = 0; i < isp->num_ipc_chans; i++) {
366413
struct isp_chan_desc desc;
367-
dma_addr_t desc_iova = table_iova + (i * sizeof(desc));
414+
void *desc_virt = table_virt + (i * sizeof(desc));
368415
struct isp_channel *chan =
369416
kzalloc(sizeof(struct isp_channel), GFP_KERNEL);
370417
if (!chan)
371418
goto out;
372419
isp->ipc_chans[i] = chan;
373420

374-
isp_ioread(isp, desc_iova, &desc, sizeof(desc));
421+
memcpy(&desc, desc_virt, sizeof(desc));
375422
chan->name = kstrdup(desc.name, GFP_KERNEL);
376423
chan->type = desc.type;
377424
chan->src = desc.src;
378425
chan->doorbell = 1 << chan->src;
379426
chan->num = desc.num;
380427
chan->size = desc.num * ISP_IPC_MESSAGE_SIZE;
381428
chan->iova = desc.iova;
429+
chan->virt =
430+
apple_isp_ipc_translate(isp, desc.iova, chan->size);
382431
chan->cursor = 0;
383432
spin_lock_init(&chan->lock);
384433

434+
if (!chan->virt) {
435+
dev_err(isp->dev, "Failed to find channel buffer\n");
436+
goto out;
437+
}
438+
385439
if ((chan->type != ISP_IPC_CHAN_TYPE_COMMAND) &&
386440
(chan->type != ISP_IPC_CHAN_TYPE_REPLY) &&
387441
(chan->type != ISP_IPC_CHAN_TYPE_REPORT)) {
@@ -439,11 +493,11 @@ static int isp_firmware_boot_stage3(struct apple_isp *isp)
439493
continue;
440494
for (int j = 0; j < chan->num; j++) {
441495
struct isp_message msg;
442-
dma_addr_t msg_iova = chan->iova + (j * sizeof(msg));
496+
void *msg_virt = chan->virt + (j * sizeof(msg));
443497

444498
memset(&msg, 0, sizeof(msg));
445499
msg.arg0 = ISP_IPC_FLAG_ACK;
446-
isp_iowrite(isp, msg_iova, &msg, sizeof(msg));
500+
memcpy(msg_virt, &msg, sizeof(msg));
447501
}
448502
}
449503
wmb();
@@ -547,6 +601,10 @@ static int isp_start_command_processor(struct apple_isp *isp)
547601
static void isp_collect_gc_surface(struct apple_isp *isp)
548602
{
549603
struct isp_surf *tmp, *surf;
604+
605+
isp->log_surf = NULL;
606+
isp->bt_surf = NULL;
607+
550608
list_for_each_entry_safe_reverse(surf, tmp, &isp->gc, head) {
551609
isp_dbg(isp, "freeing iova: 0x%llx size: 0x%llx virt: %pS\n",
552610
surf->iova, surf->size, (void *)surf->virt);

drivers/media/platform/apple/isp/isp-fw.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,13 @@ void apple_isp_free_firmware_surface(struct apple_isp *isp);
1212
int apple_isp_firmware_boot(struct apple_isp *isp);
1313
void apple_isp_firmware_shutdown(struct apple_isp *isp);
1414

15+
void *apple_isp_translate(struct apple_isp *isp, struct isp_surf *surf,
16+
dma_addr_t iova, size_t size);
17+
18+
static inline void *apple_isp_ipc_translate(struct apple_isp *isp,
19+
dma_addr_t iova, size_t size)
20+
{
21+
return apple_isp_translate(isp, isp->ipc_surf, iova, size);
22+
}
23+
1524
#endif /* __ISP_FW_H__ */

drivers/media/platform/apple/isp/isp-iommu.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,12 +213,6 @@ void isp_free_surface(struct apple_isp *isp, struct isp_surf *surf)
213213
}
214214
}
215215

216-
void *isp_iotranslate(struct apple_isp *isp, dma_addr_t iova)
217-
{
218-
phys_addr_t phys = iommu_iova_to_phys(isp->domain, iova);
219-
return phys_to_virt(phys);
220-
}
221-
222216
int apple_isp_iommu_map_sgt(struct apple_isp *isp, struct isp_surf *surf,
223217
struct sg_table *sgt, u64 size)
224218
{

drivers/media/platform/apple/isp/isp-iommu.h

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,6 @@ struct isp_surf *__isp_alloc_surface(struct apple_isp *isp, u64 size, bool gc);
1212
struct isp_surf *isp_alloc_surface_vmap(struct apple_isp *isp, u64 size);
1313
int isp_surf_vmap(struct apple_isp *isp, struct isp_surf *surf);
1414
void isp_free_surface(struct apple_isp *isp, struct isp_surf *surf);
15-
void *isp_iotranslate(struct apple_isp *isp, dma_addr_t iova);
16-
17-
static inline void isp_ioread(struct apple_isp *isp, dma_addr_t iova,
18-
void *data, u64 size)
19-
{
20-
void *virt = isp_iotranslate(isp, iova);
21-
memcpy(data, virt, size);
22-
}
23-
24-
static inline void isp_iowrite(struct apple_isp *isp, dma_addr_t iova,
25-
void *data, u64 size)
26-
{
27-
void *virt = isp_iotranslate(isp, iova);
28-
memcpy(virt, data, size);
29-
}
3015

3116
int apple_isp_iommu_map_sgt(struct apple_isp *isp, struct isp_surf *surf,
3217
struct sg_table *sgt, u64 size);

0 commit comments

Comments
 (0)