06bfc1a6f633b248de998622d24cb2f394c98a34
[dpdk.git] / lib / librte_eal / linuxapp / eal / eal_pci.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <string.h>
35 #include <dirent.h>
36 #include <sys/mman.h>
37
38 #include <rte_log.h>
39 #include <rte_pci.h>
40 #include <rte_tailq.h>
41 #include <rte_eal_memconfig.h>
42 #include <rte_malloc.h>
43 #include <rte_devargs.h>
44 #include <rte_memcpy.h>
45
46 #include "rte_pci_dev_ids.h"
47 #include "eal_filesystem.h"
48 #include "eal_private.h"
49 #include "eal_pci_init.h"
50
51 /**
52  * @file
53  * PCI probing under linux
54  *
55  * This code is used to simulate a PCI probe by parsing information in sysfs.
56  * When a registered device matches a driver, it is then initialized with
57  * IGB_UIO driver (or doesn't initialize, if the device wasn't bound to it).
58  */
59
60 struct mapped_pci_res_list *pci_res_list = NULL;
61
62 /* unbind kernel driver for this device */
63 static int
64 pci_unbind_kernel_driver(struct rte_pci_device *dev)
65 {
66         int n;
67         FILE *f;
68         char filename[PATH_MAX];
69         char buf[BUFSIZ];
70         struct rte_pci_addr *loc = &dev->addr;
71
72         /* open /sys/bus/pci/devices/AAAA:BB:CC.D/driver */
73         snprintf(filename, sizeof(filename),
74                  SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/driver/unbind",
75                  loc->domain, loc->bus, loc->devid, loc->function);
76
77         f = fopen(filename, "w");
78         if (f == NULL) /* device was not bound */
79                 return 0;
80
81         n = snprintf(buf, sizeof(buf), PCI_PRI_FMT "\n",
82                      loc->domain, loc->bus, loc->devid, loc->function);
83         if ((n < 0) || (n >= (int)sizeof(buf))) {
84                 RTE_LOG(ERR, EAL, "%s(): snprintf failed\n", __func__);
85                 goto error;
86         }
87         if (fwrite(buf, n, 1, f) == 0) {
88                 RTE_LOG(ERR, EAL, "%s(): could not write to %s\n", __func__,
89                                 filename);
90                 goto error;
91         }
92
93         fclose(f);
94         return 0;
95
96 error:
97         fclose(f);
98         return -1;
99 }
100
101 static int
102 pci_get_kernel_driver_by_path(const char *filename, char *dri_name)
103 {
104         int count;
105         char path[PATH_MAX];
106         char *name;
107
108         if (!filename || !dri_name)
109                 return -1;
110
111         count = readlink(filename, path, PATH_MAX);
112         if (count >= PATH_MAX)
113                 return -1;
114
115         /* For device does not have a driver */
116         if (count < 0)
117                 return 1;
118
119         path[count] = '\0';
120
121         name = strrchr(path, '/');
122         if (name) {
123                 strncpy(dri_name, name + 1, strlen(name + 1) + 1);
124                 return 0;
125         }
126
127         return -1;
128 }
129
130 void *
131 pci_find_max_end_va(void)
132 {
133         const struct rte_memseg *seg = rte_eal_get_physmem_layout();
134         const struct rte_memseg *last = seg;
135         unsigned i = 0;
136
137         for (i = 0; i < RTE_MAX_MEMSEG; i++, seg++) {
138                 if (seg->addr == NULL)
139                         break;
140
141                 if (seg->addr > last->addr)
142                         last = seg;
143
144         }
145         return RTE_PTR_ADD(last->addr, last->len);
146 }
147
148
149 /* map a particular resource from a file */
150 void *
151 pci_map_resource(void *requested_addr, int fd, off_t offset, size_t size,
152                  int additional_flags)
153 {
154         void *mapaddr;
155
156         /* Map the PCI memory resource of device */
157         mapaddr = mmap(requested_addr, size, PROT_READ | PROT_WRITE,
158                         MAP_SHARED | additional_flags, fd, offset);
159         if (mapaddr == MAP_FAILED) {
160                 RTE_LOG(ERR, EAL, "%s(): cannot mmap(%d, %p, 0x%lx, 0x%lx): %s (%p)\n",
161                         __func__, fd, requested_addr,
162                         (unsigned long)size, (unsigned long)offset,
163                         strerror(errno), mapaddr);
164         } else {
165                 RTE_LOG(DEBUG, EAL, "  PCI memory mapped at %p\n", mapaddr);
166         }
167
168         return mapaddr;
169 }
170
171 /* parse the "resource" sysfs file */
172 static int
173 pci_parse_sysfs_resource(const char *filename, struct rte_pci_device *dev)
174 {
175         FILE *f;
176         char buf[BUFSIZ];
177         union pci_resource_info {
178                 struct {
179                         char *phys_addr;
180                         char *end_addr;
181                         char *flags;
182                 };
183                 char *ptrs[PCI_RESOURCE_FMT_NVAL];
184         } res_info;
185         int i;
186         uint64_t phys_addr, end_addr, flags;
187
188         f = fopen(filename, "r");
189         if (f == NULL) {
190                 RTE_LOG(ERR, EAL, "Cannot open sysfs resource\n");
191                 return -1;
192         }
193
194         for (i = 0; i<PCI_MAX_RESOURCE; i++) {
195
196                 if (fgets(buf, sizeof(buf), f) == NULL) {
197                         RTE_LOG(ERR, EAL,
198                                 "%s(): cannot read resource\n", __func__);
199                         goto error;
200                 }
201
202                 if (rte_strsplit(buf, sizeof(buf), res_info.ptrs, 3, ' ') != 3) {
203                         RTE_LOG(ERR, EAL,
204                                 "%s(): bad resource format\n", __func__);
205                         goto error;
206                 }
207                 errno = 0;
208                 phys_addr = strtoull(res_info.phys_addr, NULL, 16);
209                 end_addr = strtoull(res_info.end_addr, NULL, 16);
210                 flags = strtoull(res_info.flags, NULL, 16);
211                 if (errno != 0) {
212                         RTE_LOG(ERR, EAL,
213                                 "%s(): bad resource format\n", __func__);
214                         goto error;
215                 }
216
217                 if (flags & IORESOURCE_MEM) {
218                         dev->mem_resource[i].phys_addr = phys_addr;
219                         dev->mem_resource[i].len = end_addr - phys_addr + 1;
220                         /* not mapped for now */
221                         dev->mem_resource[i].addr = NULL;
222                 }
223         }
224         fclose(f);
225         return 0;
226
227 error:
228         fclose(f);
229         return -1;
230 }
231
232 /* Scan one pci sysfs entry, and fill the devices list from it. */
233 static int
234 pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
235              uint8_t devid, uint8_t function)
236 {
237         char filename[PATH_MAX];
238         unsigned long tmp;
239         struct rte_pci_device *dev;
240         char driver[PATH_MAX];
241         int ret;
242
243         dev = malloc(sizeof(*dev));
244         if (dev == NULL)
245                 return -1;
246
247         memset(dev, 0, sizeof(*dev));
248         dev->addr.domain = domain;
249         dev->addr.bus = bus;
250         dev->addr.devid = devid;
251         dev->addr.function = function;
252
253         /* get vendor id */
254         snprintf(filename, sizeof(filename), "%s/vendor", dirname);
255         if (eal_parse_sysfs_value(filename, &tmp) < 0) {
256                 free(dev);
257                 return -1;
258         }
259         dev->id.vendor_id = (uint16_t)tmp;
260
261         /* get device id */
262         snprintf(filename, sizeof(filename), "%s/device", dirname);
263         if (eal_parse_sysfs_value(filename, &tmp) < 0) {
264                 free(dev);
265                 return -1;
266         }
267         dev->id.device_id = (uint16_t)tmp;
268
269         /* get subsystem_vendor id */
270         snprintf(filename, sizeof(filename), "%s/subsystem_vendor",
271                  dirname);
272         if (eal_parse_sysfs_value(filename, &tmp) < 0) {
273                 free(dev);
274                 return -1;
275         }
276         dev->id.subsystem_vendor_id = (uint16_t)tmp;
277
278         /* get subsystem_device id */
279         snprintf(filename, sizeof(filename), "%s/subsystem_device",
280                  dirname);
281         if (eal_parse_sysfs_value(filename, &tmp) < 0) {
282                 free(dev);
283                 return -1;
284         }
285         dev->id.subsystem_device_id = (uint16_t)tmp;
286
287         /* get max_vfs */
288         dev->max_vfs = 0;
289         snprintf(filename, sizeof(filename), "%s/max_vfs", dirname);
290         if (!access(filename, F_OK) &&
291             eal_parse_sysfs_value(filename, &tmp) == 0)
292                 dev->max_vfs = (uint16_t)tmp;
293         else {
294                 /* for non igb_uio driver, need kernel version >= 3.8 */
295                 snprintf(filename, sizeof(filename),
296                          "%s/sriov_numvfs", dirname);
297                 if (!access(filename, F_OK) &&
298                     eal_parse_sysfs_value(filename, &tmp) == 0)
299                         dev->max_vfs = (uint16_t)tmp;
300         }
301
302         /* get numa node */
303         snprintf(filename, sizeof(filename), "%s/numa_node",
304                  dirname);
305         if (access(filename, R_OK) != 0) {
306                 /* if no NUMA support just set node to -1 */
307                 dev->numa_node = -1;
308         } else {
309                 if (eal_parse_sysfs_value(filename, &tmp) < 0) {
310                         free(dev);
311                         return -1;
312                 }
313                 dev->numa_node = tmp;
314         }
315
316         /* parse resources */
317         snprintf(filename, sizeof(filename), "%s/resource", dirname);
318         if (pci_parse_sysfs_resource(filename, dev) < 0) {
319                 RTE_LOG(ERR, EAL, "%s(): cannot parse resource\n", __func__);
320                 free(dev);
321                 return -1;
322         }
323
324         /* parse driver */
325         snprintf(filename, sizeof(filename), "%s/driver", dirname);
326         ret = pci_get_kernel_driver_by_path(filename, driver);
327         if (!ret) {
328                 if (!strcmp(driver, "vfio-pci"))
329                         dev->pt_driver = RTE_PT_VFIO;
330                 else if (!strcmp(driver, "igb_uio"))
331                         dev->pt_driver = RTE_PT_IGB_UIO;
332                 else if (!strcmp(driver, "uio_pci_generic"))
333                         dev->pt_driver = RTE_PT_UIO_GENERIC;
334                 else
335                         dev->pt_driver = RTE_PT_UNKNOWN;
336         } else if (ret < 0) {
337                 RTE_LOG(ERR, EAL, "Fail to get kernel driver\n");
338                 free(dev);
339                 return -1;
340         } else
341                 dev->pt_driver = RTE_PT_UNKNOWN;
342
343         /* device is valid, add in list (sorted) */
344         if (TAILQ_EMPTY(&pci_device_list)) {
345                 TAILQ_INSERT_TAIL(&pci_device_list, dev, next);
346         }
347         else {
348                 struct rte_pci_device *dev2 = NULL;
349                 int ret;
350
351                 TAILQ_FOREACH(dev2, &pci_device_list, next) {
352                         ret = rte_eal_compare_pci_addr(&dev->addr, &dev2->addr);
353                         if (ret > 0)
354                                 continue;
355                         else if (ret < 0) {
356                                 TAILQ_INSERT_BEFORE(dev2, dev, next);
357                                 return 0;
358                         } else { /* already registered */
359                                 /* update pt_driver */
360                                 dev2->pt_driver = dev->pt_driver;
361                                 dev2->max_vfs = dev->max_vfs;
362                                 memmove(dev2->mem_resource,
363                                         dev->mem_resource,
364                                         sizeof(dev->mem_resource));
365                                 free(dev);
366                                 return 0;
367                         }
368                 }
369                 TAILQ_INSERT_TAIL(&pci_device_list, dev, next);
370         }
371
372         return 0;
373 }
374
375 /*
376  * split up a pci address into its constituent parts.
377  */
378 static int
379 parse_pci_addr_format(const char *buf, int bufsize, uint16_t *domain,
380                 uint8_t *bus, uint8_t *devid, uint8_t *function)
381 {
382         /* first split on ':' */
383         union splitaddr {
384                 struct {
385                         char *domain;
386                         char *bus;
387                         char *devid;
388                         char *function;
389                 };
390                 char *str[PCI_FMT_NVAL]; /* last element-separator is "." not ":" */
391         } splitaddr;
392
393         char *buf_copy = strndup(buf, bufsize);
394         if (buf_copy == NULL)
395                 return -1;
396
397         if (rte_strsplit(buf_copy, bufsize, splitaddr.str, PCI_FMT_NVAL, ':')
398                         != PCI_FMT_NVAL - 1)
399                 goto error;
400         /* final split is on '.' between devid and function */
401         splitaddr.function = strchr(splitaddr.devid,'.');
402         if (splitaddr.function == NULL)
403                 goto error;
404         *splitaddr.function++ = '\0';
405
406         /* now convert to int values */
407         errno = 0;
408         *domain = (uint16_t)strtoul(splitaddr.domain, NULL, 16);
409         *bus = (uint8_t)strtoul(splitaddr.bus, NULL, 16);
410         *devid = (uint8_t)strtoul(splitaddr.devid, NULL, 16);
411         *function = (uint8_t)strtoul(splitaddr.function, NULL, 10);
412         if (errno != 0)
413                 goto error;
414
415         free(buf_copy); /* free the copy made with strdup */
416         return 0;
417 error:
418         free(buf_copy);
419         return -1;
420 }
421
422 /*
423  * Scan the content of the PCI bus, and the devices in the devices
424  * list
425  */
426 static int
427 pci_scan(void)
428 {
429         struct dirent *e;
430         DIR *dir;
431         char dirname[PATH_MAX];
432         uint16_t domain;
433         uint8_t bus, devid, function;
434
435         dir = opendir(SYSFS_PCI_DEVICES);
436         if (dir == NULL) {
437                 RTE_LOG(ERR, EAL, "%s(): opendir failed: %s\n",
438                         __func__, strerror(errno));
439                 return -1;
440         }
441
442         while ((e = readdir(dir)) != NULL) {
443                 if (e->d_name[0] == '.')
444                         continue;
445
446                 if (parse_pci_addr_format(e->d_name, sizeof(e->d_name), &domain,
447                                 &bus, &devid, &function) != 0)
448                         continue;
449
450                 snprintf(dirname, sizeof(dirname), "%s/%s", SYSFS_PCI_DEVICES,
451                          e->d_name);
452                 if (pci_scan_one(dirname, domain, bus, devid, function) < 0)
453                         goto error;
454         }
455         closedir(dir);
456         return 0;
457
458 error:
459         closedir(dir);
460         return -1;
461 }
462
463 #ifdef RTE_PCI_CONFIG
464 static int
465 pci_config_extended_tag(struct rte_pci_device *dev)
466 {
467         struct rte_pci_addr *loc = &dev->addr;
468         char filename[PATH_MAX];
469         char buf[BUFSIZ];
470         FILE *f;
471
472         /* not configured, let it as is */
473         if (strncmp(RTE_PCI_EXTENDED_TAG, "on", 2) != 0 &&
474                 strncmp(RTE_PCI_EXTENDED_TAG, "off", 3) != 0)
475                 return 0;
476
477         snprintf(filename, sizeof(filename),
478                 SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/" "extended_tag",
479                 loc->domain, loc->bus, loc->devid, loc->function);
480         f = fopen(filename, "rw+");
481         if (!f)
482                 return -1;
483
484         fgets(buf, sizeof(buf), f);
485         if (strncmp(RTE_PCI_EXTENDED_TAG, "on", 2) == 0) {
486                 /* enable Extended Tag*/
487                 if (strncmp(buf, "on", 2) != 0) {
488                         fseek(f, 0, SEEK_SET);
489                         fputs("on", f);
490                 }
491         } else {
492                 /* disable Extended Tag */
493                 if (strncmp(buf, "off", 3) != 0) {
494                         fseek(f, 0, SEEK_SET);
495                         fputs("off", f);
496                 }
497         }
498         fclose(f);
499
500         return 0;
501 }
502
503 static int
504 pci_config_max_read_request_size(struct rte_pci_device *dev)
505 {
506         struct rte_pci_addr *loc = &dev->addr;
507         char filename[PATH_MAX];
508         char buf[BUFSIZ], param[BUFSIZ];
509         FILE *f;
510         /* size can be 128, 256, 512, 1024, 2048, 4096 */
511         uint32_t max_size = RTE_PCI_MAX_READ_REQUEST_SIZE;
512
513         /* not configured, let it as is */
514         if (!max_size)
515                 return 0;
516
517         snprintf(filename, sizeof(filename),
518                 SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/" "max_read_request_size",
519                         loc->domain, loc->bus, loc->devid, loc->function);
520         f = fopen(filename, "rw+");
521         if (!f)
522                 return -1;
523
524         fgets(buf, sizeof(buf), f);
525         snprintf(param, sizeof(param), "%d", max_size);
526
527         /* check if the size to be set is the same as current */
528         if (strcmp(buf, param) == 0) {
529                 fclose(f);
530                 return 0;
531         }
532         fseek(f, 0, SEEK_SET);
533         fputs(param, f);
534         fclose(f);
535
536         return 0;
537 }
538
539 static void
540 pci_config_space_set(struct rte_pci_device *dev)
541 {
542         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
543                 return;
544
545         /* configure extended tag */
546         pci_config_extended_tag(dev);
547
548         /* configure max read request size */
549         pci_config_max_read_request_size(dev);
550 }
551 #endif
552
553 static int
554 pci_map_device(struct rte_pci_device *dev)
555 {
556         int ret = -1;
557
558         /* try mapping the NIC resources using VFIO if it exists */
559         switch (dev->pt_driver) {
560         case RTE_PT_VFIO:
561 #ifdef VFIO_PRESENT
562                 if (pci_vfio_is_enabled())
563                         ret = pci_vfio_map_resource(dev);
564 #endif
565                 break;
566         case RTE_PT_IGB_UIO:
567         case RTE_PT_UIO_GENERIC:
568                 /* map resources for devices that use uio */
569                 ret = pci_uio_map_resource(dev);
570                 break;
571         default:
572                 RTE_LOG(DEBUG, EAL, "  Not managed by known pt driver,"
573                         " skipped\n");
574                 ret = 1;
575                 break;
576         }
577
578         return ret;
579 }
580
581 /*
582  * If vendor/device ID match, call the devinit() function of the
583  * driver.
584  */
585 int
586 rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *dev)
587 {
588         int ret;
589         struct rte_pci_id *id_table;
590
591         for (id_table = dr->id_table ; id_table->vendor_id != 0; id_table++) {
592
593                 /* check if device's identifiers match the driver's ones */
594                 if (id_table->vendor_id != dev->id.vendor_id &&
595                                 id_table->vendor_id != PCI_ANY_ID)
596                         continue;
597                 if (id_table->device_id != dev->id.device_id &&
598                                 id_table->device_id != PCI_ANY_ID)
599                         continue;
600                 if (id_table->subsystem_vendor_id != dev->id.subsystem_vendor_id &&
601                                 id_table->subsystem_vendor_id != PCI_ANY_ID)
602                         continue;
603                 if (id_table->subsystem_device_id != dev->id.subsystem_device_id &&
604                                 id_table->subsystem_device_id != PCI_ANY_ID)
605                         continue;
606
607                 struct rte_pci_addr *loc = &dev->addr;
608
609                 RTE_LOG(DEBUG, EAL, "PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
610                                 loc->domain, loc->bus, loc->devid, loc->function,
611                                 dev->numa_node);
612
613                 RTE_LOG(DEBUG, EAL, "  probe driver: %x:%x %s\n", dev->id.vendor_id,
614                                 dev->id.device_id, dr->name);
615
616                 /* no initialization when blacklisted, return without error */
617                 if (dev->devargs != NULL &&
618                         dev->devargs->type == RTE_DEVTYPE_BLACKLISTED_PCI) {
619                         RTE_LOG(DEBUG, EAL, "  Device is blacklisted, not initializing\n");
620                         return 1;
621                 }
622
623                 if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING) {
624 #ifdef RTE_PCI_CONFIG
625                         /*
626                          * Set PCIe config space for high performance.
627                          * Return value can be ignored.
628                          */
629                         pci_config_space_set(dev);
630 #endif
631                         /* map resources for devices that use igb_uio */
632                         ret = pci_map_device(dev);
633                         if (ret != 0)
634                                 return ret;
635                 } else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND &&
636                            rte_eal_process_type() == RTE_PROC_PRIMARY) {
637                         /* unbind current driver */
638                         if (pci_unbind_kernel_driver(dev) < 0)
639                                 return -1;
640                 }
641
642                 /* reference driver structure */
643                 dev->driver = dr;
644
645                 /* call the driver devinit() function */
646                 return dr->devinit(dr, dev);
647         }
648         /* return positive value if driver is not found */
649         return 1;
650 }
651
652 /* Init the PCI EAL subsystem */
653 int
654 rte_eal_pci_init(void)
655 {
656         TAILQ_INIT(&pci_driver_list);
657         TAILQ_INIT(&pci_device_list);
658         pci_res_list = RTE_TAILQ_RESERVE_BY_IDX(RTE_TAILQ_PCI,
659                         mapped_pci_res_list);
660
661         /* for debug purposes, PCI can be disabled */
662         if (internal_config.no_pci)
663                 return 0;
664
665         if (pci_scan() < 0) {
666                 RTE_LOG(ERR, EAL, "%s(): Cannot scan PCI bus\n", __func__);
667                 return -1;
668         }
669 #ifdef VFIO_PRESENT
670         pci_vfio_enable();
671
672         if (pci_vfio_is_enabled()) {
673
674                 /* if we are primary process, create a thread to communicate with
675                  * secondary processes. the thread will use a socket to wait for
676                  * requests from secondary process to send open file descriptors,
677                  * because VFIO does not allow multiple open descriptors on a group or
678                  * VFIO container.
679                  */
680                 if (internal_config.process_type == RTE_PROC_PRIMARY &&
681                                 pci_vfio_mp_sync_setup() < 0)
682                         return -1;
683         }
684 #endif
685         return 0;
686 }