-
Notifications
You must be signed in to change notification settings - Fork 9
/
wormhole.c
221 lines (174 loc) · 7.76 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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
// 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"
#include "hwmon.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 ARC_CSM_START (0x1FE80000 - 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);
}
static struct tt_attribute_data wh_attributes[] = {
{ __ATTR(tt_aiclk, S_IRUGO, tt_show_attribute, NULL), 0x60, 0xFFFF },
{ __ATTR(tt_axiclk, S_IRUGO, tt_show_attribute, NULL), 0x64, 0xFFFF },
{ __ATTR(tt_arcclk, S_IRUGO, tt_show_attribute, NULL), 0x68, 0xFFFF },
{ __ATTR(tt_card_type, S_IRUGO, tt_show_card_type, NULL), 0x10, 0x0 },
{ __ATTR(tt_serial, S_IRUGO, tt_show_card_serial, NULL), 0x10, 0x0 },
{ __ATTR(tt_arc_fw_ver, S_IRUGO, tt_show_fw_ver, NULL), 0x18, 0x0 },
{ __ATTR(tt_eth_fw_ver, S_IRUGO, tt_show_eth_fw_ver, NULL), 0x2C, 0x0 },
{ __ATTR(tt_m3bl_fw_ver, S_IRUGO, tt_show_fw_ver, NULL), 0x30, 0x0 },
{ __ATTR(tt_m3app_fw_ver, S_IRUGO, tt_show_fw_ver, NULL), 0x34, 0x0 },
{ __ATTR(tt_ttflash_ver, S_IRUGO, tt_show_fw_ver, NULL), 0xB8, 0x0 },
{ __ATTR(tt_fw_bundle_ver, S_IRUGO, tt_show_fw_ver, NULL), 0xC4, 0x0 },
{ __ATTR_NULL, 0, 0 }
};
static u32 wh_arc_addr_to_sysreg(u32 arc_addr) {
return ARC_CSM_START + (arc_addr - 0x10000000);
}
// 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 const struct tt_hwmon_attr wh_hwmon_attributes[] = {
{ hwmon_temp, hwmon_temp_input, 0x74, 0, GENMASK(15, 0), 64 },
{ hwmon_temp, hwmon_temp_max, 0x8c, 0, GENMASK(15, 0), 1000 },
{ hwmon_in, hwmon_in_input, 0x70, 0, GENMASK(31, 0), 1 },
{ hwmon_in, hwmon_in_max, 0x88, 16, GENMASK(15, 0), 1 },
{ hwmon_curr, hwmon_curr_input, 0x84, 0, GENMASK(15, 0), 1000 },
{ hwmon_curr, hwmon_curr_max, 0x84, 16, GENMASK(15, 0), 1000 },
{ hwmon_power, hwmon_power_input, 0x80, 0, GENMASK(15, 0), 1000000 },
{ hwmon_power, hwmon_power_max, 0x80, 16, GENMASK(15, 0), 1000000 },
{ .reg_offset = TT_HWMON_ATTR_END },
};
static const struct tt_hwmon_label wh_hwmon_labels[] = {
{ hwmon_temp, hwmon_temp_label, "asic1_temp" },
{ hwmon_in, hwmon_in_label, "vcore1" },
{ hwmon_curr, hwmon_curr_label, "current1" },
{ hwmon_power, hwmon_power_label, "power1" },
{ .name = NULL },
};
static const struct hwmon_channel_info *wh_hwmon_info[] = {
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX),
HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_MAX),
HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_MAX),
HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_LABEL | HWMON_P_MAX),
NULL,
};
static const struct hwmon_chip_info wh_hwmon_chip_info = {
.ops = &tt_hwmon_ops,
.info = wh_hwmon_info,
};
static void wormhole_hwmon_init(struct wormhole_device *wh_dev) {
struct tenstorrent_device *tt_dev = &wh_dev->tt;
struct device *dev = &tt_dev->pdev->dev;
struct tt_hwmon_context *context = &tt_dev->hwmon_context;
struct device *hwmon_device;
u32 telemetry_offset;
if (!grayskull_read_fw_telemetry_offset(reset_unit_regs(wh_dev), &telemetry_offset))
goto wormhole_hwmon_init_err;
context->attributes = wh_hwmon_attributes;
context->labels = wh_hwmon_labels;
context->telemetry_base = wh_dev->bar4_mapping + wh_arc_addr_to_sysreg(telemetry_offset);
hwmon_device = devm_hwmon_device_register_with_info(dev, "wormhole", context, &wh_hwmon_chip_info, NULL);
if (IS_ERR(hwmon_device))
goto wormhole_hwmon_init_err;
tt_dev->attributes = wh_attributes;
return;
wormhole_hwmon_init_err:
dev_warn(dev, "Failed to initialize hwmon.\n");
}
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 bool wormhole_post_hardware_init(struct tenstorrent_device *tt_dev) {
struct wormhole_device *wh_dev = tt_dev_to_wh_dev(tt_dev);
wormhole_hwmon_init(wh_dev);
return true;
}
static void wormhole_cleanup_hardware(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));
}
static void wormhole_cleanup(struct tenstorrent_device *tt_dev) {
struct wormhole_device *wh_dev = tt_dev_to_wh_dev(tt_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);
}
struct tenstorrent_device_class wormhole_class = {
.name = "Wormhole",
.instance_size = sizeof(struct wormhole_device),
.dma_address_bits = 32,
.init_device = wormhole_init,
.init_hardware = wormhole_init_hardware,
.post_hardware_init = wormhole_post_hardware_init,
.cleanup_hardware = wormhole_cleanup_hardware,
.cleanup_device = wormhole_cleanup,
.reboot = wormhole_cleanup_hardware,
};