1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <npi_espc.h>
29 #include <nxge_espc.h>
30
31 static int npi_vpd_read_prop(npi_handle_t handle, uint32_t ep,
32 const char *prop, int len, char *val);
33
34 npi_status_t
npi_espc_pio_enable(npi_handle_t handle)35 npi_espc_pio_enable(npi_handle_t handle)
36 {
37 NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_EN_REG), 0x1);
38 return (NPI_SUCCESS);
39 }
40
41 npi_status_t
npi_espc_pio_disable(npi_handle_t handle)42 npi_espc_pio_disable(npi_handle_t handle)
43 {
44 NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_EN_REG), 0);
45 return (NPI_SUCCESS);
46 }
47
48 npi_status_t
npi_espc_eeprom_entry(npi_handle_t handle,io_op_t op,uint32_t addr,uint8_t * data)49 npi_espc_eeprom_entry(npi_handle_t handle, io_op_t op, uint32_t addr,
50 uint8_t *data)
51 {
52 uint64_t val = 0;
53
54 if ((addr & ~EPC_EEPROM_ADDR_BITS) != 0) {
55 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL,
56 " npi_espc_eerprom_entry"
57 " Invalid input addr <0x%x>\n",
58 addr));
59 return (NPI_FAILURE | NPI_ESPC_EEPROM_ADDR_INVALID);
60 }
61
62 switch (op) {
63 case OP_SET:
64 val = EPC_WRITE_INITIATE | (addr << EPC_EEPROM_ADDR_SHIFT) |
65 *data;
66 NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), val);
67 EPC_WAIT_RW_COMP(handle, &val, EPC_WRITE_COMPLETE);
68 if ((val & EPC_WRITE_COMPLETE) == 0) {
69 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL,
70 " npi_espc_eeprom_entry"
71 " HW Error: EEPROM_WR <0x%x>\n",
72 val));
73 return (NPI_FAILURE | NPI_ESPC_EEPROM_WRITE_FAILED);
74 }
75 break;
76 case OP_GET:
77 val = EPC_READ_INITIATE | (addr << EPC_EEPROM_ADDR_SHIFT);
78 NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), val);
79 EPC_WAIT_RW_COMP(handle, &val, EPC_READ_COMPLETE);
80 if ((val & EPC_READ_COMPLETE) == 0) {
81 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL,
82 " npi_espc_eeprom_entry"
83 " HW Error: EEPROM_RD <0x%x>",
84 val));
85 return (NPI_FAILURE | NPI_ESPC_EEPROM_READ_FAILED);
86 }
87 NXGE_REG_RD64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), &val);
88 /*
89 * Workaround for synchronization issues - do a second PIO
90 */
91 val = EPC_READ_INITIATE | (addr << EPC_EEPROM_ADDR_SHIFT);
92 NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), val);
93 EPC_WAIT_RW_COMP(handle, &val, EPC_READ_COMPLETE);
94 if ((val & EPC_READ_COMPLETE) == 0) {
95 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL,
96 " npi_espc_eeprom_entry HW Error: "
97 "EEPROM_RD <0x%x>", val));
98 return (NPI_FAILURE | NPI_ESPC_EEPROM_READ_FAILED);
99 }
100 NXGE_REG_RD64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), &val);
101 *data = val & EPC_EEPROM_DATA_MASK;
102 break;
103 default:
104 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL,
105 " npi_espc_eeprom_entry"
106 " Invalid Input addr <0x%x>\n", addr));
107 return (NPI_FAILURE | NPI_ESPC_OPCODE_INVALID);
108 }
109
110 return (NPI_SUCCESS);
111 }
112
113 npi_status_t
npi_espc_mac_addr_get(npi_handle_t handle,uint8_t * data)114 npi_espc_mac_addr_get(npi_handle_t handle, uint8_t *data)
115 {
116 mac_addr_0_t mac0;
117 mac_addr_1_t mac1;
118
119 NXGE_REG_RD64(handle, ESPC_MAC_ADDR_0, &mac0.value);
120 data[0] = mac0.bits.w0.byte0;
121 data[1] = mac0.bits.w0.byte1;
122 data[2] = mac0.bits.w0.byte2;
123 data[3] = mac0.bits.w0.byte3;
124
125 NXGE_REG_RD64(handle, ESPC_MAC_ADDR_1, &mac1.value);
126 data[4] = mac1.bits.w0.byte4;
127 data[5] = mac1.bits.w0.byte5;
128
129 return (NPI_SUCCESS);
130 }
131
132 npi_status_t
npi_espc_num_ports_get(npi_handle_t handle,uint8_t * data)133 npi_espc_num_ports_get(npi_handle_t handle, uint8_t *data)
134 {
135 uint64_t val = 0;
136
137 NXGE_REG_RD64(handle, ESPC_NUM_PORTS_MACS, &val);
138 val &= NUM_PORTS_MASK;
139 *data = (uint8_t)val;
140
141 return (NPI_SUCCESS);
142 }
143
144 npi_status_t
npi_espc_num_macs_get(npi_handle_t handle,uint8_t * data)145 npi_espc_num_macs_get(npi_handle_t handle, uint8_t *data)
146 {
147 uint64_t val = 0;
148
149 NXGE_REG_RD64(handle, ESPC_NUM_PORTS_MACS, &val);
150 val &= NUM_MAC_ADDRS_MASK;
151 val = (val >> NUM_MAC_ADDRS_SHIFT);
152 *data = (uint8_t)val;
153
154 return (NPI_SUCCESS);
155 }
156
157 npi_status_t
npi_espc_model_str_get(npi_handle_t handle,char * data)158 npi_espc_model_str_get(npi_handle_t handle, char *data)
159 {
160 uint64_t val = 0;
161 uint16_t str_len;
162 int i, j;
163
164 NXGE_REG_RD64(handle, ESPC_MOD_STR_LEN, &val);
165 val &= MOD_STR_LEN_MASK;
166 str_len = (uint8_t)val;
167
168 if (str_len > MAX_MOD_STR_LEN) {
169 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL,
170 " npi_espc_model_str_get"
171 " Model string length %d exceeds max %d\n",
172 str_len, MAX_MOD_STR_LEN));
173 return (NPI_FAILURE | NPI_ESPC_STR_LEN_INVALID);
174 }
175
176 /*
177 * Might have to reverse the order depending on how the string
178 * is written.
179 */
180 for (i = 0, j = 0; i < str_len; j++) {
181 NXGE_REG_RD64(handle, ESPC_MOD_STR(j), &val);
182 data[i++] = ((char *)&val)[3];
183 data[i++] = ((char *)&val)[2];
184 data[i++] = ((char *)&val)[1];
185 data[i++] = ((char *)&val)[0];
186 }
187
188 data[str_len] = '\0';
189
190 return (NPI_SUCCESS);
191 }
192
193 npi_status_t
npi_espc_bd_model_str_get(npi_handle_t handle,char * data)194 npi_espc_bd_model_str_get(npi_handle_t handle, char *data)
195 {
196 uint64_t val = 0;
197 uint16_t str_len;
198 int i, j;
199
200 NXGE_REG_RD64(handle, ESPC_BD_MOD_STR_LEN, &val);
201 val &= BD_MOD_STR_LEN_MASK;
202 str_len = (uint8_t)val;
203
204 if (str_len > MAX_BD_MOD_STR_LEN) {
205 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL,
206 " npi_espc_model_str_get"
207 " Board Model string length %d "
208 "exceeds max %d\n",
209 str_len, MAX_BD_MOD_STR_LEN));
210 return (NPI_FAILURE | NPI_ESPC_STR_LEN_INVALID);
211 }
212
213 /*
214 * Might have to reverse the order depending on how the string
215 * is written.
216 */
217 for (i = 0, j = 0; i < str_len; j++) {
218 NXGE_REG_RD64(handle, ESPC_BD_MOD_STR(j), &val);
219 data[i++] = ((char *)&val)[3];
220 data[i++] = ((char *)&val)[2];
221 data[i++] = ((char *)&val)[1];
222 data[i++] = ((char *)&val)[0];
223 }
224
225 data[str_len] = '\0';
226
227 return (NPI_SUCCESS);
228 }
229
230 npi_status_t
npi_espc_phy_type_get(npi_handle_t handle,uint8_t * data)231 npi_espc_phy_type_get(npi_handle_t handle, uint8_t *data)
232 {
233 phy_type_t phy;
234
235 NXGE_REG_RD64(handle, ESPC_PHY_TYPE, &phy.value);
236 data[0] = phy.bits.w0.pt0_phy_type;
237 data[1] = phy.bits.w0.pt1_phy_type;
238 data[2] = phy.bits.w0.pt2_phy_type;
239 data[3] = phy.bits.w0.pt3_phy_type;
240
241 return (NPI_SUCCESS);
242 }
243
244 npi_status_t
npi_espc_port_phy_type_get(npi_handle_t handle,uint8_t * data,uint8_t portn)245 npi_espc_port_phy_type_get(npi_handle_t handle, uint8_t *data, uint8_t portn)
246 {
247 phy_type_t phy;
248
249 ASSERT(IS_PORT_NUM_VALID(portn));
250
251 NXGE_REG_RD64(handle, ESPC_PHY_TYPE, &phy.value);
252 switch (portn) {
253 case 0:
254 *data = phy.bits.w0.pt0_phy_type;
255 break;
256 case 1:
257 *data = phy.bits.w0.pt1_phy_type;
258 break;
259 case 2:
260 *data = phy.bits.w0.pt2_phy_type;
261 break;
262 case 3:
263 *data = phy.bits.w0.pt3_phy_type;
264 break;
265 default:
266 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL,
267 " npi_espc_port_phy_type_get"
268 " Invalid Input: portn <%d>",
269 portn));
270 return (NPI_FAILURE | NPI_ESPC_PORT_INVALID);
271 }
272
273 return (NPI_SUCCESS);
274 }
275
276 npi_status_t
npi_espc_max_frame_get(npi_handle_t handle,uint16_t * data)277 npi_espc_max_frame_get(npi_handle_t handle, uint16_t *data)
278 {
279 uint64_t val = 0;
280
281 NXGE_REG_RD64(handle, ESPC_MAX_FM_SZ, &val);
282 val &= MAX_FM_SZ_MASK;
283 *data = (uint8_t)val;
284
285 return (NPI_SUCCESS);
286 }
287
288 npi_status_t
npi_espc_version_get(npi_handle_t handle,uint16_t * data)289 npi_espc_version_get(npi_handle_t handle, uint16_t *data)
290 {
291 uint64_t val = 0;
292
293 NXGE_REG_RD64(handle, ESPC_VER_IMGSZ, &val);
294 val &= VER_NUM_MASK;
295 *data = (uint8_t)val;
296
297 return (NPI_SUCCESS);
298 }
299
300 npi_status_t
npi_espc_img_sz_get(npi_handle_t handle,uint16_t * data)301 npi_espc_img_sz_get(npi_handle_t handle, uint16_t *data)
302 {
303 uint64_t val = 0;
304
305 NXGE_REG_RD64(handle, ESPC_VER_IMGSZ, &val);
306 val &= IMG_SZ_MASK;
307 val = val >> IMG_SZ_SHIFT;
308 *data = (uint8_t)val;
309
310 return (NPI_SUCCESS);
311 }
312
313 npi_status_t
npi_espc_chksum_get(npi_handle_t handle,uint8_t * data)314 npi_espc_chksum_get(npi_handle_t handle, uint8_t *data)
315 {
316 uint64_t val = 0;
317
318 NXGE_REG_RD64(handle, ESPC_CHKSUM, &val);
319 val &= CHKSUM_MASK;
320 *data = (uint8_t)val;
321
322 return (NPI_SUCCESS);
323 }
324
325 npi_status_t
npi_espc_intr_num_get(npi_handle_t handle,uint8_t * data)326 npi_espc_intr_num_get(npi_handle_t handle, uint8_t *data)
327 {
328 intr_num_t intr;
329
330 NXGE_REG_RD64(handle, ESPC_INTR_NUM, &intr.value);
331 data[0] = intr.bits.w0.pt0_intr_num;
332 data[1] = intr.bits.w0.pt1_intr_num;
333 data[2] = intr.bits.w0.pt2_intr_num;
334 data[3] = intr.bits.w0.pt3_intr_num;
335
336 return (NPI_SUCCESS);
337 }
338
339 void
npi_espc_dump(npi_handle_t handle)340 npi_espc_dump(npi_handle_t handle)
341 {
342 int i;
343 uint64_t val = 0;
344
345 NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL,
346 "Dumping SEEPROM registers directly:\n\n"));
347
348 for (i = 0; i < 23; i++) {
349 NXGE_REG_RD64(handle, ESPC_NCR_REGN(i), &val);
350 NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL,
351 "reg[%d] 0x%llx\n",
352 i, val & 0xffffffff));
353 }
354
355 NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, "\n\n"));
356 }
357
358 uint32_t
npi_espc_reg_get(npi_handle_t handle,int reg_idx)359 npi_espc_reg_get(npi_handle_t handle, int reg_idx)
360 {
361 uint64_t val = 0;
362 uint32_t reg_val = 0;
363
364 NXGE_REG_RD64(handle, ESPC_NCR_REGN(reg_idx), &val);
365 reg_val = val & 0xffffffff;
366
367 return (reg_val);
368 }
369
vpd_rd(npi_handle_t handle,uint32_t addr)370 static inline uint8_t vpd_rd(npi_handle_t handle, uint32_t addr)
371 {
372 uint8_t data = 0;
373
374 if (npi_espc_eeprom_entry(handle, OP_GET, addr, &data) != NPI_SUCCESS)
375 data = 0;
376 return (data);
377 }
378
379 npi_status_t
npi_espc_vpd_info_get(npi_handle_t handle,p_npi_vpd_info_t vpdp,uint32_t rom_len)380 npi_espc_vpd_info_get(npi_handle_t handle, p_npi_vpd_info_t vpdp,
381 uint32_t rom_len)
382 {
383 int i, len;
384 uint32_t base = 0, kstart = 0, ep, end;
385 uint8_t fd_flags = 0;
386
387 /* Fill the vpd_info struct with invalid vals */
388 (void) strcpy(vpdp->model, "\0");
389 (void) strcpy(vpdp->bd_model, "\0");
390 (void) strcpy(vpdp->phy_type, "\0");
391 (void) strcpy(vpdp->ver, "\0");
392 vpdp->num_macs = 0;
393 for (i = 0; i < ETHERADDRL; i++) {
394 vpdp->mac_addr[i] = 0;
395 }
396
397 ep = 0;
398 end = ep + rom_len;
399
400 /* go through the images till OBP image type is found */
401 while (ep < end) {
402 base = ep;
403 /* check for expansion rom header signature */
404 if (vpd_rd(handle, ep) != 0x55 ||
405 vpd_rd(handle, ep + 1) != 0xaa) {
406 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL,
407 "npi_espc_vpd_info_get: expansion rom image "
408 "not found, 0x%x [0x%x 0x%x]", ep,
409 vpd_rd(handle, ep), vpd_rd(handle, ep + 1)));
410 goto vpd_info_err;
411 }
412 /* go to the beginning of the PCI data struct of this image */
413 ep = ep + 23;
414 ep = base + ((vpd_rd(handle, ep) << 8) |
415 (vpd_rd(handle, ep + 1)));
416 /* check for PCI data struct signature "PCIR" */
417 if ((vpd_rd(handle, ep) != 0x50) ||
418 (vpd_rd(handle, ep + 1) != 0x43) ||
419 (vpd_rd(handle, ep + 2) != 0x49) ||
420 (vpd_rd(handle, ep + 3) != 0x52)) {
421 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL,
422 "npi_espc_vpd_info_get: PCIR sig not found"));
423 goto vpd_info_err;
424 }
425 /* check for image type OBP */
426 if (vpd_rd(handle, ep + 20) != 0x01) {
427 /* go to the next image */
428 ep = base + ((vpd_rd(handle, base + 2)) * 512);
429 continue;
430 }
431 /* find the beginning of the VPD data */
432 base = base + (vpd_rd(handle, ep + 8) |
433 (vpd_rd(handle, ep + 9) << 8));
434 break;
435 }
436
437 /* check first byte of identifier string tag */
438 if (!base || (vpd_rd(handle, base + 0) != 0x82)) {
439 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL,
440 "npi_espc_vpd_info_get: Could not find VPD!!"));
441 goto vpd_info_err;
442 }
443
444 /*
445 * skip over the ID string descriptor to go to the read-only VPD
446 * keywords list.
447 */
448 i = (vpd_rd(handle, base + 1) |
449 (vpd_rd(handle, base + 2) << 8)) + 3;
450
451 while (i < EXPANSION_ROM_SIZE) {
452 if (vpd_rd(handle, base + i) != 0x90) { /* no vpd found */
453 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL,
454 "nxge_get_vpd_info: Could not find "
455 "VPD ReadOnly list!! [0x%x] %d",
456 vpd_rd(handle, base + i), i));
457 goto vpd_info_err;
458 }
459
460 /* found a vpd read-only list, get its length */
461 len = vpd_rd(handle, base + i + 1) |
462 (vpd_rd(handle, base + i + 2) << 8);
463
464 /* extract keywords */
465 kstart = base + i + 3;
466 ep = kstart;
467 /*
468 * Each keyword field is as follows:
469 * 2 bytes keyword in the form of "Zx" where x = 0,1,2....
470 * 1 byte keyword data field length - klen
471 * Now the actual keyword data field:
472 * 1 byte VPD property instance, 'M' / 'I'
473 * 2 bytes
474 * 1 byte VPD property data type, 'B' / 'S'
475 * 1 byte VPD property value length - n
476 * Actual property string, length (klen - n - 5) bytes
477 * Actual property value, length n bytes
478 */
479 while ((ep - kstart) < len) {
480 int klen = vpd_rd(handle, ep + 2);
481 int dlen;
482 char type;
483
484 ep += 3;
485
486 /*
487 * Look for the following properties:
488 *
489 * local-mac-address:
490 * -- VPD Instance 'I'
491 * -- VPD Type String 'B'
492 * -- property string == local-mac-address
493 *
494 * model:
495 * -- VPD Instance 'M'
496 * -- VPD Type String 'S'
497 * -- property string == model
498 *
499 * board-model:
500 * -- VPD Instance 'M'
501 * -- VPD Type String 'S'
502 * -- property string == board-model
503 *
504 * num-mac-addresses:
505 * -- VPD Instance 'I'
506 * -- VPD Type String 'B'
507 * -- property string == num-mac-addresses
508 *
509 * phy-type:
510 * -- VPD Instance 'I'
511 * -- VPD Type String 'S'
512 * -- property string == phy-type
513 *
514 * version:
515 * -- VPD Instance 'M'
516 * -- VPD Type String 'S'
517 * -- property string == version
518 */
519 if (vpd_rd(handle, ep) == 'M') {
520 type = vpd_rd(handle, ep + 3);
521 if (type == 'S') {
522 dlen = vpd_rd(handle, ep + 4);
523 if (npi_vpd_read_prop(handle, ep + 5,
524 "model", dlen, vpdp->model)) {
525 fd_flags |= FD_MODEL;
526 goto next;
527 }
528 if (npi_vpd_read_prop(handle, ep + 5,
529 "board-model", dlen,
530 vpdp->bd_model)) {
531 fd_flags |= FD_BD_MODEL;
532 goto next;
533 }
534 if (npi_vpd_read_prop(handle, ep + 5,
535 "version", dlen, vpdp->ver)) {
536 fd_flags |= FD_FW_VERSION;
537 goto next;
538 }
539 }
540 goto next;
541 } else if (vpd_rd(handle, ep) == 'I') {
542 type = vpd_rd(handle, ep + 3);
543 if (type == 'B') {
544 dlen = vpd_rd(handle, ep + 4);
545 if (npi_vpd_read_prop(handle, ep + 5,
546 "local-mac-address", dlen,
547 (char *)(vpdp->mac_addr))) {
548 fd_flags |= FD_MAC_ADDR;
549 goto next;
550 }
551 if (npi_vpd_read_prop(handle, ep + 5,
552 "num-mac-addresses", dlen,
553 (char *)&(vpdp->num_macs))) {
554 fd_flags |= FD_NUM_MACS;
555 }
556 } else if (type == 'S') {
557 dlen = vpd_rd(handle, ep + 4);
558 if (npi_vpd_read_prop(handle, ep + 5,
559 "phy-type", dlen,
560 vpdp->phy_type)) {
561 fd_flags |= FD_PHY_TYPE;
562 }
563 }
564 goto next;
565 } else {
566 goto vpd_info_err;
567 }
568
569 next:
570 if ((fd_flags & FD_ALL) == FD_ALL)
571 goto vpd_success;
572 ep += klen;
573 }
574 i += len + 3;
575 }
576
577 vpd_success:
578 return (NPI_SUCCESS);
579
580 vpd_info_err:
581 return (NPI_FAILURE);
582 }
583
584 static int
npi_vpd_read_prop(npi_handle_t handle,uint32_t ep,const char * prop,int len,char * val)585 npi_vpd_read_prop(npi_handle_t handle, uint32_t ep, const char *prop, int len,
586 char *val)
587 {
588 int prop_len = strlen(prop) + 1;
589 int i;
590
591 for (i = 0; i < prop_len; i++) {
592 if (vpd_rd(handle, ep + i) != prop[i])
593 return (0);
594 }
595
596 ep += prop_len;
597
598 for (i = 0; i < len; i++)
599 val[i] = vpd_rd(handle, ep + i);
600 return (1);
601 }
602