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
mspcic_pci_scan(int root)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
mspcic_pci_fixup(int depth,pcitag_t starttag,int * maxbus,uint32_t * io,uint32_t * mem,uint32_t iotop,uint32_t memtop)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
set_pci_props(device_t dev)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