iommu: dart: Support different variants with different registers

T8110 has a new register layout. To accommodate this, first move all the
register offsets to the hw structure, and rename all the existing
registers to DART_T8020_*.

Reviewed-by: Sven Peter <sven@svenpeter.dev>
Signed-off-by: Hector Martin <marcan@marcan.st>
Link: https://lore.kernel.org/r/20230113105029.26654-7-marcan@marcan.st
Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
Hector Martin 2023-01-13 19:50:29 +09:00 committed by Joerg Roedel
parent a772a02c18
commit b76c68fcb4

View file

@ -38,6 +38,7 @@
#define DART_MAX_TTBR 4 #define DART_MAX_TTBR 4
#define MAX_DARTS_PER_DEVICE 2 #define MAX_DARTS_PER_DEVICE 2
/* Common registers */
#define DART_PARAMS1 0x00 #define DART_PARAMS1 0x00
#define DART_PARAMS1_PAGE_SHIFT GENMASK(27, 24) #define DART_PARAMS1_PAGE_SHIFT GENMASK(27, 24)
@ -45,52 +46,78 @@
#define DART_PARAMS2 0x04 #define DART_PARAMS2 0x04
#define DART_PARAMS2_BYPASS_SUPPORT BIT(0) #define DART_PARAMS2_BYPASS_SUPPORT BIT(0)
#define DART_STREAM_COMMAND 0x20 /* T8020/T6000 registers */
#define DART_STREAM_COMMAND_BUSY BIT(2)
#define DART_STREAM_COMMAND_INVALIDATE BIT(20)
#define DART_STREAM_SELECT 0x34 #define DART_T8020_STREAM_COMMAND 0x20
#define DART_T8020_STREAM_COMMAND_BUSY BIT(2)
#define DART_T8020_STREAM_COMMAND_INVALIDATE BIT(20)
#define DART_ERROR 0x40 #define DART_T8020_STREAM_SELECT 0x34
#define DART_ERROR_STREAM GENMASK(27, 24)
#define DART_ERROR_CODE GENMASK(11, 0)
#define DART_ERROR_FLAG BIT(31)
#define DART_ERROR_READ_FAULT BIT(4) #define DART_T8020_ERROR 0x40
#define DART_ERROR_WRITE_FAULT BIT(3) #define DART_T8020_ERROR_STREAM GENMASK(27, 24)
#define DART_ERROR_NO_PTE BIT(2) #define DART_T8020_ERROR_CODE GENMASK(11, 0)
#define DART_ERROR_NO_PMD BIT(1) #define DART_T8020_ERROR_FLAG BIT(31)
#define DART_ERROR_NO_TTBR BIT(0)
#define DART_CONFIG 0x60 #define DART_T8020_ERROR_READ_FAULT BIT(4)
#define DART_CONFIG_LOCK BIT(15) #define DART_T8020_ERROR_WRITE_FAULT BIT(3)
#define DART_T8020_ERROR_NO_PTE BIT(2)
#define DART_T8020_ERROR_NO_PMD BIT(1)
#define DART_T8020_ERROR_NO_TTBR BIT(0)
#define DART_T8020_CONFIG 0x60
#define DART_T8020_CONFIG_LOCK BIT(15)
#define DART_STREAM_COMMAND_BUSY_TIMEOUT 100 #define DART_STREAM_COMMAND_BUSY_TIMEOUT 100
#define DART_ERROR_ADDR_HI 0x54 #define DART_T8020_ERROR_ADDR_HI 0x54
#define DART_ERROR_ADDR_LO 0x50 #define DART_T8020_ERROR_ADDR_LO 0x50
#define DART_STREAMS_ENABLE 0xfc #define DART_T8020_STREAMS_ENABLE 0xfc
#define DART_TCR(sid) (0x100 + 4 * (sid)) #define DART_T8020_TCR 0x100
#define DART_TCR_TRANSLATE_ENABLE BIT(7) #define DART_T8020_TCR_TRANSLATE_ENABLE BIT(7)
#define DART_TCR_BYPASS0_ENABLE BIT(8) #define DART_T8020_TCR_BYPASS_DART BIT(8)
#define DART_TCR_BYPASS1_ENABLE BIT(12) #define DART_T8020_TCR_BYPASS_DAPF BIT(12)
#define DART_TTBR_VALID BIT(31) #define DART_T8020_TTBR 0x200
#define DART_TTBR_SHIFT 12 #define DART_T8020_TTBR_VALID BIT(31)
#define DART_T8020_TTBR_ADDR_FIELD_SHIFT 0
#define DART_T8020_TTBR_SHIFT 12
#define DART_TTBR(dart, sid, idx) (0x200 + \ #define DART_TCR(dart, sid) ((dart)->hw->tcr + ((sid) << 2))
#define DART_TTBR(dart, sid, idx) ((dart)->hw->ttbr + \
(((dart)->hw->ttbr_count * (sid)) << 2) + \ (((dart)->hw->ttbr_count * (sid)) << 2) + \
((idx) << 2)) ((idx) << 2))
struct apple_dart_stream_map;
struct apple_dart_hw { struct apple_dart_hw {
irqreturn_t (*irq_handler)(int irq, void *dev);
int (*invalidate_tlb)(struct apple_dart_stream_map *stream_map);
u32 oas; u32 oas;
enum io_pgtable_fmt fmt; enum io_pgtable_fmt fmt;
int max_sid_count; int max_sid_count;
u64 lock;
u64 lock_bit;
u64 error;
u64 enable_streams;
u64 tcr;
u64 tcr_enabled;
u64 tcr_disabled;
u64 tcr_bypass;
u64 ttbr;
u64 ttbr_valid;
u64 ttbr_addr_field_shift;
u64 ttbr_shift;
int ttbr_count; int ttbr_count;
}; };
@ -217,8 +244,7 @@ apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map)
int sid; int sid;
for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
writel(DART_TCR_TRANSLATE_ENABLE, writel(dart->hw->tcr_enabled, dart->regs + DART_TCR(dart, sid));
dart->regs + DART_TCR(sid));
} }
static void apple_dart_hw_disable_dma(struct apple_dart_stream_map *stream_map) static void apple_dart_hw_disable_dma(struct apple_dart_stream_map *stream_map)
@ -227,7 +253,7 @@ static void apple_dart_hw_disable_dma(struct apple_dart_stream_map *stream_map)
int sid; int sid;
for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
writel(0, dart->regs + DART_TCR(sid)); writel(dart->hw->tcr_disabled, dart->regs + DART_TCR(dart, sid));
} }
static void static void
@ -238,8 +264,8 @@ apple_dart_hw_enable_bypass(struct apple_dart_stream_map *stream_map)
WARN_ON(!stream_map->dart->supports_bypass); WARN_ON(!stream_map->dart->supports_bypass);
for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
writel(DART_TCR_BYPASS0_ENABLE | DART_TCR_BYPASS1_ENABLE, writel(dart->hw->tcr_bypass,
dart->regs + DART_TCR(sid)); dart->regs + DART_TCR(dart, sid));
} }
static void apple_dart_hw_set_ttbr(struct apple_dart_stream_map *stream_map, static void apple_dart_hw_set_ttbr(struct apple_dart_stream_map *stream_map,
@ -248,9 +274,10 @@ static void apple_dart_hw_set_ttbr(struct apple_dart_stream_map *stream_map,
struct apple_dart *dart = stream_map->dart; struct apple_dart *dart = stream_map->dart;
int sid; int sid;
WARN_ON(paddr & ((1 << DART_TTBR_SHIFT) - 1)); WARN_ON(paddr & ((1 << dart->hw->ttbr_shift) - 1));
for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
writel(DART_TTBR_VALID | (paddr >> DART_TTBR_SHIFT), writel(dart->hw->ttbr_valid |
(paddr >> dart->hw->ttbr_shift) << dart->hw->ttbr_addr_field_shift,
dart->regs + DART_TTBR(dart, sid, idx)); dart->regs + DART_TTBR(dart, sid, idx));
} }
@ -274,7 +301,7 @@ apple_dart_hw_clear_all_ttbrs(struct apple_dart_stream_map *stream_map)
} }
static int static int
apple_dart_hw_stream_command(struct apple_dart_stream_map *stream_map, apple_dart_t8020_hw_stream_command(struct apple_dart_stream_map *stream_map,
u32 command) u32 command)
{ {
unsigned long flags; unsigned long flags;
@ -283,12 +310,12 @@ apple_dart_hw_stream_command(struct apple_dart_stream_map *stream_map,
spin_lock_irqsave(&stream_map->dart->lock, flags); spin_lock_irqsave(&stream_map->dart->lock, flags);
writel(stream_map->sidmap[0], stream_map->dart->regs + DART_STREAM_SELECT); writel(stream_map->sidmap[0], stream_map->dart->regs + DART_T8020_STREAM_SELECT);
writel(command, stream_map->dart->regs + DART_STREAM_COMMAND); writel(command, stream_map->dart->regs + DART_T8020_STREAM_COMMAND);
ret = readl_poll_timeout_atomic( ret = readl_poll_timeout_atomic(
stream_map->dart->regs + DART_STREAM_COMMAND, command_reg, stream_map->dart->regs + DART_T8020_STREAM_COMMAND, command_reg,
!(command_reg & DART_STREAM_COMMAND_BUSY), 1, !(command_reg & DART_T8020_STREAM_COMMAND_BUSY), 1,
DART_STREAM_COMMAND_BUSY_TIMEOUT); DART_STREAM_COMMAND_BUSY_TIMEOUT);
spin_unlock_irqrestore(&stream_map->dart->lock, flags); spin_unlock_irqrestore(&stream_map->dart->lock, flags);
@ -304,10 +331,10 @@ apple_dart_hw_stream_command(struct apple_dart_stream_map *stream_map,
} }
static int static int
apple_dart_hw_invalidate_tlb(struct apple_dart_stream_map *stream_map) apple_dart_t8020_hw_invalidate_tlb(struct apple_dart_stream_map *stream_map)
{ {
return apple_dart_hw_stream_command(stream_map, return apple_dart_t8020_hw_stream_command(
DART_STREAM_COMMAND_INVALIDATE); stream_map, DART_T8020_STREAM_COMMAND_INVALIDATE);
} }
static int apple_dart_hw_reset(struct apple_dart *dart) static int apple_dart_hw_reset(struct apple_dart *dart)
@ -316,8 +343,8 @@ static int apple_dart_hw_reset(struct apple_dart *dart)
struct apple_dart_stream_map stream_map; struct apple_dart_stream_map stream_map;
int i; int i;
config = readl(dart->regs + DART_CONFIG); config = readl(dart->regs + dart->hw->lock);
if (config & DART_CONFIG_LOCK) { if (config & dart->hw->lock_bit) {
dev_err(dart->dev, "DART is locked down until reboot: %08x\n", dev_err(dart->dev, "DART is locked down until reboot: %08x\n",
config); config);
return -EINVAL; return -EINVAL;
@ -331,12 +358,12 @@ static int apple_dart_hw_reset(struct apple_dart *dart)
/* enable all streams globally since TCR is used to control isolation */ /* enable all streams globally since TCR is used to control isolation */
for (i = 0; i < BITS_TO_U32(dart->num_streams); i++) for (i = 0; i < BITS_TO_U32(dart->num_streams); i++)
writel(U32_MAX, dart->regs + DART_STREAMS_ENABLE + 4 * i); writel(U32_MAX, dart->regs + dart->hw->enable_streams + 4 * i);
/* clear any pending errors before the interrupt is unmasked */ /* clear any pending errors before the interrupt is unmasked */
writel(readl(dart->regs + DART_ERROR), dart->regs + DART_ERROR); writel(readl(dart->regs + dart->hw->error), dart->regs + dart->hw->error);
return apple_dart_hw_invalidate_tlb(&stream_map); return dart->hw->invalidate_tlb(&stream_map);
} }
static void apple_dart_domain_flush_tlb(struct apple_dart_domain *domain) static void apple_dart_domain_flush_tlb(struct apple_dart_domain *domain)
@ -351,7 +378,7 @@ static void apple_dart_domain_flush_tlb(struct apple_dart_domain *domain)
for (j = 0; j < BITS_TO_LONGS(stream_map.dart->num_streams); j++) for (j = 0; j < BITS_TO_LONGS(stream_map.dart->num_streams); j++)
stream_map.sidmap[j] = atomic_long_read(&domain_stream_map->sidmap[j]); stream_map.sidmap[j] = atomic_long_read(&domain_stream_map->sidmap[j]);
apple_dart_hw_invalidate_tlb(&stream_map); stream_map.dart->hw->invalidate_tlb(&stream_map);
} }
} }
@ -425,7 +452,7 @@ apple_dart_setup_translation(struct apple_dart_domain *domain,
apple_dart_hw_clear_ttbr(stream_map, i); apple_dart_hw_clear_ttbr(stream_map, i);
apple_dart_hw_enable_translation(stream_map); apple_dart_hw_enable_translation(stream_map);
apple_dart_hw_invalidate_tlb(stream_map); stream_map->dart->hw->invalidate_tlb(stream_map);
} }
static int apple_dart_finalize_domain(struct iommu_domain *domain, static int apple_dart_finalize_domain(struct iommu_domain *domain,
@ -816,30 +843,30 @@ static const struct iommu_ops apple_dart_iommu_ops = {
} }
}; };
static irqreturn_t apple_dart_irq(int irq, void *dev) static irqreturn_t apple_dart_t8020_irq(int irq, void *dev)
{ {
struct apple_dart *dart = dev; struct apple_dart *dart = dev;
const char *fault_name = NULL; const char *fault_name = NULL;
u32 error = readl(dart->regs + DART_ERROR); u32 error = readl(dart->regs + DART_T8020_ERROR);
u32 error_code = FIELD_GET(DART_ERROR_CODE, error); u32 error_code = FIELD_GET(DART_T8020_ERROR_CODE, error);
u32 addr_lo = readl(dart->regs + DART_ERROR_ADDR_LO); u32 addr_lo = readl(dart->regs + DART_T8020_ERROR_ADDR_LO);
u32 addr_hi = readl(dart->regs + DART_ERROR_ADDR_HI); u32 addr_hi = readl(dart->regs + DART_T8020_ERROR_ADDR_HI);
u64 addr = addr_lo | (((u64)addr_hi) << 32); u64 addr = addr_lo | (((u64)addr_hi) << 32);
u8 stream_idx = FIELD_GET(DART_ERROR_STREAM, error); u8 stream_idx = FIELD_GET(DART_T8020_ERROR_STREAM, error);
if (!(error & DART_ERROR_FLAG)) if (!(error & DART_T8020_ERROR_FLAG))
return IRQ_NONE; return IRQ_NONE;
/* there should only be a single bit set but let's use == to be sure */ /* there should only be a single bit set but let's use == to be sure */
if (error_code == DART_ERROR_READ_FAULT) if (error_code == DART_T8020_ERROR_READ_FAULT)
fault_name = "READ FAULT"; fault_name = "READ FAULT";
else if (error_code == DART_ERROR_WRITE_FAULT) else if (error_code == DART_T8020_ERROR_WRITE_FAULT)
fault_name = "WRITE FAULT"; fault_name = "WRITE FAULT";
else if (error_code == DART_ERROR_NO_PTE) else if (error_code == DART_T8020_ERROR_NO_PTE)
fault_name = "NO PTE FOR IOVA"; fault_name = "NO PTE FOR IOVA";
else if (error_code == DART_ERROR_NO_PMD) else if (error_code == DART_T8020_ERROR_NO_PMD)
fault_name = "NO PMD FOR IOVA"; fault_name = "NO PMD FOR IOVA";
else if (error_code == DART_ERROR_NO_TTBR) else if (error_code == DART_T8020_ERROR_NO_TTBR)
fault_name = "NO TTBR FOR IOVA"; fault_name = "NO TTBR FOR IOVA";
else else
fault_name = "unknown"; fault_name = "unknown";
@ -849,7 +876,7 @@ static irqreturn_t apple_dart_irq(int irq, void *dev)
"translation fault: status:0x%x stream:%d code:0x%x (%s) at 0x%llx", "translation fault: status:0x%x stream:%d code:0x%x (%s) at 0x%llx",
error, stream_idx, error_code, fault_name, addr); error, stream_idx, error_code, fault_name, addr);
writel(error, dart->regs + DART_ERROR); writel(error, dart->regs + DART_T8020_ERROR);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -911,7 +938,7 @@ static int apple_dart_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err_clk_disable; goto err_clk_disable;
ret = request_irq(dart->irq, apple_dart_irq, IRQF_SHARED, ret = request_irq(dart->irq, dart->hw->irq_handler, IRQF_SHARED,
"apple-dart fault handler", dart); "apple-dart fault handler", dart);
if (ret) if (ret)
goto err_clk_disable; goto err_clk_disable;
@ -959,17 +986,51 @@ static int apple_dart_remove(struct platform_device *pdev)
} }
static const struct apple_dart_hw apple_dart_hw_t8103 = { static const struct apple_dart_hw apple_dart_hw_t8103 = {
.irq_handler = apple_dart_t8020_irq,
.invalidate_tlb = apple_dart_t8020_hw_invalidate_tlb,
.oas = 36, .oas = 36,
.fmt = APPLE_DART, .fmt = APPLE_DART,
.max_sid_count = 16, .max_sid_count = 16,
.enable_streams = DART_T8020_STREAMS_ENABLE,
.lock = DART_T8020_CONFIG,
.lock_bit = DART_T8020_CONFIG_LOCK,
.error = DART_T8020_ERROR,
.tcr = DART_T8020_TCR,
.tcr_enabled = DART_T8020_TCR_TRANSLATE_ENABLE,
.tcr_disabled = 0,
.tcr_bypass = DART_T8020_TCR_BYPASS_DAPF | DART_T8020_TCR_BYPASS_DART,
.ttbr = DART_T8020_TTBR,
.ttbr_valid = DART_T8020_TTBR_VALID,
.ttbr_addr_field_shift = DART_T8020_TTBR_ADDR_FIELD_SHIFT,
.ttbr_shift = DART_T8020_TTBR_SHIFT,
.ttbr_count = 4, .ttbr_count = 4,
}; };
static const struct apple_dart_hw apple_dart_hw_t6000 = { static const struct apple_dart_hw apple_dart_hw_t6000 = {
.irq_handler = apple_dart_t8020_irq,
.invalidate_tlb = apple_dart_t8020_hw_invalidate_tlb,
.oas = 42, .oas = 42,
.fmt = APPLE_DART2, .fmt = APPLE_DART2,
.max_sid_count = 16, .max_sid_count = 16,
.enable_streams = DART_T8020_STREAMS_ENABLE,
.lock = DART_T8020_CONFIG,
.lock_bit = DART_T8020_CONFIG_LOCK,
.error = DART_T8020_ERROR,
.tcr = DART_T8020_TCR,
.tcr_enabled = DART_T8020_TCR_TRANSLATE_ENABLE,
.tcr_disabled = 0,
.tcr_bypass = DART_T8020_TCR_BYPASS_DAPF | DART_T8020_TCR_BYPASS_DART,
.ttbr = DART_T8020_TTBR,
.ttbr_valid = DART_T8020_TTBR_VALID,
.ttbr_addr_field_shift = DART_T8020_TTBR_ADDR_FIELD_SHIFT,
.ttbr_shift = DART_T8020_TTBR_SHIFT,
.ttbr_count = 4, .ttbr_count = 4,
}; };
@ -979,7 +1040,7 @@ static __maybe_unused int apple_dart_suspend(struct device *dev)
unsigned int sid, idx; unsigned int sid, idx;
for (sid = 0; sid < dart->num_streams; sid++) { for (sid = 0; sid < dart->num_streams; sid++) {
dart->save_tcr[sid] = readl_relaxed(dart->regs + DART_TCR(sid)); dart->save_tcr[sid] = readl_relaxed(dart->regs + DART_TCR(dart, sid));
for (idx = 0; idx < dart->hw->ttbr_count; idx++) for (idx = 0; idx < dart->hw->ttbr_count; idx++)
dart->save_ttbr[sid][idx] = dart->save_ttbr[sid][idx] =
readl(dart->regs + DART_TTBR(dart, sid, idx)); readl(dart->regs + DART_TTBR(dart, sid, idx));
@ -1004,7 +1065,7 @@ static __maybe_unused int apple_dart_resume(struct device *dev)
for (idx = 0; idx < dart->hw->ttbr_count; idx++) for (idx = 0; idx < dart->hw->ttbr_count; idx++)
writel(dart->save_ttbr[sid][idx], writel(dart->save_ttbr[sid][idx],
dart->regs + DART_TTBR(dart, sid, idx)); dart->regs + DART_TTBR(dart, sid, idx));
writel(dart->save_tcr[sid], dart->regs + DART_TCR(sid)); writel(dart->save_tcr[sid], dart->regs + DART_TCR(dart, sid));
} }
return 0; return 0;