xref: /haiku/src/libs/compat/freebsd_network/bus.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
1 /*
2  * Copyright 2007, Hugo Santos. All Rights Reserved.
3  * Copyright 2004, Marcus Overhagen. All Rights Reserved.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 extern "C" {
9 #include "device.h"
10 }
11 
12 #include <stdlib.h>
13 
14 #include <algorithm>
15 
16 #include <arch/cpu.h>
17 
18 extern "C" {
19 #include <compat/dev/pci/pcireg.h>
20 #include <compat/dev/pci/pcivar.h>
21 #include <compat/machine/resource.h>
22 #include <compat/sys/mutex.h>
23 #include <compat/machine/bus.h>
24 #include <compat/sys/rman.h>
25 #include <compat/sys/bus.h>
26 }
27 
28 // private kernel header to get B_NO_HANDLED_INFO
29 #include <int.h>
30 
31 #include <PCI_x86.h>
32 
33 
34 //#define DEBUG_BUS_SPACE_RW
35 #ifdef DEBUG_BUS_SPACE_RW
36 #	define TRACE_BUS_SPACE_RW(x) driver_printf x
37 #else
38 #	define TRACE_BUS_SPACE_RW(x)
39 #endif
40 
41 //#define DEBUG_PCI
42 #ifdef DEBUG_PCI
43 #	define TRACE_PCI(dev, format, args...) device_printf(dev, format , ##args)
44 #else
45 #	define TRACE_PCI(dev, format, args...) do { } while (0)
46 #endif
47 
48 
49 struct internal_intr {
50 	device_t		dev;
51 	driver_filter_t* filter;
52 	driver_intr_t	*handler;
53 	void			*arg;
54 	int				irq;
55 	uint32			flags;
56 
57 	thread_id		thread;
58 	sem_id			sem;
59 	int32			handling;
60 };
61 
62 static int32 intr_wrapper(void *data);
63 
64 
65 static int
66 fls(int mask)
67 {
68 	int bit;
69 	if (mask == 0)
70 		return (0);
71 	for (bit = 1; mask != 1; bit++)
72 		mask = (unsigned int)mask >> 1;
73 	return (bit);
74 }
75 
76 
77 static area_id
78 map_mem(void **virtualAddr, phys_addr_t _phy, size_t size, uint32 protection,
79 	const char *name)
80 {
81 	uint32 offset = _phy & (B_PAGE_SIZE - 1);
82 	phys_addr_t physicalAddr = _phy - offset;
83 	area_id area;
84 
85 	size = roundup(size + offset, B_PAGE_SIZE);
86 	area = map_physical_memory(name, physicalAddr, size, B_ANY_KERNEL_ADDRESS,
87 		protection, virtualAddr);
88 	if (area < B_OK)
89 		return area;
90 
91 	*virtualAddr = (uint8 *)(*virtualAddr) + offset;
92 
93 	return area;
94 }
95 
96 
97 static int
98 bus_alloc_irq_resource(device_t dev, struct resource *res)
99 {
100 	uint8 irq = pci_read_config(dev, PCI_interrupt_line, 1);
101 	if (irq == 0 || irq == 0xff)
102 		return -1;
103 
104 	/* TODO: IRQ resources! */
105 	res->r_bustag = 0;
106 	res->r_bushandle = irq;
107 
108 	return 0;
109 }
110 
111 
112 static int
113 bus_alloc_mem_resource(device_t dev, struct resource *res, int regid)
114 {
115 	pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info;
116 
117 	// check the offset really is of a BAR
118 	if (regid < PCI_base_registers || (regid % sizeof(uint32) != 0)
119 		|| (regid >= PCI_base_registers + 6 * (int)sizeof(uint32)))
120 		return -1;
121 
122 	// turn offset into array index
123 	regid -= PCI_base_registers;
124 	regid /= sizeof(uint32);
125 
126 	uint32 addr = info->u.h0.base_registers[regid];
127 	uint32 size = info->u.h0.base_register_sizes[regid];
128 	uchar flags = info->u.h0.base_register_flags[regid];
129 
130 	// reject empty regions
131 	if (size == 0)
132 		return -1;
133 
134 	// reject I/O space
135 	if (flags & PCI_address_space)
136 		return -1;
137 
138 	// TODO: check flags & PCI_address_prefetchable ?
139 
140 	void *virtualAddr;
141 
142 	res->r_mapped_area = map_mem(&virtualAddr, addr, size, 0,
143 		"bus_alloc_resource(MEMORY)");
144 	if (res->r_mapped_area < B_OK)
145 		return -1;
146 
147 	res->r_bustag = X86_BUS_SPACE_MEM;
148 	res->r_bushandle = (bus_space_handle_t)virtualAddr;
149 	return 0;
150 }
151 
152 
153 static int
154 bus_alloc_ioport_resource(device_t dev, struct resource *res, int regid)
155 {
156 	res->r_bustag = X86_BUS_SPACE_IO;
157 	res->r_bushandle = pci_read_config(dev, regid, 4) & PCI_address_io_mask;
158 	return 0;
159 }
160 
161 
162 struct resource *
163 bus_alloc_resource(device_t dev, int type, int *rid, unsigned long start,
164 	unsigned long end, unsigned long count, uint32 flags)
165 {
166 	struct resource *res;
167 	int result = -1;
168 
169 	if (type != SYS_RES_IRQ && type != SYS_RES_MEMORY
170 		&& type != SYS_RES_IOPORT)
171 		return NULL;
172 
173 	device_printf(dev, "bus_alloc_resource(%i, [%i], 0x%lx, 0x%lx, 0x%lx,"
174 		"0x%" B_PRIx32 ")\n", type, *rid, start, end, count, flags);
175 
176 	// maybe a local array of resources is enough
177 	res = (struct resource *)malloc(sizeof(struct resource));
178 	if (res == NULL)
179 		return NULL;
180 
181 	if (type == SYS_RES_IRQ) {
182 		if (*rid == 0) {
183 			// pinned interrupt
184 			result = bus_alloc_irq_resource(dev, res);
185 		} else {
186 			// msi or msi-x interrupt at index *rid - 1
187 			pci_info *info;
188 			info = &((struct root_device_softc *)dev->root->softc)->pci_info;
189 			res->r_bustag = 1;
190 			res->r_bushandle = info->u.h0.interrupt_line + *rid - 1;
191 			result = 0;
192 		}
193 	} else if (type == SYS_RES_MEMORY)
194 		result = bus_alloc_mem_resource(dev, res, *rid);
195 	else if (type == SYS_RES_IOPORT)
196 		result = bus_alloc_ioport_resource(dev, res, *rid);
197 
198 	if (result < 0) {
199 		free(res);
200 		return NULL;
201 	}
202 
203 	res->r_type = type;
204 	return res;
205 }
206 
207 
208 int
209 bus_release_resource(device_t dev, int type, int rid, struct resource *res)
210 {
211 	if (res->r_type != type)
212 		panic("bus_release_resource: mismatch");
213 
214 	if (type == SYS_RES_MEMORY)
215 		delete_area(res->r_mapped_area);
216 
217 	free(res);
218 	return 0;
219 }
220 
221 
222 int
223 bus_alloc_resources(device_t dev, struct resource_spec *resourceSpec,
224 	struct resource **resources)
225 {
226 	int i;
227 
228 	for (i = 0; resourceSpec[i].type != -1; i++) {
229 		resources[i] = bus_alloc_resource_any(dev,
230 			resourceSpec[i].type, &resourceSpec[i].rid, resourceSpec[i].flags);
231 		if (resources[i] == NULL
232 			&& (resourceSpec[i].flags & RF_OPTIONAL) == 0) {
233 			for (++i; resourceSpec[i].type != -1; i++) {
234 				resources[i] = NULL;
235 			}
236 
237 			bus_release_resources(dev, resourceSpec, resources);
238 			return ENXIO;
239 		}
240 	}
241 	return 0;
242 }
243 
244 
245 void
246 bus_release_resources(device_t dev, const struct resource_spec *resourceSpec,
247 	struct resource **resources)
248 {
249 	int i;
250 
251 	for (i = 0; resourceSpec[i].type != -1; i++) {
252 		if (resources[i] == NULL)
253 			continue;
254 
255 		bus_release_resource(dev, resourceSpec[i].type, resourceSpec[i].rid,
256 			resources[i]);
257 		resources[i] = NULL;
258 	}
259 }
260 
261 
262 bus_space_handle_t
263 rman_get_bushandle(struct resource *res)
264 {
265 	return res->r_bushandle;
266 }
267 
268 
269 bus_space_tag_t
270 rman_get_bustag(struct resource *res)
271 {
272 	return res->r_bustag;
273 }
274 
275 
276 int
277 rman_get_rid(struct resource *res)
278 {
279 	return 0;
280 }
281 
282 
283 void*
284 rman_get_virtual(struct resource *res)
285 {
286 	return NULL;
287 }
288 
289 
290 //	#pragma mark - Interrupt handling
291 
292 
293 static int32
294 intr_wrapper(void *data)
295 {
296 	struct internal_intr *intr = (struct internal_intr *)data;
297 
298 	//device_printf(intr->dev, "in interrupt handler.\n");
299 
300 	if (!HAIKU_CHECK_DISABLE_INTERRUPTS(intr->dev))
301 		return B_UNHANDLED_INTERRUPT;
302 
303 	release_sem_etc(intr->sem, 1, B_DO_NOT_RESCHEDULE);
304 	return intr->handling ? B_HANDLED_INTERRUPT : B_INVOKE_SCHEDULER;
305 }
306 
307 
308 static int32
309 intr_handler(void *data)
310 {
311 	struct internal_intr *intr = (struct internal_intr *)data;
312 	status_t status;
313 
314 	while (1) {
315 		status = acquire_sem(intr->sem);
316 		if (status < B_OK)
317 			break;
318 
319 		//device_printf(intr->dev, "in soft interrupt handler.\n");
320 
321 		atomic_or(&intr->handling, 1);
322 		intr->handler(intr->arg);
323 		atomic_and(&intr->handling, 0);
324 		HAIKU_REENABLE_INTERRUPTS(intr->dev);
325 	}
326 
327 	return 0;
328 }
329 
330 
331 static void
332 free_internal_intr(struct internal_intr *intr)
333 {
334 	if (intr->sem >= B_OK) {
335 		status_t status;
336 		delete_sem(intr->sem);
337 		wait_for_thread(intr->thread, &status);
338 	}
339 
340 	free(intr);
341 }
342 
343 
344 int
345 bus_setup_intr(device_t dev, struct resource *res, int flags,
346 	driver_filter_t* filter, driver_intr_t handler, void *arg, void **_cookie)
347 {
348 	/* TODO check MPSAFE etc */
349 
350 	struct internal_intr *intr = (struct internal_intr *)malloc(
351 		sizeof(struct internal_intr));
352 	char semName[64];
353 	status_t status;
354 
355 	if (intr == NULL)
356 		return B_NO_MEMORY;
357 
358 	intr->dev = dev;
359 	intr->filter = filter;
360 	intr->handler = handler;
361 	intr->arg = arg;
362 	intr->irq = res->r_bushandle;
363 	intr->flags = flags;
364 	intr->sem = -1;
365 	intr->thread = -1;
366 
367 	if (filter != NULL) {
368 		status = install_io_interrupt_handler(intr->irq,
369 			(interrupt_handler)intr->filter, intr->arg, 0);
370 	} else {
371 		snprintf(semName, sizeof(semName), "%s intr", dev->device_name);
372 
373 		intr->sem = create_sem(0, semName);
374 		if (intr->sem < B_OK) {
375 			free(intr);
376 			return B_NO_MEMORY;
377 		}
378 
379 		snprintf(semName, sizeof(semName), "%s intr handler", dev->device_name);
380 
381 		intr->thread = spawn_kernel_thread(intr_handler, semName,
382 			B_REAL_TIME_DISPLAY_PRIORITY, intr);
383 		if (intr->thread < B_OK) {
384 			delete_sem(intr->sem);
385 			free(intr);
386 			return B_NO_MEMORY;
387 		}
388 
389 		status = install_io_interrupt_handler(intr->irq,
390 			intr_wrapper, intr, 0);
391 	}
392 
393 	if (status == B_OK && res->r_bustag == 1 && gPCIx86 != NULL) {
394 		// this is an msi, enable it
395 		pci_info *info
396 			= &((struct root_device_softc *)dev->root->softc)->pci_info;
397 		if (((struct root_device_softc *)dev->root->softc)->is_msi) {
398 			if (gPCIx86->enable_msi(info->bus, info->device,
399 					info->function) != B_OK) {
400 				device_printf(dev, "enabling msi failed\n");
401 				bus_teardown_intr(dev, res, intr);
402 				return ENODEV;
403 			}
404 		} else if (((struct root_device_softc *)dev->root->softc)->is_msix) {
405 			if (gPCIx86->enable_msix(info->bus, info->device,
406 					info->function) != B_OK) {
407 				device_printf(dev, "enabling msix failed\n");
408 				bus_teardown_intr(dev, res, intr);
409 				return ENODEV;
410 			}
411 		}
412 	}
413 
414 	if (status < B_OK) {
415 		free_internal_intr(intr);
416 		return status;
417 	}
418 
419 	resume_thread(intr->thread);
420 
421 	*_cookie = intr;
422 	return 0;
423 }
424 
425 
426 int
427 bus_teardown_intr(device_t dev, struct resource *res, void *arg)
428 {
429 	struct internal_intr *intr = (struct internal_intr *)arg;
430 	if (intr == NULL)
431 		return -1;
432 
433 	struct root_device_softc *root = (struct root_device_softc *)dev->root->softc;
434 
435 	if ((root->is_msi || root->is_msix) && gPCIx86 != NULL) {
436 		// disable msi generation
437 		pci_info *info = &root->pci_info;
438 		gPCIx86->disable_msi(info->bus, info->device, info->function);
439 	}
440 
441 	if (intr->filter != NULL) {
442 		remove_io_interrupt_handler(intr->irq, (interrupt_handler)intr->filter,
443 			intr->arg);
444 	} else {
445 		remove_io_interrupt_handler(intr->irq, intr_wrapper, intr);
446 	}
447 
448 	free_internal_intr(intr);
449 	return 0;
450 }
451 
452 
453 int
454 bus_bind_intr(device_t dev, struct resource *res, int cpu)
455 {
456 	if (dev->parent == NULL)
457 		return EINVAL;
458 
459 	// TODO
460 	return 0;
461 }
462 
463 
464 int bus_describe_intr(device_t dev, struct resource *irq, void *cookie,
465 	const char* fmt, ...)
466 {
467 	if (dev->parent == NULL)
468 		return EINVAL;
469 
470 	// we don't really support names for interrupts
471 	return 0;
472 }
473 
474 
475 //	#pragma mark - bus functions
476 
477 
478 bus_dma_tag_t
479 bus_get_dma_tag(device_t dev)
480 {
481 	return NULL;
482 }
483 
484 
485 int
486 bus_generic_suspend(device_t dev)
487 {
488 	UNIMPLEMENTED();
489 	return B_ERROR;
490 }
491 
492 
493 int
494 bus_generic_resume(device_t dev)
495 {
496 	UNIMPLEMENTED();
497 	return B_ERROR;
498 }
499 
500 
501 void
502 bus_generic_shutdown(device_t dev)
503 {
504 	UNIMPLEMENTED();
505 }
506 
507 
508 int
509 bus_print_child_header(device_t dev, device_t child)
510 {
511 	UNIMPLEMENTED();
512 	return B_ERROR;
513 }
514 
515 
516 int
517 bus_print_child_footer(device_t dev, device_t child)
518 {
519 	UNIMPLEMENTED();
520 	return B_ERROR;
521 }
522 
523 
524 int
525 bus_generic_print_child(device_t dev, device_t child)
526 {
527 	UNIMPLEMENTED();
528 	return B_ERROR;
529 }
530 
531 
532 void
533 bus_generic_driver_added(device_t dev, driver_t *driver)
534 {
535 	UNIMPLEMENTED();
536 }
537 
538 
539 int
540 bus_child_present(device_t child)
541 {
542 	device_t parent = device_get_parent(child);
543 	if (parent == NULL)
544 		return 0;
545 
546 	return bus_child_present(parent);
547 }
548 
549 
550 void
551 bus_enumerate_hinted_children(device_t bus)
552 {
553 #if 0
554 	UNIMPLEMENTED();
555 #endif
556 }
557 
558 
559 
560 //	#pragma mark - PCI functions
561 
562 
563 uint32_t
564 pci_read_config(device_t dev, int offset, int size)
565 {
566 	pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info;
567 
568 	uint32_t value = gPci->read_pci_config(info->bus, info->device,
569 		info->function, offset, size);
570 	TRACE_PCI(dev, "pci_read_config(%i, %i) = 0x%x\n", offset, size, value);
571 	return value;
572 }
573 
574 
575 void
576 pci_write_config(device_t dev, int offset, uint32_t value, int size)
577 {
578 	pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info;
579 
580 	TRACE_PCI(dev, "pci_write_config(%i, 0x%x, %i)\n", offset, value, size);
581 
582 	gPci->write_pci_config(info->bus, info->device, info->function, offset,
583 		size, value);
584 }
585 
586 
587 uint16_t
588 pci_get_vendor(device_t dev)
589 {
590 	return pci_read_config(dev, PCI_vendor_id, 2);
591 }
592 
593 
594 uint16_t
595 pci_get_device(device_t dev)
596 {
597 	return pci_read_config(dev, PCI_device_id, 2);
598 }
599 
600 
601 uint16_t
602 pci_get_subvendor(device_t dev)
603 {
604 	return pci_read_config(dev, PCI_subsystem_vendor_id, 2);
605 }
606 
607 
608 uint16_t
609 pci_get_subdevice(device_t dev)
610 {
611 	return pci_read_config(dev, PCI_subsystem_id, 2);
612 }
613 
614 
615 uint8_t
616 pci_get_revid(device_t dev)
617 {
618 	return pci_read_config(dev, PCI_revision, 1);
619 }
620 
621 
622 uint32_t
623 pci_get_domain(device_t dev)
624 {
625 	return 0;
626 }
627 
628 uint32_t
629 pci_get_devid(device_t dev)
630 {
631 	return pci_read_config(dev, PCI_device_id, 2) << 16 |
632 		pci_read_config(dev, PCI_vendor_id, 2);
633 }
634 
635 uint8_t
636 pci_get_cachelnsz(device_t dev)
637 {
638 	return pci_read_config(dev, PCI_line_size, 1);
639 }
640 
641 uint8_t *
642 pci_get_ether(device_t dev)
643 {
644 	/* used in if_dc to get the MAC from CardBus CIS for Xircom card */
645 	return NULL; /* NULL is handled in the caller correctly */
646 }
647 
648 uint8_t
649 pci_get_bus(device_t dev)
650 {
651 	pci_info *info
652 		= &((struct root_device_softc *)dev->root->softc)->pci_info;
653 	return info->bus;
654 }
655 
656 
657 uint8_t
658 pci_get_slot(device_t dev)
659 {
660 	pci_info *info
661 		= &((struct root_device_softc *)dev->root->softc)->pci_info;
662 	return info->device;
663 }
664 
665 
666 uint8_t
667 pci_get_function(device_t dev)
668 {
669 	pci_info *info
670 		= &((struct root_device_softc *)dev->root->softc)->pci_info;
671 	return info->function;
672 }
673 
674 
675 device_t
676 pci_find_dbsf(uint32_t domain, uint8_t bus, uint8_t slot, uint8_t func)
677 {
678 	// We don't support that yet - if we want to support the multi port
679 	// feature of the Broadcom BCM 570x driver, we would have to change
680 	// that.
681 	return NULL;
682 }
683 
684 
685 static void
686 pci_set_command_bit(device_t dev, uint16_t bit)
687 {
688 	uint16_t command = pci_read_config(dev, PCI_command, 2);
689 	pci_write_config(dev, PCI_command, command | bit, 2);
690 }
691 
692 
693 int
694 pci_enable_busmaster(device_t dev)
695 {
696 	pci_set_command_bit(dev, PCI_command_master);
697 	return 0;
698 }
699 
700 
701 int
702 pci_enable_io(device_t dev, int space)
703 {
704 	/* adapted from FreeBSD's pci_enable_io_method */
705 	int bit = 0;
706 
707 	switch (space) {
708 		case SYS_RES_IOPORT:
709 			bit = PCI_command_io;
710 			break;
711 		case SYS_RES_MEMORY:
712 			bit = PCI_command_memory;
713 			break;
714 		default:
715 			return EINVAL;
716 	}
717 
718 	pci_set_command_bit(dev, bit);
719 	if (pci_read_config(dev, PCI_command, 2) & bit)
720 		return 0;
721 
722 	device_printf(dev, "pci_enable_io(%d) failed.\n", space);
723 
724 	return ENXIO;
725 }
726 
727 
728 int
729 pci_find_cap(device_t dev, int capability, int *capreg)
730 {
731 	return pci_find_extcap(dev, capability, capreg);
732 }
733 
734 
735 int
736 pci_find_extcap(device_t child, int capability, int *_capabilityRegister)
737 {
738 	uint8 capabilityPointer;
739 	uint8 headerType;
740 	uint16 status;
741 
742 	status = pci_read_config(child, PCIR_STATUS, 2);
743 	if ((status & PCIM_STATUS_CAPPRESENT) == 0)
744 		return ENXIO;
745 
746 	headerType = pci_read_config(child, PCI_header_type, 1);
747 	switch (headerType & PCIM_HDRTYPE) {
748 		case 0:
749 		case 1:
750 			capabilityPointer = PCIR_CAP_PTR;
751 			break;
752 		case 2:
753 			capabilityPointer = PCIR_CAP_PTR_2;
754 			break;
755 		default:
756 			return ENXIO;
757 	}
758 	capabilityPointer = pci_read_config(child, capabilityPointer, 1);
759 
760 	while (capabilityPointer != 0) {
761 		if (pci_read_config(child, capabilityPointer + PCICAP_ID, 1)
762 				== capability) {
763 			if (_capabilityRegister != NULL)
764 				*_capabilityRegister = capabilityPointer;
765 			return 0;
766 		}
767 		capabilityPointer = pci_read_config(child,
768 			capabilityPointer + PCICAP_NEXTPTR, 1);
769 	}
770 
771 	return ENOENT;
772 }
773 
774 
775 int
776 pci_msi_count(device_t dev)
777 {
778 	pci_info *info;
779 	if (gPCIx86 == NULL)
780 		return 0;
781 
782 	info = &((struct root_device_softc *)dev->root->softc)->pci_info;
783 	return gPCIx86->get_msi_count(info->bus, info->device, info->function);
784 }
785 
786 
787 int
788 pci_alloc_msi(device_t dev, int *count)
789 {
790 	pci_info *info;
791 	uint8 startVector = 0;
792 	if (gPCIx86 == NULL)
793 		return ENODEV;
794 
795 	info = &((struct root_device_softc *)dev->root->softc)->pci_info;
796 
797 	if (gPCIx86->configure_msi(info->bus, info->device, info->function, *count,
798 			&startVector) != B_OK) {
799 		return ENODEV;
800 	}
801 
802 	((struct root_device_softc *)dev->root->softc)->is_msi = true;
803 	info->u.h0.interrupt_line = startVector;
804 	return EOK;
805 }
806 
807 
808 int
809 pci_release_msi(device_t dev)
810 {
811 	pci_info *info;
812 	if (gPCIx86 == NULL)
813 		return ENODEV;
814 
815 	info = &((struct root_device_softc *)dev->root->softc)->pci_info;
816 	gPCIx86->unconfigure_msi(info->bus, info->device, info->function);
817 	((struct root_device_softc *)dev->root->softc)->is_msi = false;
818 	((struct root_device_softc *)dev->root->softc)->is_msix = false;
819 	return EOK;
820 }
821 
822 
823 int
824 pci_msix_count(device_t dev)
825 {
826 	pci_info *info;
827 	if (gPCIx86 == NULL)
828 		return 0;
829 
830 	info = &((struct root_device_softc *)dev->root->softc)->pci_info;
831 	return gPCIx86->get_msix_count(info->bus, info->device, info->function);
832 }
833 
834 
835 int
836 pci_alloc_msix(device_t dev, int *count)
837 {
838 	pci_info *info;
839 	uint8 startVector = 0;
840 	if (gPCIx86 == NULL)
841 		return ENODEV;
842 
843 	info = &((struct root_device_softc *)dev->root->softc)->pci_info;
844 
845 	if (gPCIx86->configure_msix(info->bus, info->device, info->function, *count,
846 			&startVector) != B_OK) {
847 		return ENODEV;
848 	}
849 
850 	((struct root_device_softc *)dev->root->softc)->is_msix = true;
851 	info->u.h0.interrupt_line = startVector;
852 	return EOK;
853 }
854 
855 
856 int
857 pci_get_max_read_req(device_t dev)
858 {
859 	int cap;
860 	uint16_t val;
861 
862 	if (pci_find_extcap(dev, PCIY_EXPRESS, &cap) != 0)
863 		return (0);
864 	val = pci_read_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, 2);
865 	val &= PCIM_EXP_CTL_MAX_READ_REQUEST;
866 	val >>= 12;
867 	return (1 << (val + 7));
868 }
869 
870 
871 int
872 pci_set_max_read_req(device_t dev, int size)
873 {
874 	int cap;
875 	uint16_t val;
876 
877 	if (pci_find_extcap(dev, PCIY_EXPRESS, &cap) != 0)
878 		return (0);
879 	if (size < 128)
880 		size = 128;
881 	if (size > 4096)
882 		size = 4096;
883 	size = (1 << (fls(size) - 1));
884 	val = pci_read_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, 2);
885 	val &= ~PCIM_EXP_CTL_MAX_READ_REQUEST;
886 	val |= (fls(size) - 8) << 12;
887 	pci_write_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, val, 2);
888 	return (size);
889 }
890 
891 
892 int
893 pci_get_powerstate(device_t dev)
894 {
895 	int capabilityRegister;
896 	uint16 status;
897 	int powerState = PCI_POWERSTATE_D0;
898 
899 	if (pci_find_extcap(dev, PCIY_PMG, &capabilityRegister) != EOK)
900 		return powerState;
901 
902 	status = pci_read_config(dev, capabilityRegister + PCIR_POWER_STATUS, 2);
903 	switch (status & PCI_pm_mask) {
904 		case PCI_pm_state_d0:
905 			break;
906 		case PCI_pm_state_d1:
907 			powerState = PCI_POWERSTATE_D1;
908 			break;
909 		case PCI_pm_state_d2:
910 			powerState = PCI_POWERSTATE_D2;
911 			break;
912 		case PCI_pm_state_d3:
913 			powerState = PCI_POWERSTATE_D3;
914 			break;
915 		default:
916 			powerState = PCI_POWERSTATE_UNKNOWN;
917 			break;
918 	}
919 
920 	TRACE_PCI(dev, "%s: D%i\n", __func__, powerState);
921 	return powerState;
922 }
923 
924 
925 int
926 pci_set_powerstate(device_t dev, int newPowerState)
927 {
928 	int capabilityRegister;
929 	int oldPowerState;
930 	uint8 currentPowerManagementStatus;
931 	uint8 newPowerManagementStatus;
932 	uint16 powerManagementCapabilities;
933 	bigtime_t stateTransitionDelayInUs = 0;
934 
935 	if (pci_find_extcap(dev, PCIY_PMG, &capabilityRegister) != EOK)
936 		return EOPNOTSUPP;
937 
938 	oldPowerState = pci_get_powerstate(dev);
939 	if (oldPowerState == newPowerState)
940 		return EOK;
941 
942 	switch (std::max(oldPowerState, newPowerState)) {
943 		case PCI_POWERSTATE_D2:
944 			stateTransitionDelayInUs = 200;
945 			break;
946 		case PCI_POWERSTATE_D3:
947 			stateTransitionDelayInUs = 10000;
948 			break;
949 	}
950 
951 	currentPowerManagementStatus = pci_read_config(dev, capabilityRegister
952 		+ PCIR_POWER_STATUS, 2);
953 	newPowerManagementStatus = currentPowerManagementStatus & ~PCI_pm_mask;
954 	powerManagementCapabilities = pci_read_config(dev, capabilityRegister
955 		+ PCIR_POWER_CAP, 2);
956 
957 	switch (newPowerState) {
958 		case PCI_POWERSTATE_D0:
959 			newPowerManagementStatus |= PCIM_PSTAT_D0;
960 			break;
961 		case PCI_POWERSTATE_D1:
962 			if ((powerManagementCapabilities & PCI_pm_d1supp) == 0)
963 				return EOPNOTSUPP;
964 			newPowerManagementStatus |= PCIM_PSTAT_D1;
965 			break;
966 		case PCI_POWERSTATE_D2:
967 			if ((powerManagementCapabilities & PCI_pm_d2supp) == 0)
968 				return EOPNOTSUPP;
969 			newPowerManagementStatus |= PCIM_PSTAT_D2;
970 			break;
971 		case PCI_POWERSTATE_D3:
972 			newPowerManagementStatus |= PCIM_PSTAT_D3;
973 			break;
974 		default:
975 			return EINVAL;
976 	}
977 
978 	TRACE_PCI(dev, "%s: D%i -> D%i\n", __func__, oldPowerState, newPowerState);
979 	pci_write_config(dev, capabilityRegister + PCIR_POWER_STATUS, newPowerState,
980 		2);
981 	if (stateTransitionDelayInUs != 0)
982 		snooze(stateTransitionDelayInUs);
983 
984 	return EOK;
985 }
986