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