+/*
+ * For machines where the transfers on an I/O bus can stall because
+ * the CPU is in an idle mode, These APIs allow a driver to specify
+ * the maximum bus stall that they can handle. 0 indicates no limit.
+ */
+void IOService::
+setCPUSnoopDelay(UInt32 __unused ns)
+{
+#if __i386__
+ ml_set_maxsnoop(ns);
+#endif /* __i386__ */
+}
+
+UInt32 IOService::
+getCPUSnoopDelay()
+{
+#if __i386__
+ return ml_get_maxsnoop();
+#else
+ return 0;
+#endif /* __i386__ */
+}
+
+void IOService::
+requireMaxBusStall(UInt32 __unused ns)
+{
+#if __i386__
+ static const UInt kNoReplace = -1U; // Must be an illegal index
+ UInt replace = kNoReplace;
+
+ IOLockLock(sBusStallLock);
+
+ UInt count = sBusStall->getLength() / sizeof(BusStallEntry);
+ BusStallEntry *entries = (BusStallEntry *) sBusStall->getBytesNoCopy();
+
+ if (ns) {
+ const BusStallEntry ne = {this, ns};
+
+ // Set Maximum bus delay.
+ for (UInt i = 0; i < count; i++) {
+ const IOService *thisService = entries[i].fService;
+ if (this == thisService)
+ replace = i;
+ else if (!thisService) {
+ if (kNoReplace == replace)
+ replace = i;
+ }
+ else {
+ const UInt32 thisMax = entries[i].fMaxDelay;
+ if (thisMax < ns)
+ ns = thisMax;
+ }
+ }
+
+ // Must be safe to call from locked context
+ ml_set_maxbusdelay(ns);
+
+ if (kNoReplace == replace)
+ sBusStall->appendBytes(&ne, sizeof(ne));
+ else
+ entries[replace] = ne;
+ }
+ else {
+ ns = -1U; // Set to max unsigned, i.e. no restriction
+
+ for (UInt i = 0; i < count; i++) {
+ // Clear a maximum bus delay.
+ const IOService *thisService = entries[i].fService;
+ UInt32 thisMax = entries[i].fMaxDelay;
+ if (this == thisService)
+ replace = i;
+ else if (thisService && thisMax < ns)
+ ns = thisMax;
+ }
+
+ // Check if entry found
+ if (kNoReplace != replace) {
+ entries[replace].fService = 0; // Null the entry
+ ml_set_maxbusdelay(ns);
+ }
+ }
+
+ IOLockUnlock(sBusStallLock);
+#endif /* __i386__ */
+}
+