1 /* $NetBSD: pci_fixup.c,v 1.5 2021/11/01 21:28:02 andvar Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Julian Coleman. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/device.h> 34 35 #include <net/if.h> 36 #include <net/if_ether.h> 37 38 #define _SPARC_BUS_DMA_PRIVATE 39 #include <sys/bus.h> 40 #include <machine/autoconf.h> 41 #include <machine/promlib.h> 42 43 #include <dev/pci/pcireg.h> 44 #include <dev/pci/pcivar.h> 45 #include <dev/pci/pcidevs.h> 46 47 #include <dev/ofw/ofw_pci.h> 48 49 #include <sparc/sparc/msiiepreg.h> 50 #include <sparc/sparc/msiiepvar.h> 51 #include <sparc/sparc/pci_fixup.h> 52 53 static void mspcic_pci_fixup(int, pcitag_t, int *, uint32_t *, uint32_t *, 54 uint32_t, uint32_t memtop); 55 56 57 /* ====================================================================== 58 * 59 * General PCI bus fixup 60 */ 61 62 #define MAX_DEVFUN 256 /* 32 device * 8 function */ 63 #define DF_NEXTDEV(i) (i + 7 - (i % 8)) 64 #define MAP_TOP(map) (map.pcibase + map.size) 65 #define RND_IO_START(t, m) (((t & m) == t) ? t : \ 66 ((t + PCI_MAPREG_IO_SIZE(m)) & m)) 67 #define RND_MEM_START(t, m) (((t & m) == t) ? t : \ 68 ((t + PCI_MAPREG_MEM_SIZE(m)) & m)) 69 70 void 71 mspcic_pci_scan(int root) 72 { 73 int i, j, node, bus, dev, fun, maxbus, len, class; 74 struct ofw_pci_register reg; 75 pcitag_t tag; 76 pcireg_t val, saved; 77 uint32_t io[IOMAP_SIZE], mem[MEMMAP_SIZE]; 78 #ifdef SPARC_PCI_FIXUP_DEBUG 79 char name[80]; 80 81 memset(name, 0, sizeof(name)); 82 #endif 83 maxbus = 1; 84 for (i = 0; i < IOMAP_SIZE; i++) 85 io[i] = mspcic_pci_iomap[i].pcibase; 86 for (i = 0; i < MEMMAP_SIZE; i++) 87 mem[i] = mspcic_pci_memmap[i].pcibase; 88 node = OF_child(root); 89 90 #ifdef SPARC_PCI_FIXUP_DEBUG 91 printf("mspcic_pci_scan start:\n"); 92 printf(" max bus %d\n", maxbus); 93 for (i = 0; i < IOMAP_SIZE; i++) 94 printf(" PCI I/O %d %08x to %08x\n", 95 i, io[i], MAP_TOP(mspcic_pci_iomap[i]) - 1); 96 for (i = 0; i < MEMMAP_SIZE; i++) 97 printf(" PCI Mem %d %08x to %08x\n", 98 i, mem[i], MAP_TOP(mspcic_pci_memmap[i]) - 1); 99 #endif 100 101 /* 102 * Scan our known PCI devices and collect: 103 * maximum bus number 104 * maximum used address in each I/O and memory range 105 */ 106 while(node) { 107 uint32_t busrange[2]; 108 109 #ifdef SPARC_PCI_FIXUP_DEBUG 110 OF_getprop(node, "name", &name, sizeof(name)); 111 printf("> checking node %x: %s\n", node, name); 112 #endif 113 len = OF_getproplen(node, "reg"); 114 if (len < sizeof(reg)) 115 continue; 116 if (OF_getprop(node, "reg", (void *)®, sizeof(reg)) != len) 117 panic("pci_probe_bus: OF_getprop len botch"); 118 bus = OFW_PCI_PHYS_HI_BUS(reg.phys_hi); 119 dev = OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi); 120 fun = OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi); 121 tag = PCITAG_CREATE(node, bus, dev, fun); 122 #ifdef SPARC_PCI_FIXUP_DEBUG 123 printf("> bus %2d, dev %2d, fun %2d\n", 124 PCITAG_BUS(tag), PCITAG_DEV(tag), PCITAG_FUN(tag)); 125 #endif 126 /* Enable all the different spaces/errors for this device */ 127 pci_conf_write(NULL, tag, PCI_COMMAND_STATUS_REG, 128 PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | 129 PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_PARITY_ENABLE); 130 131 /* Configured PCI-PCI bridges - increment max bus number */ 132 if ((OF_getprop(node, "bus-range", (void *)&busrange, 133 sizeof(busrange)) == sizeof(busrange))) 134 { 135 if (busrange[1] > maxbus) 136 maxbus = busrange[1] + 1; 137 if (maxbus > 255) 138 panic("mspcic_pci_scan: maxbus > 255"); 139 140 /* go down one level */ 141 node = OF_child(node); 142 continue; 143 } 144 145 /* Next node, or parent's next node (if we descended) */ 146 if (OF_peer(node)) 147 node = OF_peer(node); 148 else if (OF_parent(node) != root) { 149 node = OF_parent(node); 150 node = OF_peer(node); 151 } else 152 node = 0; 153 154 /* Check the Mem and I/O allocations for this node */ 155 val = pci_conf_read(NULL, tag, PCI_BHLC_REG); 156 if (PCI_HDRTYPE_TYPE(val)) /* Type 0x00 has BAR's */ 157 continue; /* Skip to next node */ 158 159 /* 160 * Read BAR's: 161 * save the current (address) value 162 * write 0xffffffff and read back the size mask 163 * restore the saved value 164 */ 165 for (i = 0; i < 6; i++) { 166 saved = pci_conf_read(NULL, tag, PCI_BAR(i)); 167 pci_conf_write(NULL, tag, PCI_BAR(i), (pcireg_t) ~0x0); 168 val = pci_conf_read(NULL, tag, PCI_BAR(i)); 169 pci_conf_write(NULL, tag, PCI_BAR(i), saved); 170 if (!val) 171 continue; /* Skip to next BAR */ 172 saved &= 0xfffffffe; /* Remove I/O bit */ 173 #ifdef SPARC_PCI_FIXUP_DEBUG 174 printf("> BAR %02x: value %08x mask %08x\n", 175 PCI_BAR(i), saved, val); 176 #endif 177 178 /* Compare the address + size against our mappings */ 179 if (PCI_MAPREG_TYPE(val) == PCI_MAPREG_TYPE_IO) { 180 saved = saved + PCI_MAPREG_IO_SIZE(val); 181 for (j = 0; j < IOMAP_SIZE; j++) 182 if (saved > io[j] && saved <= 183 MAP_TOP(mspcic_pci_iomap[j])) 184 io[j] = saved; 185 } else { /* PCI_MAPREG_TYPE_MEM */ 186 saved = saved + PCI_MAPREG_MEM_SIZE(val); 187 for (j = 0; j < MEMMAP_SIZE; j++) 188 if (saved > mem[j] && saved <= 189 MAP_TOP(mspcic_pci_memmap[j])) 190 mem[j] = saved; 191 } 192 } 193 194 /* Read ROM */ 195 saved = pci_conf_read(NULL, tag, PCI_MAPREG_ROM); 196 pci_conf_write(NULL, tag, PCI_MAPREG_ROM, (pcireg_t) ~0x0); 197 val = pci_conf_read(NULL, tag, PCI_MAPREG_ROM); 198 pci_conf_write(NULL, tag, PCI_MAPREG_ROM, saved); 199 if (val) { 200 #ifdef SPARC_PCI_FIXUP_DEBUG 201 printf("> ROM: start %08x mask %08x\n", saved, val); 202 #endif 203 saved = saved + PCI_MAPREG_MEM_SIZE(val); 204 for (j = 0; j < MEMMAP_SIZE; j++) 205 if (saved > mem[j] && saved <= 206 MAP_TOP(mspcic_pci_memmap[j])) 207 mem[j] = saved; 208 } 209 } 210 211 #ifdef SPARC_PCI_FIXUP_DEBUG 212 printf("mspcic_pci_scan finish:\n"); 213 printf(" max bus %d\n", maxbus); 214 for (i = 0; i < IOMAP_SIZE; i++) 215 if (io[i] < MAP_TOP(mspcic_pci_iomap[i]) - 1) 216 printf(" PCI I/O free %d %08x to %08x\n", 217 i, io[i], MAP_TOP(mspcic_pci_iomap[i]) - 1); 218 else 219 printf(" PCI I/O %d full %08x to %08x\n", 220 i, mspcic_pci_iomap[i].sysbase, 221 MAP_TOP(mspcic_pci_iomap[i]) - 1); 222 for (i = 0; i < MEMMAP_SIZE; i++) 223 if (mem[i] < MAP_TOP(mspcic_pci_memmap[i]) - 1) 224 printf(" PCI Mem free %d %08x to %08x\n", 225 i, mem[i], MAP_TOP(mspcic_pci_memmap[i]) - 1); 226 else 227 printf(" PCI %d Mem full %08x to %08x\n", 228 i, mspcic_pci_memmap[i].sysbase, 229 MAP_TOP(mspcic_pci_memmap[i]) - 1); 230 #endif 231 232 node = OF_child(root); 233 /* 234 * Scan our known PCI devices and fix up any buses that 235 * the firmware didn't configure. 236 */ 237 while(node) { 238 int next, k; 239 240 /* Next node, or parent's next node (if we descended) */ 241 if (OF_peer(node)) 242 next = OF_peer(node); 243 else if (OF_parent(node) != root) { 244 next = OF_parent(node); 245 next = OF_peer(node); 246 } else 247 next = 0; 248 249 len = OF_getproplen(node, "class-code"); 250 if (!len) { 251 node = next; 252 continue; 253 } 254 OF_getprop(node, "class-code", &class, len); 255 if (!IS_PCI_BRIDGE(class)) { 256 node = next; 257 continue; 258 } 259 len = OF_getproplen(node, "reg"); 260 if (len < sizeof(reg)) 261 continue; 262 if (OF_getprop(node, "reg", (void *)®, sizeof(reg)) != len) 263 panic("pci_probe_bus: OF_getprop len botch"); 264 bus = OFW_PCI_PHYS_HI_BUS(reg.phys_hi); 265 dev = OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi); 266 fun = OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi); 267 tag = PCITAG_CREATE(node, bus, dev, fun); 268 269 /* 270 * Find ranges with largest free space 271 * Round up start to 12 bit (io) and 20 bit (mem) multiples 272 * because bridge base/limit registers have that granularity. 273 */ 274 i = 0; 275 j = 0; 276 for (k = 1; k < IOMAP_SIZE; k++) { 277 io[k] = RND_IO_START(io[k], 0xf000); 278 if (MAP_TOP(mspcic_pci_iomap[k]) - io[k] > 279 MAP_TOP(mspcic_pci_iomap[i]) - io[i]) 280 i = k; 281 } 282 for (k = 1; k < MEMMAP_SIZE; k++) { 283 mem[k] = RND_MEM_START(mem[k], 0xfff00000); 284 if (MAP_TOP(mspcic_pci_memmap[k]) - mem[k] > 285 MAP_TOP(mspcic_pci_memmap[j]) - mem[j]) 286 j = k; 287 } 288 mspcic_pci_fixup(1, tag, &maxbus, &io[i], &mem[j], 289 MAP_TOP(mspcic_pci_iomap[i]), 290 MAP_TOP(mspcic_pci_memmap[j])); 291 node = next; 292 } 293 } 294 295 static void 296 mspcic_pci_fixup(int depth, pcitag_t starttag, int *maxbus, uint32_t *io, 297 uint32_t *mem, uint32_t iotop, uint32_t memtop) 298 { 299 int i, j, startbus; 300 uint32_t startio, startmem; 301 pcitag_t tag; 302 pcireg_t val, size, start; 303 304 startbus = *maxbus; 305 startio = *io; 306 startmem = *mem; 307 308 #ifdef SPARC_PCI_FIXUP_DEBUG 309 printf("mspcic_pci_fixup start:\n"); 310 printf(" bridge at (%d %d %d), depth %d\n", PCITAG_BUS(starttag), 311 PCITAG_DEV(starttag), PCITAG_FUN(starttag), depth); 312 printf(" start bus %d\n", startbus); 313 printf(" io free %08x to %08x\n", startio, iotop - 1); 314 printf(" mem free %08x to %08x\n", startmem, memtop - 1); 315 #endif 316 317 pci_conf_write(NULL, starttag, PCI_COMMAND_STATUS_REG, 318 PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE 319 | PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_PARITY_ENABLE); 320 pci_conf_write(NULL, starttag, PCI_BRIDGE_CONTROL_REG, 0); 321 322 /* Secondary bus = startbus, subordinate bus = 0xff */ 323 pci_conf_write(NULL, starttag, PCI_BRIDGE_BUS_REG, 324 __SHIFTIN(startbus & 0xff, PCI_BRIDGE_BUS_SECONDARY) | 325 __SHIFTIN(0xff, PCI_BRIDGE_BUS_SUBORDINATE)); 326 327 /* 328 * Fix up bus numbering, bus addresses, device addresses, 329 * interrupts and fast back-to-back capabilities. 330 */ 331 for (i = 0; i < MAX_DEVFUN; i++) { 332 tag = PCITAG_CREATE(0, startbus, i / 8, i % 8); 333 /* Enable all the different spaces for this device */ 334 pci_conf_write(NULL, tag, PCI_COMMAND_STATUS_REG, 335 PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE 336 | PCI_COMMAND_IO_ENABLE | PCI_COMMAND_PARITY_ENABLE); 337 val = pci_conf_read(NULL, tag, PCI_ID_REG); 338 if (PCI_VENDOR(val) == PCI_VENDOR_INVALID) { 339 i = DF_NEXTDEV(i); 340 continue; 341 } 342 #ifdef SPARC_PCI_FIXUP_DEBUG 343 printf("> Found %04x:%04x at (%d %d %d)\n", PCI_VENDOR(val), 344 PCI_PRODUCT(val), startbus, i / 8, i % 8); 345 #endif 346 347 /* Check interrupt pin(s), and write depth to line */ 348 val = pci_conf_read(NULL, tag, PCI_INTERRUPT_REG); 349 if (PCI_INTERRUPT_PIN(val)) { 350 val = (val & ~(PCI_INTERRUPT_LINE_MASK << 351 PCI_INTERRUPT_LINE_SHIFT)) | depth; 352 pci_conf_write(NULL, tag, PCI_INTERRUPT_REG, val); 353 } 354 355 /* Check device type */ 356 val = pci_conf_read(NULL, tag, PCI_CLASS_REG); 357 if (IS_PCI_BRIDGE(val)) { 358 (*maxbus)++; 359 if (*maxbus > 255) 360 panic("mspcic_pci_fixup: maxbus > 255"); 361 mspcic_pci_fixup(depth + 1, tag, maxbus, io, mem, 362 iotop, memtop); 363 } 364 365 pci_conf_write(NULL, tag, PCI_MAPREG_ROM, (pcireg_t) ~0x0); 366 val = pci_conf_read(NULL, tag, PCI_MAPREG_ROM); 367 if (val) { 368 size = PCI_MAPREG_MEM_SIZE(val); 369 start = RND_MEM_START(*mem, val); 370 if (start + size <= memtop) { 371 *mem = start + size; 372 pci_conf_write(NULL, tag, PCI_MAPREG_ROM, 373 start); 374 #ifdef SPARC_PCI_FIXUP_DEBUG 375 printf("> ROM: %08x to %08x mask %08x\n", 376 start, (*mem) - 1, val); 377 #endif 378 } 379 } 380 381 val = pci_conf_read(NULL, tag, PCI_BHLC_REG); 382 /* Check for multifunction devices and for BAR's */ 383 if (!PCI_HDRTYPE_MULTIFN(val)) 384 i = DF_NEXTDEV(i); 385 if (PCI_HDRTYPE_TYPE(val)) 386 continue; 387 388 /* 389 * Read BAR's: 390 * write 0xffffffff and read back the size mask 391 * set the base address 392 */ 393 for (j = 0; j < 6; j++) { 394 pci_conf_write(NULL, tag, PCI_BAR(j), 395 (pcireg_t) ~0x0); 396 val = pci_conf_read(NULL, tag, PCI_BAR(j)); 397 if (!val) 398 continue; 399 if (PCI_MAPREG_TYPE(val) == 400 PCI_MAPREG_TYPE_IO) { 401 size = PCI_MAPREG_IO_SIZE(val); 402 start = RND_IO_START(*io, val); 403 if (start + size <= iotop) { 404 *io = start + size; 405 pci_conf_write(NULL, tag, PCI_BAR(j), 406 start); 407 #ifdef SPARC_PCI_FIXUP_DEBUG 408 printf("> BAR %02x set: %08x to %08x " 409 "mask %08x (io)\n", PCI_BAR(j), 410 start, (*io) - 1, val); 411 #endif 412 } else { 413 pci_conf_write(NULL, tag, 414 PCI_COMMAND_STATUS_REG, 0); 415 printf("Fixup failed for (%d %d %d)\n", 416 startbus, i / 8, i % 8); 417 } 418 } else { /* PCI_MAPREG_TYPE_MEM */ 419 size = PCI_MAPREG_MEM_SIZE(val); 420 start = RND_MEM_START(*mem, val); 421 if (start + size <= memtop) { 422 *mem = start + size; 423 pci_conf_write(NULL, tag, PCI_BAR(j), 424 start); 425 #ifdef SPARC_PCI_FIXUP_DEBUG 426 printf("> BAR %02x set: %08x to %08x " 427 "mask %08x (mem)\n", PCI_BAR(j), 428 start, (*mem) - 1, val); 429 #endif 430 } else { 431 pci_conf_write(NULL, tag, 432 PCI_COMMAND_STATUS_REG, 0); 433 printf("Fixup failed for (%d %d %d)\n", 434 startbus, i / 8, i % 8); 435 } 436 } 437 } 438 } 439 440 /* Secondary bus = startbus, subordinate bus = maxbus */ 441 pci_conf_write(NULL, starttag, PCI_BRIDGE_BUS_REG, 442 __SHIFTIN(startbus & 0xff, PCI_BRIDGE_BUS_SECONDARY) | 443 __SHIFTIN(*maxbus & 0xff, PCI_BRIDGE_BUS_SUBORDINATE)); 444 445 /* 16-bit I/O range */ 446 val = ((startio & 0xf000) >> 8) | ((*(io) - 1) & 0xf000); 447 pci_conf_write(NULL, starttag, PCI_BRIDGE_STATIO_REG, val); 448 #ifdef SPARC_PCI_FIXUP_DEBUG 449 printf("16-bit I/O range = %04x\n", 450 pci_conf_read(NULL, starttag, PCI_BRIDGE_STATIO_REG) & 0xffff); 451 #endif 452 453 /* Mem range and (disabled) prefetch mem range */ 454 val = ((startmem & 0xfff00000) >> 16) | 455 ((*(mem) - 1) & 0xfff00000); 456 pci_conf_write(NULL, starttag, PCI_BRIDGE_MEMORY_REG, val); 457 pci_conf_write(NULL, starttag, PCI_BRIDGE_PREFETCHMEM_REG, 0x0000ffff); 458 #ifdef SPARC_PCI_FIXUP_DEBUG 459 printf("Mem range = %08x\n", 460 pci_conf_read(NULL, starttag, PCI_BRIDGE_MEMORY_REG)); 461 printf("Pref mem range = %08x\n", 462 pci_conf_read(NULL, starttag, PCI_BRIDGE_PREFETCHMEM_REG)); 463 #endif 464 465 /* 32-bit I/O range (if supported) */ 466 val = pci_conf_read(NULL, starttag, PCI_BRIDGE_STATIO_REG); 467 if ((val & 0x0101) == 0x0101) { 468 val = ((startio & 0xffff0000) >> 16) | 469 ((*(io) - 1) & 0xffff0000); 470 pci_conf_write(NULL, starttag, PCI_BRIDGE_IOHIGH_REG, val); 471 } 472 #ifdef SPARC_PCI_FIXUP_DEBUG 473 printf("32-bit I/O range = %08x\n", 474 pci_conf_read(NULL, starttag, PCI_BRIDGE_IOHIGH_REG)); 475 #endif 476 477 /* 64-bit prefetchable range (if supported) - set it to 0 */ 478 val = pci_conf_read(NULL, starttag, PCI_BRIDGE_PREFETCHMEM_REG); 479 if (val & 0x01) { 480 pci_conf_write(NULL, starttag, 481 PCI_BRIDGE_PREFETCHBASEUP32_REG, (pcireg_t) ~0); 482 pci_conf_write(NULL, starttag, 483 PCI_BRIDGE_PREFETCHLIMITUP32_REG, (pcireg_t) 0); 484 } 485 486 #ifdef SPARC_PCI_FIXUP_DEBUG 487 printf("mspcic_pci_fixup finish:\n"); 488 printf(" bridge at (%d %d %d), depth %d\n", PCITAG_BUS(starttag), 489 PCITAG_DEV(starttag), PCITAG_FUN(starttag), depth); 490 printf(" bus range %d to %d\n", startbus, *maxbus); 491 printf(" io used %08x to %08x\n", startio, *(io) - 1); 492 printf(" mem used %08x to %08x\n", startmem, *(mem) - 1); 493 #endif 494 } 495 496 /* ====================================================================== 497 * 498 * PCI device fixup for autoconf 499 */ 500 501 void 502 set_pci_props(device_t dev) 503 { 504 struct idprom *idp; 505 uint8_t eaddr[ETHER_ADDR_LEN]; 506 prop_dictionary_t dict; 507 prop_data_t blob; 508 509 /* 510 * We only handle network devices. 511 * XXX: We have to set the ethernet address for HME cards here. If 512 * we leave this to the driver attachment, we will crash when trying 513 * to map the 16MB Ebus device in if_hme_pci.c. 514 */ 515 if (!(device_is_a(dev, "le") || device_is_a(dev, "hme") || 516 device_is_a(dev, "be") || device_is_a(dev, "ie"))) 517 return; 518 519 idp = prom_getidprom(); 520 memcpy(eaddr, idp->idp_etheraddr, 6); 521 dict = device_properties(dev); 522 blob = prop_data_create_data(eaddr, ETHER_ADDR_LEN); 523 prop_dictionary_set(dict, "mac-address", blob); 524 prop_object_release(blob); 525 } 526