blob: 0d5a80b2d07a5b7f2487f60712283b6b708634fb [file] [log] [blame]
Andreas Noeverc90553b2014-06-03 22:04:11 +02001/*
2 * Thunderbolt Cactus Ridge driver - eeprom access
3 *
4 * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
5 */
6
Andreas Noevercd22e732014-06-12 23:11:46 +02007#include <linux/crc32.h>
Andreas Noeverc90553b2014-06-03 22:04:11 +02008#include "tb.h"
9
10/**
11 * tb_eeprom_ctl_write() - write control word
12 */
13static int tb_eeprom_ctl_write(struct tb_switch *sw, struct tb_eeprom_ctl *ctl)
14{
15 return tb_sw_write(sw, ctl, TB_CFG_SWITCH, sw->cap_plug_events + 4, 1);
16}
17
18/**
19 * tb_eeprom_ctl_write() - read control word
20 */
21static int tb_eeprom_ctl_read(struct tb_switch *sw, struct tb_eeprom_ctl *ctl)
22{
23 return tb_sw_read(sw, ctl, TB_CFG_SWITCH, sw->cap_plug_events + 4, 1);
24}
25
26enum tb_eeprom_transfer {
27 TB_EEPROM_IN,
28 TB_EEPROM_OUT,
29};
30
31/**
32 * tb_eeprom_active - enable rom access
33 *
34 * WARNING: Always disable access after usage. Otherwise the controller will
35 * fail to reprobe.
36 */
37static int tb_eeprom_active(struct tb_switch *sw, bool enable)
38{
39 struct tb_eeprom_ctl ctl;
40 int res = tb_eeprom_ctl_read(sw, &ctl);
41 if (res)
42 return res;
43 if (enable) {
44 ctl.access_high = 1;
45 res = tb_eeprom_ctl_write(sw, &ctl);
46 if (res)
47 return res;
48 ctl.access_low = 0;
49 return tb_eeprom_ctl_write(sw, &ctl);
50 } else {
51 ctl.access_low = 1;
52 res = tb_eeprom_ctl_write(sw, &ctl);
53 if (res)
54 return res;
55 ctl.access_high = 0;
56 return tb_eeprom_ctl_write(sw, &ctl);
57 }
58}
59
60/**
61 * tb_eeprom_transfer - transfer one bit
62 *
63 * If TB_EEPROM_IN is passed, then the bit can be retrieved from ctl->data_in.
64 * If TB_EEPROM_OUT is passed, then ctl->data_out will be written.
65 */
66static int tb_eeprom_transfer(struct tb_switch *sw, struct tb_eeprom_ctl *ctl,
67 enum tb_eeprom_transfer direction)
68{
69 int res;
70 if (direction == TB_EEPROM_OUT) {
71 res = tb_eeprom_ctl_write(sw, ctl);
72 if (res)
73 return res;
74 }
75 ctl->clock = 1;
76 res = tb_eeprom_ctl_write(sw, ctl);
77 if (res)
78 return res;
79 if (direction == TB_EEPROM_IN) {
80 res = tb_eeprom_ctl_read(sw, ctl);
81 if (res)
82 return res;
83 }
84 ctl->clock = 0;
85 return tb_eeprom_ctl_write(sw, ctl);
86}
87
88/**
89 * tb_eeprom_out - write one byte to the bus
90 */
91static int tb_eeprom_out(struct tb_switch *sw, u8 val)
92{
93 struct tb_eeprom_ctl ctl;
94 int i;
95 int res = tb_eeprom_ctl_read(sw, &ctl);
96 if (res)
97 return res;
98 for (i = 0; i < 8; i++) {
99 ctl.data_out = val & 0x80;
100 res = tb_eeprom_transfer(sw, &ctl, TB_EEPROM_OUT);
101 if (res)
102 return res;
103 val <<= 1;
104 }
105 return 0;
106}
107
108/**
109 * tb_eeprom_in - read one byte from the bus
110 */
111static int tb_eeprom_in(struct tb_switch *sw, u8 *val)
112{
113 struct tb_eeprom_ctl ctl;
114 int i;
115 int res = tb_eeprom_ctl_read(sw, &ctl);
116 if (res)
117 return res;
118 *val = 0;
119 for (i = 0; i < 8; i++) {
120 *val <<= 1;
121 res = tb_eeprom_transfer(sw, &ctl, TB_EEPROM_IN);
122 if (res)
123 return res;
124 *val |= ctl.data_in;
125 }
126 return 0;
127}
128
129/**
130 * tb_eeprom_read_n - read count bytes from offset into val
131 */
132static int tb_eeprom_read_n(struct tb_switch *sw, u16 offset, u8 *val,
133 size_t count)
134{
135 int i, res;
136 res = tb_eeprom_active(sw, true);
137 if (res)
138 return res;
139 res = tb_eeprom_out(sw, 3);
140 if (res)
141 return res;
142 res = tb_eeprom_out(sw, offset >> 8);
143 if (res)
144 return res;
145 res = tb_eeprom_out(sw, offset);
146 if (res)
147 return res;
148 for (i = 0; i < count; i++) {
149 res = tb_eeprom_in(sw, val + i);
150 if (res)
151 return res;
152 }
153 return tb_eeprom_active(sw, false);
154}
155
Andreas Noevercd22e732014-06-12 23:11:46 +0200156static u8 tb_crc8(u8 *data, int len)
Andreas Noeverc90553b2014-06-03 22:04:11 +0200157{
Andreas Noevercd22e732014-06-12 23:11:46 +0200158 int i, j;
159 u8 val = 0xff;
160 for (i = 0; i < len; i++) {
161 val ^= data[i];
162 for (j = 0; j < 8; j++)
163 val = (val << 1) ^ ((val & 0x80) ? 7 : 0);
164 }
165 return val;
166}
167
168static u32 tb_crc32(void *data, size_t len)
169{
170 return ~__crc32c_le(~0, data, len);
171}
172
173#define TB_DROM_DATA_START 13
174struct tb_drom_header {
175 /* BYTE 0 */
176 u8 uid_crc8; /* checksum for uid */
177 /* BYTES 1-8 */
178 u64 uid;
179 /* BYTES 9-12 */
180 u32 data_crc32; /* checksum for data_len bytes starting at byte 13 */
181 /* BYTE 13 */
182 u8 device_rom_revision; /* should be <= 1 */
183 u16 data_len:10;
184 u8 __unknown1:6;
185 /* BYTES 16-21 */
186 u16 vendor_id;
187 u16 model_id;
188 u8 model_rev;
189 u8 eeprom_rev;
190} __packed;
191
192enum tb_drom_entry_type {
193 TB_DROM_ENTRY_GENERIC,
194 TB_DROM_ENTRY_PORT,
195};
196
197struct tb_drom_entry_header {
198 u8 len;
199 u8 index:6;
200 bool port_disabled:1; /* only valid if type is TB_DROM_ENTRY_PORT */
201 enum tb_drom_entry_type type:1;
202} __packed;
203
204struct tb_drom_entry_port {
205 /* BYTES 0-1 */
206 struct tb_drom_entry_header header;
207 /* BYTE 2 */
208 u8 dual_link_port_rid:4;
209 u8 link_nr:1;
210 u8 unknown1:2;
211 bool has_dual_link_port:1;
212
213 /* BYTE 3 */
214 u8 dual_link_port_nr:6;
215 u8 unknown2:2;
216
217 /* BYTES 4 - 5 TODO decode */
218 u8 micro2:4;
219 u8 micro1:4;
220 u8 micro3;
221
222 /* BYTES 5-6, TODO: verify (find hardware that has these set) */
223 u8 peer_port_rid:4;
224 u8 unknown3:3;
225 bool has_peer_port:1;
226 u8 peer_port_nr:6;
227 u8 unknown4:2;
228} __packed;
229
230
231/**
232 * tb_eeprom_get_drom_offset - get drom offset within eeprom
233 */
234int tb_eeprom_get_drom_offset(struct tb_switch *sw, u16 *offset)
235{
Andreas Noeverc90553b2014-06-03 22:04:11 +0200236 struct tb_cap_plug_events cap;
237 int res;
238 if (!sw->cap_plug_events) {
239 tb_sw_warn(sw, "no TB_CAP_PLUG_EVENTS, cannot read eeprom\n");
240 return -ENOSYS;
241 }
242 res = tb_sw_read(sw, &cap, TB_CFG_SWITCH, sw->cap_plug_events,
243 sizeof(cap) / 4);
244 if (res)
245 return res;
Andreas Noevercd22e732014-06-12 23:11:46 +0200246
Andreas Noeverc90553b2014-06-03 22:04:11 +0200247 if (!cap.eeprom_ctl.present || cap.eeprom_ctl.not_present) {
248 tb_sw_warn(sw, "no NVM\n");
249 return -ENOSYS;
250 }
251
252 if (cap.drom_offset > 0xffff) {
253 tb_sw_warn(sw, "drom offset is larger than 0xffff: %#x\n",
254 cap.drom_offset);
255 return -ENXIO;
256 }
Andreas Noevercd22e732014-06-12 23:11:46 +0200257 *offset = cap.drom_offset;
258 return 0;
259}
Andreas Noeverc90553b2014-06-03 22:04:11 +0200260
Andreas Noevercd22e732014-06-12 23:11:46 +0200261/**
262 * tb_drom_read_uid_only - read uid directly from drom
263 *
264 * Does not use the cached copy in sw->drom. Used during resume to check switch
265 * identity.
266 */
267int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid)
268{
269 u8 data[9];
270 u16 drom_offset;
271 u8 crc;
272 int res = tb_eeprom_get_drom_offset(sw, &drom_offset);
Andreas Noeverc90553b2014-06-03 22:04:11 +0200273 if (res)
274 return res;
Andreas Noevercd22e732014-06-12 23:11:46 +0200275
276 /* read uid */
277 res = tb_eeprom_read_n(sw, drom_offset, data, 9);
278 if (res)
279 return res;
280
281 crc = tb_crc8(data + 1, 8);
282 if (crc != data[0]) {
283 tb_sw_warn(sw, "uid crc8 missmatch (expected: %#x, got: %#x)\n",
284 data[0], crc);
285 return -EIO;
286 }
287
Andreas Noeverc90553b2014-06-03 22:04:11 +0200288 *uid = *(u64 *)(data+1);
289 return 0;
290}
291
Andreas Noevercd22e732014-06-12 23:11:46 +0200292static void tb_drom_parse_port_entry(struct tb_port *port,
293 struct tb_drom_entry_port *entry)
294{
295 port->link_nr = entry->link_nr;
296 if (entry->has_dual_link_port)
297 port->dual_link_port =
298 &port->sw->ports[entry->dual_link_port_nr];
299}
Andreas Noeverc90553b2014-06-03 22:04:11 +0200300
Andreas Noevercd22e732014-06-12 23:11:46 +0200301static int tb_drom_parse_entry(struct tb_switch *sw,
302 struct tb_drom_entry_header *header)
303{
304 struct tb_port *port;
305 int res;
306 enum tb_port_type type;
Andreas Noeverc90553b2014-06-03 22:04:11 +0200307
Andreas Noevercd22e732014-06-12 23:11:46 +0200308 if (header->type != TB_DROM_ENTRY_PORT)
309 return 0;
310
311 port = &sw->ports[header->index];
312 port->disabled = header->port_disabled;
313 if (port->disabled)
314 return 0;
315
316 res = tb_port_read(port, &type, TB_CFG_PORT, 2, 1);
317 if (res)
318 return res;
319 type &= 0xffffff;
320
321 if (type == TB_TYPE_PORT) {
322 struct tb_drom_entry_port *entry = (void *) header;
323 if (header->len != sizeof(*entry)) {
324 tb_sw_warn(sw,
325 "port entry has size %#x (expected %#lx)\n",
326 header->len, sizeof(struct tb_drom_entry_port));
327 return -EIO;
328 }
329 tb_drom_parse_port_entry(port, entry);
330 }
331 return 0;
332}
333
334/**
335 * tb_drom_parse_entries - parse the linked list of drom entries
336 *
337 * Drom must have been copied to sw->drom.
338 */
339static int tb_drom_parse_entries(struct tb_switch *sw)
340{
341 struct tb_drom_header *header = (void *) sw->drom;
342 u16 pos = sizeof(*header);
343 u16 drom_size = header->data_len + TB_DROM_DATA_START;
344
345 while (pos < drom_size) {
346 struct tb_drom_entry_header *entry = (void *) (sw->drom + pos);
347 if (pos + 1 == drom_size || pos + entry->len > drom_size
348 || !entry->len) {
349 tb_sw_warn(sw, "drom buffer overrun, aborting\n");
350 return -EIO;
351 }
352
353 tb_drom_parse_entry(sw, entry);
354
355 pos += entry->len;
356 }
357 return 0;
358}
359
360/**
361 * tb_drom_read - copy drom to sw->drom and parse it
362 */
363int tb_drom_read(struct tb_switch *sw)
364{
365 u16 drom_offset;
366 u16 size;
367 u32 crc;
368 struct tb_drom_header *header;
369 int res;
370 if (sw->drom)
371 return 0;
372
373 if (tb_route(sw) == 0) {
374 /*
375 * The root switch contains only a dummy drom (header only,
376 * no entries). Hardcode the configuration here.
377 */
378 tb_drom_read_uid_only(sw, &sw->uid);
379
380 sw->ports[1].link_nr = 0;
381 sw->ports[2].link_nr = 1;
382 sw->ports[1].dual_link_port = &sw->ports[2];
383 sw->ports[2].dual_link_port = &sw->ports[1];
384
385 sw->ports[3].link_nr = 0;
386 sw->ports[4].link_nr = 1;
387 sw->ports[3].dual_link_port = &sw->ports[4];
388 sw->ports[4].dual_link_port = &sw->ports[3];
389 return 0;
390 }
391
392 res = tb_eeprom_get_drom_offset(sw, &drom_offset);
393 if (res)
394 return res;
395
396 res = tb_eeprom_read_n(sw, drom_offset + 14, (u8 *) &size, 2);
397 if (res)
398 return res;
399 size &= 0x3ff;
400 size += TB_DROM_DATA_START;
401 tb_sw_info(sw, "reading drom (length: %#x)\n", size);
402 if (size < sizeof(*header)) {
403 tb_sw_warn(sw, "drom too small, aborting\n");
404 return -EIO;
405 }
406
407 sw->drom = kzalloc(size, GFP_KERNEL);
408 if (!sw->drom)
409 return -ENOMEM;
410 res = tb_eeprom_read_n(sw, drom_offset, sw->drom, size);
411 if (res)
412 goto err;
413
414 header = (void *) sw->drom;
415
416 if (header->data_len + TB_DROM_DATA_START != size) {
417 tb_sw_warn(sw, "drom size mismatch, aborting\n");
418 goto err;
419 }
420
421 crc = tb_crc8((u8 *) &header->uid, 8);
422 if (crc != header->uid_crc8) {
423 tb_sw_warn(sw,
424 "drom uid crc8 mismatch (expected: %#x, got: %#x), aborting\n",
425 header->uid_crc8, crc);
426 goto err;
427 }
428 sw->uid = header->uid;
429
430 crc = tb_crc32(sw->drom + TB_DROM_DATA_START, header->data_len);
431 if (crc != header->data_crc32) {
432 tb_sw_warn(sw,
433 "drom data crc32 mismatch (expected: %#x, got: %#x), aborting\n",
434 header->data_crc32, crc);
435 goto err;
436 }
437
438 if (header->device_rom_revision > 1)
439 tb_sw_warn(sw, "drom device_rom_revision %#x unknown\n",
440 header->device_rom_revision);
441
442 return tb_drom_parse_entries(sw);
443err:
444 kfree(sw->drom);
445 return -EIO;
446
447}