2 * Copyright (C) 2010 Nathan Whitehorn
3 * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
34 #include <sys/malloc.h>
36 #include <sys/clock.h>
38 #include <sys/resource.h>
44 #include <machine/bus.h>
45 #include <machine/platform.h>
46 #include <machine/resource.h>
49 #include "ps3-hvcall.h"
53 static void ps3bus_identify(driver_t
*, device_t
);
54 static int ps3bus_probe(device_t
);
55 static int ps3bus_attach(device_t
);
56 static int ps3bus_print_child(device_t dev
, device_t child
);
57 static int ps3bus_read_ivar(device_t bus
, device_t child
, int which
,
59 static struct resource
*ps3bus_alloc_resource(device_t bus
, device_t child
,
60 int type
, int *rid
, rman_res_t start
, rman_res_t end
,
61 rman_res_t count
, u_int flags
);
62 static int ps3bus_activate_resource(device_t bus
, device_t child
, int type
,
63 int rid
, struct resource
*res
);
64 static bus_dma_tag_t
ps3bus_get_dma_tag(device_t dev
, device_t child
);
65 static int ps3_iommu_map(device_t dev
, bus_dma_segment_t
*segs
, int *nsegs
, bus_addr_t min
, bus_addr_t max
, bus_size_t alignment
,
66 bus_addr_t boundary
, void *cookie
);
67 static int ps3_iommu_unmap(device_t dev
, bus_dma_segment_t
*segs
,
68 int nsegs
, void *cookie
);
69 static int ps3_gettime(device_t dev
, struct timespec
*ts
);
70 static int ps3_settime(device_t dev
, struct timespec
*ts
);
72 struct ps3bus_devinfo
{
80 struct resource_list resources
;
81 bus_dma_tag_t dma_tag
;
84 bus_addr_t dma_base
[4];
87 static MALLOC_DEFINE(M_PS3BUS
, "ps3bus", "PS3 system bus device information");
89 enum ps3bus_irq_type
{
95 enum ps3bus_reg_type
{
100 static device_method_t ps3bus_methods
[] = {
101 /* Device interface */
102 DEVMETHOD(device_identify
, ps3bus_identify
),
103 DEVMETHOD(device_probe
, ps3bus_probe
),
104 DEVMETHOD(device_attach
, ps3bus_attach
),
107 DEVMETHOD(bus_add_child
, bus_generic_add_child
),
108 DEVMETHOD(bus_get_dma_tag
, ps3bus_get_dma_tag
),
109 DEVMETHOD(bus_print_child
, ps3bus_print_child
),
110 DEVMETHOD(bus_read_ivar
, ps3bus_read_ivar
),
111 DEVMETHOD(bus_alloc_resource
, ps3bus_alloc_resource
),
112 DEVMETHOD(bus_activate_resource
, ps3bus_activate_resource
),
113 DEVMETHOD(bus_setup_intr
, bus_generic_setup_intr
),
114 DEVMETHOD(bus_teardown_intr
, bus_generic_teardown_intr
),
116 /* IOMMU interface */
117 DEVMETHOD(iommu_map
, ps3_iommu_map
),
118 DEVMETHOD(iommu_unmap
, ps3_iommu_unmap
),
120 /* Clock interface */
121 DEVMETHOD(clock_gettime
, ps3_gettime
),
122 DEVMETHOD(clock_settime
, ps3_settime
),
127 struct ps3bus_softc
{
128 struct rman sc_mem_rman
;
129 struct rman sc_intr_rman
;
130 struct mem_region
*regions
;
134 static driver_t ps3bus_driver
= {
137 sizeof(struct ps3bus_softc
)
140 static devclass_t ps3bus_devclass
;
142 DRIVER_MODULE(ps3bus
, nexus
, ps3bus_driver
, ps3bus_devclass
, 0, 0);
145 ps3bus_identify(driver_t
*driver
, device_t parent
)
147 if (strcmp(installed_platform(), "ps3") != 0)
150 if (device_find_child(parent
, "ps3bus", -1) == NULL
)
151 BUS_ADD_CHILD(parent
, 0, "ps3bus", 0);
155 ps3bus_probe(device_t dev
)
157 /* Do not attach to any OF nodes that may be present */
159 device_set_desc(dev
, "Playstation 3 System Bus");
161 return (BUS_PROBE_NOWILDCARD
);
165 ps3bus_resources_init(struct rman
*rm
, int bus_index
, int dev_index
,
166 struct ps3bus_devinfo
*dinfo
)
168 uint64_t irq_type
, irq
, outlet
;
169 uint64_t reg_type
, paddr
, len
;
174 resource_list_init(&dinfo
->resources
);
176 lv1_get_logical_ppe_id(&ppe
);
177 thread
= 32 - fls(mfctrl());
179 /* Scan for interrupts */
180 for (i
= 0; i
< 10; i
++) {
181 result
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
182 (lv1_repository_string("bus") >> 32) | bus_index
,
183 lv1_repository_string("dev") | dev_index
,
184 lv1_repository_string("intr") | i
, 0, &irq_type
, &irq
);
191 lv1_construct_event_receive_port(&outlet
);
192 lv1_connect_irq_plug_ext(ppe
, thread
, outlet
, outlet
,
194 lv1_connect_interrupt_event_receive_port(dinfo
->bus
,
195 dinfo
->dev
, outlet
, irq
);
199 lv1_construct_io_irq_outlet(irq
, &outlet
);
200 lv1_connect_irq_plug_ext(ppe
, thread
, outlet
, outlet
,
204 printf("Unknown IRQ type %ld for device %d.%d\n",
205 irq_type
, dinfo
->bus
, dinfo
->dev
);
209 resource_list_add(&dinfo
->resources
, SYS_RES_IRQ
, i
,
213 /* Scan for registers */
214 for (i
= 0; i
< 10; i
++) {
215 result
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
216 (lv1_repository_string("bus") >> 32) | bus_index
,
217 lv1_repository_string("dev") | dev_index
,
218 lv1_repository_string("reg") | i
,
219 lv1_repository_string("type"), ®_type
, &junk
);
224 result
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
225 (lv1_repository_string("bus") >> 32) | bus_index
,
226 lv1_repository_string("dev") | dev_index
,
227 lv1_repository_string("reg") | i
,
228 lv1_repository_string("data"), &paddr
, &len
);
230 result
= lv1_map_device_mmio_region(dinfo
->bus
, dinfo
->dev
,
231 paddr
, len
, 12 /* log_2(4 KB) */, &paddr
);
234 printf("Mapping registers failed for device "
235 "%d.%d (%ld.%ld): %d\n", dinfo
->bus
, dinfo
->dev
,
236 dinfo
->bustype
, dinfo
->devtype
, result
);
240 rman_manage_region(rm
, paddr
, paddr
+ len
- 1);
241 resource_list_add(&dinfo
->resources
, SYS_RES_MEMORY
, i
,
242 paddr
, paddr
+ len
, len
);
247 ps3bus_resources_init_by_type(struct rman
*rm
, int bus_index
, int dev_index
,
248 uint64_t irq_type
, uint64_t reg_type
, struct ps3bus_devinfo
*dinfo
)
250 uint64_t _irq_type
, irq
, outlet
;
251 uint64_t _reg_type
, paddr
, len
;
256 resource_list_init(&dinfo
->resources
);
258 lv1_get_logical_ppe_id(&ppe
);
259 thread
= 32 - fls(mfctrl());
261 /* Scan for interrupts */
262 for (i
= 0; i
< 10; i
++) {
263 result
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
264 (lv1_repository_string("bus") >> 32) | bus_index
,
265 lv1_repository_string("dev") | dev_index
,
266 lv1_repository_string("intr") | i
, 0, &_irq_type
, &irq
);
271 if (_irq_type
!= irq_type
)
274 lv1_construct_io_irq_outlet(irq
, &outlet
);
275 lv1_connect_irq_plug_ext(ppe
, thread
, outlet
, outlet
,
277 resource_list_add(&dinfo
->resources
, SYS_RES_IRQ
, i
,
281 /* Scan for registers */
282 for (i
= 0; i
< 10; i
++) {
283 result
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
284 (lv1_repository_string("bus") >> 32) | bus_index
,
285 lv1_repository_string("dev") | dev_index
,
286 lv1_repository_string("reg") | i
,
287 lv1_repository_string("type"), &_reg_type
, &junk
);
292 if (_reg_type
!= reg_type
)
295 result
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
296 (lv1_repository_string("bus") >> 32) | bus_index
,
297 lv1_repository_string("dev") | dev_index
,
298 lv1_repository_string("reg") | i
,
299 lv1_repository_string("data"), &paddr
, &len
);
301 result
= lv1_map_device_mmio_region(dinfo
->bus
, dinfo
->dev
,
302 paddr
, len
, 12 /* log_2(4 KB) */, &paddr
);
305 printf("Mapping registers failed for device "
306 "%d.%d (%ld.%ld): %d\n", dinfo
->bus
, dinfo
->dev
,
307 dinfo
->bustype
, dinfo
->devtype
, result
);
311 rman_manage_region(rm
, paddr
, paddr
+ len
- 1);
312 resource_list_add(&dinfo
->resources
, SYS_RES_MEMORY
, i
,
313 paddr
, paddr
+ len
, len
);
318 ps3bus_attach(device_t self
)
320 struct ps3bus_softc
*sc
;
321 struct ps3bus_devinfo
*dinfo
;
322 int bus_index
, dev_index
, result
;
323 uint64_t bustype
, bus
, devs
;
324 uint64_t dev
, devtype
;
328 sc
= device_get_softc(self
);
329 sc
->sc_mem_rman
.rm_type
= RMAN_ARRAY
;
330 sc
->sc_mem_rman
.rm_descr
= "PS3Bus Memory Mapped I/O";
331 sc
->sc_intr_rman
.rm_type
= RMAN_ARRAY
;
332 sc
->sc_intr_rman
.rm_descr
= "PS3Bus Interrupts";
333 rman_init(&sc
->sc_mem_rman
);
334 rman_init(&sc
->sc_intr_rman
);
335 rman_manage_region(&sc
->sc_intr_rman
, 0, ~0);
337 /* Get memory regions for DMA */
338 mem_regions(&sc
->regions
, &sc
->rcount
, &sc
->regions
, &sc
->rcount
);
341 * Probe all the PS3's buses.
344 for (bus_index
= 0; bus_index
< 5; bus_index
++) {
345 result
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
346 (lv1_repository_string("bus") >> 32) | bus_index
,
347 lv1_repository_string("type"), 0, 0, &bustype
, &junk
);
352 result
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
353 (lv1_repository_string("bus") >> 32) | bus_index
,
354 lv1_repository_string("id"), 0, 0, &bus
, &junk
);
359 result
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
360 (lv1_repository_string("bus") >> 32) | bus_index
,
361 lv1_repository_string("num_dev"), 0, 0, &devs
, &junk
);
363 for (dev_index
= 0; dev_index
< devs
; dev_index
++) {
364 result
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
365 (lv1_repository_string("bus") >> 32) | bus_index
,
366 lv1_repository_string("dev") | dev_index
,
367 lv1_repository_string("type"), 0, &devtype
, &junk
);
372 result
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
373 (lv1_repository_string("bus") >> 32) | bus_index
,
374 lv1_repository_string("dev") | dev_index
,
375 lv1_repository_string("id"), 0, &dev
, &junk
);
381 case PS3_DEVTYPE_USB
:
382 /* USB device has OHCI and EHCI USB host controllers */
384 lv1_open_device(bus
, dev
, 0);
386 /* OHCI host controller */
388 dinfo
= malloc(sizeof(*dinfo
), M_PS3BUS
,
393 dinfo
->bustype
= bustype
;
394 dinfo
->devtype
= devtype
;
395 dinfo
->busidx
= bus_index
;
396 dinfo
->devidx
= dev_index
;
398 ps3bus_resources_init_by_type(&sc
->sc_mem_rman
, bus_index
,
399 dev_index
, OHCI_IRQ
, OHCI_REG
, dinfo
);
401 cdev
= device_add_child(self
, "ohci", -1);
404 "device_add_child failed\n");
405 free(dinfo
, M_PS3BUS
);
409 mtx_init(&dinfo
->iommu_mtx
, "iommu", NULL
, MTX_DEF
);
410 device_set_ivars(cdev
, dinfo
);
412 /* EHCI host controller */
414 dinfo
= malloc(sizeof(*dinfo
), M_PS3BUS
,
419 dinfo
->bustype
= bustype
;
420 dinfo
->devtype
= devtype
;
421 dinfo
->busidx
= bus_index
;
422 dinfo
->devidx
= dev_index
;
424 ps3bus_resources_init_by_type(&sc
->sc_mem_rman
, bus_index
,
425 dev_index
, EHCI_IRQ
, EHCI_REG
, dinfo
);
427 cdev
= device_add_child(self
, "ehci", -1);
430 "device_add_child failed\n");
431 free(dinfo
, M_PS3BUS
);
435 mtx_init(&dinfo
->iommu_mtx
, "iommu", NULL
, MTX_DEF
);
436 device_set_ivars(cdev
, dinfo
);
439 dinfo
= malloc(sizeof(*dinfo
), M_PS3BUS
,
444 dinfo
->bustype
= bustype
;
445 dinfo
->devtype
= devtype
;
446 dinfo
->busidx
= bus_index
;
447 dinfo
->devidx
= dev_index
;
449 if (dinfo
->bustype
== PS3_BUSTYPE_SYSBUS
||
450 dinfo
->bustype
== PS3_BUSTYPE_STORAGE
)
451 lv1_open_device(bus
, dev
, 0);
453 ps3bus_resources_init(&sc
->sc_mem_rman
, bus_index
,
456 cdev
= device_add_child(self
, NULL
, -1);
459 "device_add_child failed\n");
460 free(dinfo
, M_PS3BUS
);
464 mtx_init(&dinfo
->iommu_mtx
, "iommu", NULL
, MTX_DEF
);
465 device_set_ivars(cdev
, dinfo
);
470 clock_register(self
, 1000);
472 return (bus_generic_attach(self
));
476 ps3bus_print_child(device_t dev
, device_t child
)
478 struct ps3bus_devinfo
*dinfo
= device_get_ivars(child
);
481 retval
+= bus_print_child_header(dev
, child
);
482 retval
+= resource_list_print_type(&dinfo
->resources
, "mem",
483 SYS_RES_MEMORY
, "%#jx");
484 retval
+= resource_list_print_type(&dinfo
->resources
, "irq",
487 retval
+= bus_print_child_footer(dev
, child
);
493 ps3bus_read_ivar(device_t bus
, device_t child
, int which
, uintptr_t *result
)
495 struct ps3bus_devinfo
*dinfo
= device_get_ivars(child
);
498 case PS3BUS_IVAR_BUS
:
499 *result
= dinfo
->bus
;
501 case PS3BUS_IVAR_DEVICE
:
502 *result
= dinfo
->dev
;
504 case PS3BUS_IVAR_BUSTYPE
:
505 *result
= dinfo
->bustype
;
507 case PS3BUS_IVAR_DEVTYPE
:
508 *result
= dinfo
->devtype
;
510 case PS3BUS_IVAR_BUSIDX
:
511 *result
= dinfo
->busidx
;
513 case PS3BUS_IVAR_DEVIDX
:
514 *result
= dinfo
->devidx
;
523 static struct resource
*
524 ps3bus_alloc_resource(device_t bus
, device_t child
, int type
, int *rid
,
525 rman_res_t start
, rman_res_t end
, rman_res_t count
, u_int flags
)
527 struct ps3bus_devinfo
*dinfo
;
528 struct ps3bus_softc
*sc
;
532 rman_res_t adjstart
, adjend
, adjcount
;
533 struct resource_list_entry
*rle
;
535 sc
= device_get_softc(bus
);
536 dinfo
= device_get_ivars(child
);
537 needactivate
= flags
& RF_ACTIVE
;
542 rle
= resource_list_find(&dinfo
->resources
, SYS_RES_MEMORY
,
545 device_printf(bus
, "no rle for %s memory %d\n",
546 device_get_nameunit(child
), *rid
);
550 if (start
< rle
->start
)
551 adjstart
= rle
->start
;
552 else if (start
> rle
->end
)
557 if (end
< rle
->start
)
559 else if (end
> rle
->end
)
564 adjcount
= adjend
- adjstart
;
566 rm
= &sc
->sc_mem_rman
;
569 rle
= resource_list_find(&dinfo
->resources
, SYS_RES_IRQ
,
571 rm
= &sc
->sc_intr_rman
;
572 adjstart
= rle
->start
;
573 adjcount
= ulmax(count
, rle
->count
);
574 adjend
= ulmax(rle
->end
, rle
->start
+ adjcount
- 1);
577 device_printf(bus
, "unknown resource request from %s\n",
578 device_get_nameunit(child
));
582 rv
= rman_reserve_resource(rm
, adjstart
, adjend
, adjcount
, flags
,
586 "failed to reserve resource %#lx - %#lx (%#lx)"
587 " for %s\n", adjstart
, adjend
, adjcount
,
588 device_get_nameunit(child
));
592 rman_set_rid(rv
, *rid
);
595 if (bus_activate_resource(child
, type
, *rid
, rv
) != 0) {
597 "failed to activate resource for %s\n",
598 device_get_nameunit(child
));
599 rman_release_resource(rv
);
608 ps3bus_activate_resource(device_t bus
, device_t child
, int type
, int rid
,
609 struct resource
*res
)
613 if (type
== SYS_RES_IRQ
)
614 return (bus_activate_resource(bus
, type
, rid
, res
));
616 if (type
== SYS_RES_MEMORY
) {
619 start
= (vm_offset_t
) rman_get_start(res
);
622 printf("ps3 mapdev: start %zx, len %ld\n", start
,
625 p
= pmap_mapdev(start
, (vm_size_t
) rman_get_size(res
));
628 rman_set_virtual(res
, p
);
629 rman_set_bustag(res
, &bs_be_tag
);
630 rman_set_bushandle(res
, (rman_res_t
)p
);
633 return (rman_activate_resource(res
));
637 ps3bus_get_dma_tag(device_t dev
, device_t child
)
639 struct ps3bus_devinfo
*dinfo
= device_get_ivars(child
);
640 struct ps3bus_softc
*sc
= device_get_softc(dev
);
641 int i
, err
, flags
, pagesize
;
643 if (dinfo
->bustype
!= PS3_BUSTYPE_SYSBUS
&&
644 dinfo
->bustype
!= PS3_BUSTYPE_STORAGE
)
645 return (bus_get_dma_tag(dev
));
647 mtx_lock(&dinfo
->iommu_mtx
);
648 if (dinfo
->dma_tag
!= NULL
) {
649 mtx_unlock(&dinfo
->iommu_mtx
);
650 return (dinfo
->dma_tag
);
653 flags
= 0; /* 32-bit mode */
654 if (dinfo
->bustype
== PS3_BUSTYPE_SYSBUS
&&
655 dinfo
->devtype
== PS3_DEVTYPE_USB
)
656 flags
= 2; /* 8-bit mode */
658 pagesize
= 24; /* log_2(16 MB) */
659 if (dinfo
->bustype
== PS3_BUSTYPE_STORAGE
)
660 pagesize
= 12; /* 4 KB */
662 for (i
= 0; i
< sc
->rcount
; i
++) {
663 err
= lv1_allocate_device_dma_region(dinfo
->bus
, dinfo
->dev
,
664 sc
->regions
[i
].mr_size
, pagesize
, flags
,
665 &dinfo
->dma_base
[i
]);
668 "could not allocate DMA region %d: %d\n", i
, err
);
672 err
= lv1_map_device_dma_region(dinfo
->bus
, dinfo
->dev
,
673 sc
->regions
[i
].mr_start
, dinfo
->dma_base
[i
],
674 sc
->regions
[i
].mr_size
,
675 0xf800000000000800UL
/* Cell Handbook Figure 7.3.4.1 */);
678 "could not map DMA region %d: %d\n", i
, err
);
683 err
= bus_dma_tag_create(bus_get_dma_tag(dev
),
684 1, 0, BUS_SPACE_MAXADDR
, BUS_SPACE_MAXADDR
,
685 NULL
, NULL
, BUS_SPACE_MAXSIZE
, 0, BUS_SPACE_MAXSIZE
,
686 0, NULL
, NULL
, &dinfo
->dma_tag
);
689 * Note: storage devices have IOMMU mappings set up by the hypervisor,
690 * but use physical, non-translated addresses. The above IOMMU
691 * initialization is necessary for the hypervisor to be able to set up
692 * the mappings, but actual DMA mappings should not use the IOMMU
695 if (dinfo
->bustype
!= PS3_BUSTYPE_STORAGE
)
696 bus_dma_tag_set_iommu(dinfo
->dma_tag
, dev
, dinfo
);
699 mtx_unlock(&dinfo
->iommu_mtx
);
704 return (dinfo
->dma_tag
);
708 ps3_iommu_map(device_t dev
, bus_dma_segment_t
*segs
, int *nsegs
,
709 bus_addr_t min
, bus_addr_t max
, bus_size_t alignment
, bus_addr_t boundary
,
712 struct ps3bus_devinfo
*dinfo
= cookie
;
713 struct ps3bus_softc
*sc
= device_get_softc(dev
);
716 for (i
= 0; i
< *nsegs
; i
++) {
717 for (j
= 0; j
< sc
->rcount
; j
++) {
718 if (segs
[i
].ds_addr
>= sc
->regions
[j
].mr_start
&&
719 segs
[i
].ds_addr
< sc
->regions
[j
].mr_start
+
720 sc
->regions
[j
].mr_size
)
723 KASSERT(j
< sc
->rcount
,
724 ("Trying to map address %#lx not in physical memory",
727 segs
[i
].ds_addr
= dinfo
->dma_base
[j
] +
728 (segs
[i
].ds_addr
- sc
->regions
[j
].mr_start
);
735 ps3_iommu_unmap(device_t dev
, bus_dma_segment_t
*segs
, int nsegs
, void *cookie
)
741 #define Y2K 946684800
744 ps3_gettime(device_t dev
, struct timespec
*ts
)
749 result
= lv1_get_rtc(&rtc
, &tb
);
753 ts
->tv_sec
= rtc
+ Y2K
;
759 ps3_settime(device_t dev
, struct timespec
*ts
)