forked from tenstorrent/tt-kmd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwormhole.c
132 lines (100 loc) · 4.26 KB
/
wormhole.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// SPDX-FileCopyrightText: © 2023 Tenstorrent Inc.
// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h>
#include "wormhole.h"
#include "grayskull.h"
#include "pcie.h"
#include "module.h"
#define WH_FW_MSG_PCIE_INDEX 0x51
#define WH_FW_MSG_ASTATE0 0xA0
#define WH_FW_MSG_UPDATE_M3_AUTO_RESET_TIMEOUT 0xBC
// The iATU can be used to match & remap PCIE transactions.
#define IATU_BASE 0x1200 // Relative to the start of BAR2
#define IATU_OUTBOUND 0
#define IATU_INBOUND 1
#define IATU_REGION_STRIDE 0x100
#define IATU_REGION_CTRL_1_INBOUND 0x00
#define IATU_REGION_CTRL_2_INBOUND 0x04
#define IATU_LOWER_TARGET_ADDR_INBOUND 0x14
#define IATU_UPPER_TARGET_ADDR_INBOUND 0x18
// IATU_REGION_CTRL_2_INBOUND fields
#define REGION_EN (1 << 31)
#define BAR_MATCH_MODE (1 << 30)
#define FUZZY_TYPE_MATCH (1 << 27) // MRd, MWr, MRdLk are considered the same.
#define BAR_NUM(n) ((n) << 8)
// BAR4 is 32MB and will be mapped to the system registers from 0x1E000000
// to 0x20000000.
#define BAR4_SOC_TARGET_ADDRESS 0x1E000000
#define RESET_UNIT_START (0x1FF30000 - BAR4_SOC_TARGET_ADDRESS)
#define WRITE_IATU_REG(wh_dev, direction, region, reg, value) \
write_iatu_reg(wh_dev, IATU_##direction, region, \
IATU_##reg##_##direction, (value))
static void write_iatu_reg(struct wormhole_device *wh_dev, unsigned direction,
unsigned region, unsigned reg, u32 value) {
u32 offset = IATU_BASE + (2 * region + direction) * IATU_REGION_STRIDE
+ reg;
iowrite32(value, wh_dev->bar2_mapping + offset);
}
// Program the iATU so that BAR4 is directed to the system registers.
static void map_bar4_to_system_registers(struct wormhole_device *wh_dev) {
u32 region_ctrl_2 = REGION_EN | BAR_MATCH_MODE | FUZZY_TYPE_MATCH | BAR_NUM(4);
WRITE_IATU_REG(wh_dev, INBOUND, 1, LOWER_TARGET_ADDR, BAR4_SOC_TARGET_ADDRESS);
WRITE_IATU_REG(wh_dev, INBOUND, 1, UPPER_TARGET_ADDR, 0);
WRITE_IATU_REG(wh_dev, INBOUND, 1, REGION_CTRL_1, 0);
WRITE_IATU_REG(wh_dev, INBOUND, 1, REGION_CTRL_2, region_ctrl_2);
}
static u8 __iomem *reset_unit_regs(struct wormhole_device *wh_dev) {
return wh_dev->bar4_mapping + RESET_UNIT_START;
}
static void update_device_index(struct wormhole_device *wh_dev) {
static const u8 INDEX_VALID = 0x80;
grayskull_send_arc_fw_message_with_args(reset_unit_regs(wh_dev),
WH_FW_MSG_PCIE_INDEX,
wh_dev->tt.ordinal | INDEX_VALID, 0,
10*1000, NULL);
}
static bool wormhole_init(struct tenstorrent_device *tt_dev) {
struct wormhole_device *wh_dev = tt_dev_to_wh_dev(tt_dev);
wh_dev->bar2_mapping = pci_iomap(wh_dev->tt.pdev, 2, 0);
if (wh_dev->bar2_mapping == NULL) goto fail_bar2;
wh_dev->bar4_mapping = pci_iomap(wh_dev->tt.pdev, 4, 0);
if (wh_dev->bar4_mapping == NULL) goto fail_bar4;
return true;
fail_bar4:
pci_iounmap(wh_dev->tt.pdev, wh_dev->bar2_mapping);
fail_bar2:
return false;
}
static bool wormhole_init_hardware(struct tenstorrent_device *tt_dev) {
struct wormhole_device *wh_dev = tt_dev_to_wh_dev(tt_dev);
map_bar4_to_system_registers(wh_dev);
if (arc_l2_is_running(reset_unit_regs(wh_dev))) {
grayskull_send_curr_date(reset_unit_regs(wh_dev));
grayskull_send_arc_fw_message(reset_unit_regs(wh_dev), WH_FW_MSG_ASTATE0, 10000, NULL);
update_device_index(wh_dev);
complete_pcie_init(&wh_dev->tt, reset_unit_regs(wh_dev));
grayskull_send_arc_fw_message_with_args(reset_unit_regs(wh_dev), WH_FW_MSG_UPDATE_M3_AUTO_RESET_TIMEOUT, auto_reset_timeout, 0, 10000, NULL);
}
return true;
}
static void wormhole_cleanup(struct tenstorrent_device *tt_dev) {
struct wormhole_device *wh_dev = tt_dev_to_wh_dev(tt_dev);
grayskull_shutdown_firmware(tt_dev->pdev, reset_unit_regs(wh_dev));
if (wh_dev->bar2_mapping != NULL)
pci_iounmap(wh_dev->tt.pdev, wh_dev->bar2_mapping);
if (wh_dev->bar4_mapping != NULL)
pci_iounmap(wh_dev->tt.pdev, wh_dev->bar4_mapping);
}
static void wormhole_reboot(struct tenstorrent_device *tt_dev) {
struct wormhole_device *wh_dev = tt_dev_to_wh_dev(tt_dev);
grayskull_shutdown_firmware(tt_dev->pdev, reset_unit_regs(wh_dev));
}
struct tenstorrent_device_class wormhole_class = {
.name = "Wormhole",
.instance_size = sizeof(struct wormhole_device),
.init_device = wormhole_init,
.init_hardware = wormhole_init_hardware,
.cleanup_device = wormhole_cleanup,
.reboot = wormhole_reboot,
};