Lines 1063-1068
struct vpd_readstate {
Link Here
|
1063 |
uint8_t cksum; |
1063 |
uint8_t cksum; |
1064 |
}; |
1064 |
}; |
1065 |
|
1065 |
|
|
|
1066 |
/* return 0 and one byte in *data if no read error, -1 else */ |
1066 |
static int |
1067 |
static int |
1067 |
vpd_nextbyte(struct vpd_readstate *vrs, uint8_t *data) |
1068 |
vpd_nextbyte(struct vpd_readstate *vrs, uint8_t *data) |
1068 |
{ |
1069 |
{ |
Lines 1071-1077
vpd_nextbyte(struct vpd_readstate *vrs, uint8_t *data)
Link Here
|
1071 |
|
1072 |
|
1072 |
if (vrs->bytesinval == 0) { |
1073 |
if (vrs->bytesinval == 0) { |
1073 |
if (pci_read_vpd_reg(vrs->pcib, vrs->cfg, vrs->off, ®)) |
1074 |
if (pci_read_vpd_reg(vrs->pcib, vrs->cfg, vrs->off, ®)) |
1074 |
return (ENXIO); |
1075 |
return (-1); |
1075 |
vrs->val = le32toh(reg); |
1076 |
vrs->val = le32toh(reg); |
1076 |
vrs->off += 4; |
1077 |
vrs->off += 4; |
1077 |
byte = vrs->val & 0xff; |
1078 |
byte = vrs->val & 0xff; |
Lines 1087-1389
vpd_nextbyte(struct vpd_readstate *vrs, uint8_t *data)
Link Here
|
1087 |
return (0); |
1088 |
return (0); |
1088 |
} |
1089 |
} |
1089 |
|
1090 |
|
|
|
1091 |
/* return 0 on match, -1 and "unget" byte on no match */ |
1092 |
static int |
1093 |
vpd_expectbyte(struct vpd_readstate *vrs, uint8_t expected) |
1094 |
{ |
1095 |
uint8_t data; |
1096 |
|
1097 |
if (vpd_nextbyte(vrs, &data) != 0) |
1098 |
return (-1); |
1099 |
|
1100 |
if (data == expected) |
1101 |
return (0); |
1102 |
|
1103 |
vrs->cksum -= data; |
1104 |
vrs->val = (vrs->val << 8) + data; |
1105 |
vrs->bytesinval++; |
1106 |
return (-1); |
1107 |
} |
1108 |
|
1109 |
/* return size if tag matches, -1 on no match, -2 on read error */ |
1110 |
static int |
1111 |
vpd_read_tag_size(struct vpd_readstate *vrs, uint8_t vpd_tag) |
1112 |
{ |
1113 |
uint8_t byte1, byte2; |
1114 |
|
1115 |
if (vpd_expectbyte(vrs, vpd_tag) != 0) |
1116 |
return (-1); |
1117 |
|
1118 |
if ((vpd_tag & 0x80) == 0) |
1119 |
return (vpd_tag & 0x07); |
1120 |
|
1121 |
if (vpd_nextbyte(vrs, &byte1) != 0) |
1122 |
return (-2); |
1123 |
if (vpd_nextbyte(vrs, &byte2) != 0) |
1124 |
return (-2); |
1125 |
|
1126 |
return ((byte2 << 8) + byte1); |
1127 |
} |
1128 |
|
1129 |
/* (re)allocate buffer in multiples of 8 elements */ |
1130 |
static void* |
1131 |
alloc_buffer(void* buffer, size_t element_size, int needed) |
1132 |
{ |
1133 |
int alloc, new_alloc; |
1134 |
|
1135 |
alloc = roundup2(needed, 8); |
1136 |
new_alloc = roundup2(needed + 1, 8); |
1137 |
if (alloc != new_alloc) { |
1138 |
buffer = reallocf(buffer, |
1139 |
new_alloc * element_size, M_DEVBUF, M_WAITOK | M_ZERO); |
1140 |
} |
1141 |
|
1142 |
return (buffer); |
1143 |
} |
1144 |
|
1145 |
/* read VPD keyword and return element size, return -1 on read error */ |
1146 |
static int |
1147 |
vpd_read_elem_head(struct vpd_readstate *vrs, char keyword[2]) |
1148 |
{ |
1149 |
uint8_t data; |
1150 |
|
1151 |
if (vpd_nextbyte(vrs, &keyword[0]) != 0) |
1152 |
return (-1); |
1153 |
if (vpd_nextbyte(vrs, &keyword[1]) != 0) |
1154 |
return (-1); |
1155 |
if (vpd_nextbyte(vrs, &data) != 0) |
1156 |
return (-1); |
1157 |
|
1158 |
return (data); |
1159 |
} |
1160 |
|
1161 |
/* read VPD data element of given size into allocated buffer */ |
1162 |
static char* |
1163 |
vpd_read_value(struct vpd_readstate *vrs, int size) |
1164 |
{ |
1165 |
int i; |
1166 |
char char1; |
1167 |
char *value; |
1168 |
|
1169 |
value = malloc(size + 1, M_DEVBUF, M_WAITOK); |
1170 |
for (i = 0; i < size; i++) { |
1171 |
if (vpd_nextbyte(vrs, &char1) != 0) { |
1172 |
free(value, M_DEVBUF); |
1173 |
return (NULL); |
1174 |
} |
1175 |
value[i] = char1; |
1176 |
} |
1177 |
value[size] = '\0'; |
1178 |
|
1179 |
return (value); |
1180 |
} |
1181 |
|
1182 |
/* read VPD into *keyword and *value, return length of data element */ |
1183 |
static int |
1184 |
vpd_read_elem_data(struct vpd_readstate *vrs, char keyword[2], char **value, int maxlen) |
1185 |
{ |
1186 |
int len; |
1187 |
|
1188 |
len = vpd_read_elem_head(vrs, keyword); |
1189 |
if (len > maxlen) |
1190 |
return (-1); |
1191 |
*value = vpd_read_value(vrs, len); |
1192 |
|
1193 |
return (len); |
1194 |
} |
1195 |
|
1196 |
/* subtract all data following first byte from checksum of RV element */ |
1090 |
static void |
1197 |
static void |
1091 |
pci_read_vpd(device_t pcib, pcicfgregs *cfg) |
1198 |
vpd_fixup_cksum(struct vpd_readstate *vrs, char *rvstring, int len) |
1092 |
{ |
1199 |
{ |
1093 |
struct vpd_readstate vrs; |
|
|
1094 |
int state; |
1095 |
int name; |
1096 |
int remain; |
1097 |
int i; |
1200 |
int i; |
1098 |
int alloc, off; /* alloc/off for RO/W arrays */ |
1201 |
uint8_t fixup; |
1099 |
int cksumvalid; |
|
|
1100 |
int dflen; |
1101 |
int firstrecord; |
1102 |
uint8_t byte; |
1103 |
uint8_t byte2; |
1104 |
|
1202 |
|
1105 |
/* init vpd reader */ |
1203 |
fixup = 0; |
1106 |
vrs.bytesinval = 0; |
1204 |
for (i = 1; i < len; i++) |
1107 |
vrs.off = 0; |
1205 |
fixup += rvstring[i]; |
1108 |
vrs.pcib = pcib; |
1206 |
vrs->cksum -= fixup; |
1109 |
vrs.cfg = cfg; |
1207 |
} |
1110 |
vrs.cksum = 0; |
|
|
1111 |
|
1208 |
|
1112 |
state = 0; |
1209 |
/* fetch one read-only element and return size of heading + data */ |
1113 |
name = remain = i = 0; /* shut up stupid gcc */ |
1210 |
static size_t |
1114 |
alloc = off = 0; /* shut up stupid gcc */ |
1211 |
next_vpd_ro_elem(struct vpd_readstate *vrs, int maxsize) |
1115 |
dflen = 0; /* shut up stupid gcc */ |
1212 |
{ |
1116 |
cksumvalid = -1; |
1213 |
struct pcicfg_vpd *vpd; |
1117 |
firstrecord = 1; |
1214 |
pcicfgregs *cfg; |
1118 |
while (state >= 0) { |
1215 |
struct vpd_readonly *vpd_ros; |
1119 |
if (vpd_nextbyte(&vrs, &byte)) { |
1216 |
int len; |
1120 |
pci_printf(cfg, "VPD read timed out\n"); |
1217 |
|
1121 |
state = -2; |
1218 |
cfg = vrs->cfg; |
1122 |
break; |
1219 |
vpd = &cfg->vpd; |
|
|
1220 |
|
1221 |
if (maxsize < 3) |
1222 |
return (-1); |
1223 |
vpd->vpd_ros = alloc_buffer(vpd->vpd_ros, sizeof(*vpd->vpd_ros), vpd->vpd_rocnt); |
1224 |
vpd_ros = &vpd->vpd_ros[vpd->vpd_rocnt]; |
1225 |
maxsize -= 3; |
1226 |
len = vpd_read_elem_data(vrs, vpd_ros->keyword, &vpd_ros->value, maxsize); |
1227 |
if (vpd_ros->value == NULL) |
1228 |
return (-1); |
1229 |
vpd_ros->len = len; |
1230 |
if (vpd_ros->keyword[0] == 'R' && vpd_ros->keyword[1] == 'V') { |
1231 |
vpd_fixup_cksum(vrs, vpd_ros->value, len); |
1232 |
if (vrs->cksum != 0) { |
1233 |
pci_printf(cfg, |
1234 |
"invalid VPD checksum %#hhx\n", vrs->cksum); |
1235 |
return (-1); |
1123 |
} |
1236 |
} |
1124 |
#if 0 |
1237 |
} |
1125 |
pci_printf(cfg, "vpd: val: %#x, off: %d, bytesinval: %d, byte: " |
1238 |
vpd->vpd_rocnt++; |
1126 |
"%#hhx, state: %d, remain: %d, name: %#x, i: %d\n", vrs.val, |
|
|
1127 |
vrs.off, vrs.bytesinval, byte, state, remain, name, i); |
1128 |
#endif |
1129 |
switch (state) { |
1130 |
case 0: /* item name */ |
1131 |
if (byte & 0x80) { |
1132 |
if (vpd_nextbyte(&vrs, &byte2)) { |
1133 |
state = -2; |
1134 |
break; |
1135 |
} |
1136 |
remain = byte2; |
1137 |
if (vpd_nextbyte(&vrs, &byte2)) { |
1138 |
state = -2; |
1139 |
break; |
1140 |
} |
1141 |
remain |= byte2 << 8; |
1142 |
name = byte & 0x7f; |
1143 |
} else { |
1144 |
remain = byte & 0x7; |
1145 |
name = (byte >> 3) & 0xf; |
1146 |
} |
1147 |
if (firstrecord) { |
1148 |
if (name != 0x2) { |
1149 |
pci_printf(cfg, "VPD data does not " \ |
1150 |
"start with ident (%#x)\n", name); |
1151 |
state = -2; |
1152 |
break; |
1153 |
} |
1154 |
firstrecord = 0; |
1155 |
} |
1156 |
if (vrs.off + remain - vrs.bytesinval > 0x8000) { |
1157 |
pci_printf(cfg, |
1158 |
"VPD data overflow, remain %#x\n", remain); |
1159 |
state = -1; |
1160 |
break; |
1161 |
} |
1162 |
switch (name) { |
1163 |
case 0x2: /* String */ |
1164 |
if (cfg->vpd.vpd_ident != NULL) { |
1165 |
pci_printf(cfg, |
1166 |
"duplicate VPD ident record\n"); |
1167 |
state = -2; |
1168 |
break; |
1169 |
} |
1170 |
if (remain > 255) { |
1171 |
pci_printf(cfg, |
1172 |
"VPD ident length %d exceeds 255\n", |
1173 |
remain); |
1174 |
state = -2; |
1175 |
break; |
1176 |
} |
1177 |
cfg->vpd.vpd_ident = malloc(remain + 1, |
1178 |
M_DEVBUF, M_WAITOK); |
1179 |
i = 0; |
1180 |
state = 1; |
1181 |
break; |
1182 |
case 0xf: /* End */ |
1183 |
state = -1; |
1184 |
break; |
1185 |
case 0x10: /* VPD-R */ |
1186 |
alloc = 8; |
1187 |
off = 0; |
1188 |
cfg->vpd.vpd_ros = malloc(alloc * |
1189 |
sizeof(*cfg->vpd.vpd_ros), M_DEVBUF, |
1190 |
M_WAITOK | M_ZERO); |
1191 |
state = 2; |
1192 |
break; |
1193 |
case 0x11: /* VPD-W */ |
1194 |
alloc = 8; |
1195 |
off = 0; |
1196 |
cfg->vpd.vpd_w = malloc(alloc * |
1197 |
sizeof(*cfg->vpd.vpd_w), M_DEVBUF, |
1198 |
M_WAITOK | M_ZERO); |
1199 |
state = 5; |
1200 |
break; |
1201 |
default: /* Invalid data, abort */ |
1202 |
pci_printf(cfg, "invalid VPD name: %#x\n", name); |
1203 |
state = -2; |
1204 |
break; |
1205 |
} |
1206 |
break; |
1207 |
|
1239 |
|
1208 |
case 1: /* Identifier String */ |
1240 |
return (len + 3); |
1209 |
cfg->vpd.vpd_ident[i++] = byte; |
1241 |
} |
1210 |
remain--; |
|
|
1211 |
if (remain == 0) { |
1212 |
cfg->vpd.vpd_ident[i] = '\0'; |
1213 |
state = 0; |
1214 |
} |
1215 |
break; |
1216 |
|
1242 |
|
1217 |
case 2: /* VPD-R Keyword Header */ |
1243 |
/* fetch one writable element and return size of heading + data */ |
1218 |
if (off == alloc) { |
1244 |
static size_t |
1219 |
cfg->vpd.vpd_ros = reallocf(cfg->vpd.vpd_ros, |
1245 |
next_vpd_rw_elem(struct vpd_readstate *vrs, int maxsize) |
1220 |
(alloc *= 2) * sizeof(*cfg->vpd.vpd_ros), |
1246 |
{ |
1221 |
M_DEVBUF, M_WAITOK | M_ZERO); |
1247 |
struct pcicfg_vpd *vpd; |
1222 |
} |
1248 |
pcicfgregs *cfg; |
1223 |
cfg->vpd.vpd_ros[off].keyword[0] = byte; |
1249 |
struct vpd_write *vpd_w; |
1224 |
if (vpd_nextbyte(&vrs, &byte2)) { |
1250 |
int len; |
1225 |
state = -2; |
|
|
1226 |
break; |
1227 |
} |
1228 |
cfg->vpd.vpd_ros[off].keyword[1] = byte2; |
1229 |
if (vpd_nextbyte(&vrs, &byte2)) { |
1230 |
state = -2; |
1231 |
break; |
1232 |
} |
1233 |
cfg->vpd.vpd_ros[off].len = dflen = byte2; |
1234 |
if (dflen == 0 && |
1235 |
strncmp(cfg->vpd.vpd_ros[off].keyword, "RV", |
1236 |
2) == 0) { |
1237 |
/* |
1238 |
* if this happens, we can't trust the rest |
1239 |
* of the VPD. |
1240 |
*/ |
1241 |
pci_printf(cfg, "invalid VPD RV record"); |
1242 |
cksumvalid = 0; |
1243 |
state = -1; |
1244 |
break; |
1245 |
} else if (dflen == 0) { |
1246 |
cfg->vpd.vpd_ros[off].value = malloc(1 * |
1247 |
sizeof(*cfg->vpd.vpd_ros[off].value), |
1248 |
M_DEVBUF, M_WAITOK); |
1249 |
cfg->vpd.vpd_ros[off].value[0] = '\x00'; |
1250 |
} else |
1251 |
cfg->vpd.vpd_ros[off].value = malloc( |
1252 |
(dflen + 1) * |
1253 |
sizeof(*cfg->vpd.vpd_ros[off].value), |
1254 |
M_DEVBUF, M_WAITOK); |
1255 |
remain -= 3; |
1256 |
i = 0; |
1257 |
/* keep in sync w/ state 3's transitions */ |
1258 |
if (dflen == 0 && remain == 0) |
1259 |
state = 0; |
1260 |
else if (dflen == 0) |
1261 |
state = 2; |
1262 |
else |
1263 |
state = 3; |
1264 |
break; |
1265 |
|
1251 |
|
1266 |
case 3: /* VPD-R Keyword Value */ |
1252 |
cfg = vrs->cfg; |
1267 |
cfg->vpd.vpd_ros[off].value[i++] = byte; |
1253 |
vpd = &cfg->vpd; |
1268 |
if (strncmp(cfg->vpd.vpd_ros[off].keyword, |
|
|
1269 |
"RV", 2) == 0 && cksumvalid == -1) { |
1270 |
if (vrs.cksum == 0) |
1271 |
cksumvalid = 1; |
1272 |
else { |
1273 |
if (bootverbose) |
1274 |
pci_printf(cfg, |
1275 |
"bad VPD cksum, remain %hhu\n", |
1276 |
vrs.cksum); |
1277 |
cksumvalid = 0; |
1278 |
state = -1; |
1279 |
break; |
1280 |
} |
1281 |
} |
1282 |
dflen--; |
1283 |
remain--; |
1284 |
/* keep in sync w/ state 2's transitions */ |
1285 |
if (dflen == 0) |
1286 |
cfg->vpd.vpd_ros[off++].value[i++] = '\0'; |
1287 |
if (dflen == 0 && remain == 0) { |
1288 |
cfg->vpd.vpd_rocnt = off; |
1289 |
cfg->vpd.vpd_ros = reallocf(cfg->vpd.vpd_ros, |
1290 |
off * sizeof(*cfg->vpd.vpd_ros), |
1291 |
M_DEVBUF, M_WAITOK | M_ZERO); |
1292 |
state = 0; |
1293 |
} else if (dflen == 0) |
1294 |
state = 2; |
1295 |
break; |
1296 |
|
1254 |
|
1297 |
case 4: |
1255 |
if (maxsize < 3) |
1298 |
remain--; |
1256 |
return (-1); |
1299 |
if (remain == 0) |
1257 |
vpd->vpd_w = alloc_buffer(vpd->vpd_w, sizeof(*vpd->vpd_w), vpd->vpd_wcnt); |
1300 |
state = 0; |
1258 |
if (vpd->vpd_w == NULL) { |
1301 |
break; |
1259 |
pci_printf(cfg, "out of memory"); |
|
|
1260 |
return (-1); |
1261 |
} |
1262 |
vpd_w = &vpd->vpd_w[vpd->vpd_wcnt]; |
1263 |
maxsize -= 3; |
1264 |
vpd_w->start = vrs->off + 3 - vrs->bytesinval; |
1265 |
len = vpd_read_elem_data(vrs, vpd_w->keyword, &vpd_w->value, maxsize); |
1266 |
if (vpd_w->value == NULL) |
1267 |
return (-1); |
1268 |
vpd_w->len = len; |
1269 |
vpd->vpd_wcnt++; |
1302 |
|
1270 |
|
1303 |
case 5: /* VPD-W Keyword Header */ |
1271 |
return (len + 3); |
1304 |
if (off == alloc) { |
1272 |
} |
1305 |
cfg->vpd.vpd_w = reallocf(cfg->vpd.vpd_w, |
|
|
1306 |
(alloc *= 2) * sizeof(*cfg->vpd.vpd_w), |
1307 |
M_DEVBUF, M_WAITOK | M_ZERO); |
1308 |
} |
1309 |
cfg->vpd.vpd_w[off].keyword[0] = byte; |
1310 |
if (vpd_nextbyte(&vrs, &byte2)) { |
1311 |
state = -2; |
1312 |
break; |
1313 |
} |
1314 |
cfg->vpd.vpd_w[off].keyword[1] = byte2; |
1315 |
if (vpd_nextbyte(&vrs, &byte2)) { |
1316 |
state = -2; |
1317 |
break; |
1318 |
} |
1319 |
cfg->vpd.vpd_w[off].len = dflen = byte2; |
1320 |
cfg->vpd.vpd_w[off].start = vrs.off - vrs.bytesinval; |
1321 |
cfg->vpd.vpd_w[off].value = malloc((dflen + 1) * |
1322 |
sizeof(*cfg->vpd.vpd_w[off].value), |
1323 |
M_DEVBUF, M_WAITOK); |
1324 |
remain -= 3; |
1325 |
i = 0; |
1326 |
/* keep in sync w/ state 6's transitions */ |
1327 |
if (dflen == 0 && remain == 0) |
1328 |
state = 0; |
1329 |
else if (dflen == 0) |
1330 |
state = 5; |
1331 |
else |
1332 |
state = 6; |
1333 |
break; |
1334 |
|
1273 |
|
1335 |
case 6: /* VPD-W Keyword Value */ |
1274 |
/* free all memory allocated for VPD data */ |
1336 |
cfg->vpd.vpd_w[off].value[i++] = byte; |
1275 |
static void |
1337 |
dflen--; |
1276 |
vpd_free(struct pcicfg_vpd *vpd) |
1338 |
remain--; |
1277 |
{ |
1339 |
/* keep in sync w/ state 5's transitions */ |
1278 |
int i; |
1340 |
if (dflen == 0) |
|
|
1341 |
cfg->vpd.vpd_w[off++].value[i++] = '\0'; |
1342 |
if (dflen == 0 && remain == 0) { |
1343 |
cfg->vpd.vpd_wcnt = off; |
1344 |
cfg->vpd.vpd_w = reallocf(cfg->vpd.vpd_w, |
1345 |
off * sizeof(*cfg->vpd.vpd_w), |
1346 |
M_DEVBUF, M_WAITOK | M_ZERO); |
1347 |
state = 0; |
1348 |
} else if (dflen == 0) |
1349 |
state = 5; |
1350 |
break; |
1351 |
|
1279 |
|
1352 |
default: |
1280 |
free(vpd->vpd_ident, M_DEVBUF); |
1353 |
pci_printf(cfg, "invalid state: %d\n", state); |
1281 |
for (i = 0; i < vpd->vpd_rocnt; i++) |
1354 |
state = -1; |
1282 |
free(vpd->vpd_ros[i].value, M_DEVBUF); |
1355 |
break; |
1283 |
free(vpd->vpd_ros, M_DEVBUF); |
1356 |
} |
1284 |
vpd->vpd_rocnt = 0; |
|
|
1285 |
for (i = 0; i < vpd->vpd_wcnt; i++) |
1286 |
free(vpd->vpd_w[i].value, M_DEVBUF); |
1287 |
free(vpd->vpd_w, M_DEVBUF); |
1288 |
vpd->vpd_wcnt = 0; |
1289 |
} |
1357 |
|
1290 |
|
1358 |
if (cfg->vpd.vpd_ident == NULL || cfg->vpd.vpd_ident[0] == '\0') { |
1291 |
#define VPD_TAG_END ((0x0f << 3) | 0) /* small tag, len == 0 */ |
1359 |
pci_printf(cfg, "no valid vpd ident found\n"); |
1292 |
#define VPD_TAG_IDENT (0x02 | 0x80) /* large tag */ |
1360 |
state = -2; |
1293 |
#define VPD_TAG_RO (0x10 | 0x80) /* large tag */ |
1361 |
} |
1294 |
#define VPD_TAG_RW (0x11 | 0x80) /* large tag */ |
|
|
1295 |
|
1296 |
static int |
1297 |
pci_parse_vpd(device_t pcib, pcicfgregs *cfg) |
1298 |
{ |
1299 |
struct vpd_readstate vrs; |
1300 |
int cksumvalid; |
1301 |
int size, elem_size; |
1302 |
|
1303 |
/* init vpd reader */ |
1304 |
vrs.bytesinval = 0; |
1305 |
vrs.off = 0; |
1306 |
vrs.pcib = pcib; |
1307 |
vrs.cfg = cfg; |
1308 |
vrs.cksum = 0; |
1309 |
|
1310 |
/* read VPD ident element - mandatory */ |
1311 |
size = vpd_read_tag_size(&vrs, VPD_TAG_IDENT); |
1312 |
if (size <= 0) { |
1313 |
pci_printf(cfg, "no VPD ident found\n"); |
1314 |
return (0); |
1315 |
} |
1316 |
cfg->vpd.vpd_ident = vpd_read_value(&vrs, size); |
1317 |
if (cfg->vpd.vpd_ident == NULL) { |
1318 |
pci_printf(cfg, "error accessing VPD ident data\n"); |
1319 |
return (0); |
1362 |
} |
1320 |
} |
1363 |
|
1321 |
|
1364 |
if (cksumvalid <= 0 || state < -1) { |
1322 |
/* read VPD RO elements - mandatory */ |
1365 |
/* read-only data bad, clean up */ |
1323 |
size = vpd_read_tag_size(&vrs, VPD_TAG_RO); |
1366 |
if (cfg->vpd.vpd_ros != NULL) { |
1324 |
if (size <= 0) { |
1367 |
for (off = 0; cfg->vpd.vpd_ros[off].value; off++) |
1325 |
pci_printf(cfg, "no read-only VPD data found\n"); |
1368 |
free(cfg->vpd.vpd_ros[off].value, M_DEVBUF); |
1326 |
return (0); |
1369 |
free(cfg->vpd.vpd_ros, M_DEVBUF); |
|
|
1370 |
cfg->vpd.vpd_ros = NULL; |
1371 |
} |
1372 |
} |
1327 |
} |
1373 |
if (state < -1) { |
1328 |
while (size > 0) { |
1374 |
/* I/O error, clean up */ |
1329 |
elem_size = next_vpd_ro_elem(&vrs, size); |
1375 |
pci_printf(cfg, "failed to read VPD data.\n"); |
1330 |
if (elem_size < 0) { |
1376 |
if (cfg->vpd.vpd_ident != NULL) { |
1331 |
pci_printf(cfg, "error accessing read-only VPD data\n"); |
1377 |
free(cfg->vpd.vpd_ident, M_DEVBUF); |
1332 |
return (-1); |
1378 |
cfg->vpd.vpd_ident = NULL; |
|
|
1379 |
} |
1333 |
} |
1380 |
if (cfg->vpd.vpd_w != NULL) { |
1334 |
size -= elem_size; |
1381 |
for (off = 0; cfg->vpd.vpd_w[off].value; off++) |
1335 |
} |
1382 |
free(cfg->vpd.vpd_w[off].value, M_DEVBUF); |
1336 |
cksumvalid = (vrs.cksum == 0); |
1383 |
free(cfg->vpd.vpd_w, M_DEVBUF); |
1337 |
if (!cksumvalid) |
1384 |
cfg->vpd.vpd_w = NULL; |
1338 |
return (-1); |
|
|
1339 |
|
1340 |
/* read VPD RW elements - optional */ |
1341 |
size = vpd_read_tag_size(&vrs, VPD_TAG_RW); |
1342 |
if (size == -2) |
1343 |
return (-1); |
1344 |
while (size > 0) { |
1345 |
elem_size = next_vpd_rw_elem(&vrs, size); |
1346 |
if (elem_size < 0) { |
1347 |
pci_printf(cfg, "error accessing writeable VPD data\n"); |
1348 |
return (-1); |
1385 |
} |
1349 |
} |
|
|
1350 |
size -= elem_size; |
1351 |
} |
1352 |
|
1353 |
/* read empty END tag - mandatory */ |
1354 |
size = vpd_read_tag_size(&vrs, VPD_TAG_END); |
1355 |
if (size != 0) { |
1356 |
pci_printf(cfg, "No valid VPD end tag found\n"); |
1386 |
} |
1357 |
} |
|
|
1358 |
return (0); |
1359 |
} |
1360 |
|
1361 |
static void |
1362 |
pci_read_vpd(device_t pcib, pcicfgregs *cfg) |
1363 |
{ |
1364 |
int status; |
1365 |
|
1366 |
status = pci_parse_vpd(pcib, cfg); |
1367 |
if (status < 0) |
1368 |
vpd_free(&cfg->vpd); |
1387 |
cfg->vpd.vpd_cached = 1; |
1369 |
cfg->vpd.vpd_cached = 1; |
1388 |
#undef REG |
1370 |
#undef REG |
1389 |
#undef WREG |
1371 |
#undef WREG |
Lines 2777-2795
pci_freecfg(struct pci_devinfo *dinfo)
Link Here
|
2777 |
{ |
2759 |
{ |
2778 |
struct devlist *devlist_head; |
2760 |
struct devlist *devlist_head; |
2779 |
struct pci_map *pm, *next; |
2761 |
struct pci_map *pm, *next; |
2780 |
int i; |
|
|
2781 |
|
2762 |
|
2782 |
devlist_head = &pci_devq; |
2763 |
devlist_head = &pci_devq; |
2783 |
|
2764 |
|
2784 |
if (dinfo->cfg.vpd.vpd_reg) { |
2765 |
if (dinfo->cfg.vpd.vpd_reg) |
2785 |
free(dinfo->cfg.vpd.vpd_ident, M_DEVBUF); |
2766 |
vpd_free(&dinfo->cfg.vpd); |
2786 |
for (i = 0; i < dinfo->cfg.vpd.vpd_rocnt; i++) |
2767 |
|
2787 |
free(dinfo->cfg.vpd.vpd_ros[i].value, M_DEVBUF); |
|
|
2788 |
free(dinfo->cfg.vpd.vpd_ros, M_DEVBUF); |
2789 |
for (i = 0; i < dinfo->cfg.vpd.vpd_wcnt; i++) |
2790 |
free(dinfo->cfg.vpd.vpd_w[i].value, M_DEVBUF); |
2791 |
free(dinfo->cfg.vpd.vpd_w, M_DEVBUF); |
2792 |
} |
2793 |
STAILQ_FOREACH_SAFE(pm, &dinfo->cfg.maps, pm_link, next) { |
2768 |
STAILQ_FOREACH_SAFE(pm, &dinfo->cfg.maps, pm_link, next) { |
2794 |
free(pm, M_DEVBUF); |
2769 |
free(pm, M_DEVBUF); |
2795 |
} |
2770 |
} |