+ uint32_t result = 0;
+
+ uint64_t sabs, eabs;
+ boolean_t istate, timeread = FALSE;
+
+ if (__improbable(reportphyreaddelayabs != 0)) {
+ istate = ml_set_interrupts_enabled(FALSE);
+ sabs = mach_absolute_time();
+ timeread = TRUE;
+ }
+
+#if DEVELOPMENT || DEBUG
+ if (__improbable(timeread && simulate_stretched_io)) {
+ sabs -= simulate_stretched_io;
+ }
+#endif /* x86_64 DEVELOPMENT || DEBUG */
+
+ switch (size) {
+ case 1:
+ result = inb(ioport);
+ break;
+ case 2:
+ result = inw(ioport);
+ break;
+ case 4:
+ result = inl(ioport);
+ break;
+ default:
+ panic("Invalid size %d for ml_port_io_read(0x%x)", size, (unsigned)ioport);
+ break;
+ }
+
+ if (__improbable(timeread == TRUE)) {
+ eabs = mach_absolute_time();
+
+#if DEVELOPMENT || DEBUG
+ iotrace(IOTRACE_PORTIO_READ, 0, ioport, size, result, sabs, eabs - sabs);
+#endif
+
+ if (__improbable((eabs - sabs) > reportphyreaddelayabs)) {
+ (void)ml_set_interrupts_enabled(istate);
+
+ if (phyreadpanic && (machine_timeout_suspended() == FALSE)) {
+ panic_io_port_read();
+ panic("Read from IO port 0x%x took %llu ns, "
+ "result: 0x%x (start: %llu, end: %llu), ceiling: %llu",
+ ioport, (eabs - sabs), result, sabs, eabs,
+ reportphyreaddelayabs);
+ }
+
+ if (reportphyreadosbt) {
+ OSReportWithBacktrace("ml_port_io_read(0x%x) took %lluus",
+ ioport, (eabs - sabs) / NSEC_PER_USEC);
+ }
+#if CONFIG_DTRACE
+ DTRACE_PHYSLAT3(portioread, uint64_t, (eabs - sabs),
+ uint16_t, ioport, uint32_t, size);
+#endif /* CONFIG_DTRACE */
+ } else if (__improbable(tracephyreaddelayabs > 0 && (eabs - sabs) > tracephyreaddelayabs)) {
+ KDBG(MACHDBG_CODE(DBG_MACH_IO, DBC_MACH_IO_PORTIO_READ),
+ (eabs - sabs), sabs, ioport, result);
+
+ (void)ml_set_interrupts_enabled(istate);
+ } else {
+ (void)ml_set_interrupts_enabled(istate);
+ }
+ }
+
+ return result;
+}
+
+void
+ml_port_io_write(uint16_t ioport, uint32_t val, int size)
+{
+ uint64_t sabs, eabs;
+ boolean_t istate, timewrite = FALSE;
+
+ if (__improbable(reportphywritedelayabs != 0)) {
+ istate = ml_set_interrupts_enabled(FALSE);
+ sabs = mach_absolute_time();
+ timewrite = TRUE;
+ }
+#if DEVELOPMENT || DEBUG
+ if (__improbable(timewrite && simulate_stretched_io)) {
+ sabs -= simulate_stretched_io;
+ }
+#endif /* x86_64 DEVELOPMENT || DEBUG */
+
+ switch (size) {
+ case 1:
+ outb(ioport, (uint8_t)val);
+ break;
+ case 2:
+ outw(ioport, (uint16_t)val);
+ break;
+ case 4:
+ outl(ioport, (uint32_t)val);
+ break;
+ default:
+ panic("Invalid size %d for ml_port_io_write(0x%x)", size, (unsigned)ioport);
+ break;
+ }
+
+ if (__improbable(timewrite == TRUE)) {
+ eabs = mach_absolute_time();
+
+#if DEVELOPMENT || DEBUG
+ iotrace(IOTRACE_PORTIO_WRITE, 0, ioport, size, val, sabs, eabs - sabs);
+#endif
+
+ if (__improbable((eabs - sabs) > reportphywritedelayabs)) {
+ (void)ml_set_interrupts_enabled(istate);
+
+ if (phywritepanic && (machine_timeout_suspended() == FALSE)) {
+ panic_io_port_read();
+ panic("Write to IO port 0x%x took %llu ns, val: 0x%x"
+ " (start: %llu, end: %llu), ceiling: %llu",
+ ioport, (eabs - sabs), val, sabs, eabs,
+ reportphywritedelayabs);
+ }
+
+ if (reportphywriteosbt) {
+ OSReportWithBacktrace("ml_port_io_write(0x%x, %d, 0x%llx) "
+ "took %lluus",
+ ioport, size, val, (eabs - sabs) / NSEC_PER_USEC);
+ }
+
+#if CONFIG_DTRACE
+ DTRACE_PHYSLAT4(portiowrite, uint64_t, (eabs - sabs),
+ uint16_t, ioport, uint32_t, size, uint64_t, val);
+#endif /* CONFIG_DTRACE */
+ } else if (__improbable(tracephywritedelayabs > 0 && (eabs - sabs) > tracephywritedelayabs)) {
+ KDBG(MACHDBG_CODE(DBG_MACH_IO, DBC_MACH_IO_PORTIO_WRITE),
+ (eabs - sabs), sabs, ioport, val);
+
+ (void)ml_set_interrupts_enabled(istate);
+ } else {
+ (void)ml_set_interrupts_enabled(istate);
+ }
+ }