anchor.diff:  
   (in-package :mezzano.driver.rtl8168)
   
  +;;; "Realtek Gigabit Ethernet Media Access Controller With Power Management RTL8169"
   ;;; http://www.iitg.ernet.in/asahu/cs421/RealTek.pdf
   
   ;;; Registers.
  
positive.code: (defun (setf rtl8168-tx-desc-address) (value nic descriptor)
    (setf (rtl8168-descriptor-address (rtl8168-tx-ring-virt nic) descriptor) value))
  
  (defun rtl8168-initialize (nic)
    (setf (rtl8168-irq-handler nic) (make-simple-irq (rtl8168-irq nic)))
    (sup:with-device-access ((rtl8168-boot-id nic) nil)
      ;; Initialize the device.
      (debug-print-line "Initializing RTL8168 at " (rtl8168-pci-location nic) ". IO base " (rtl8168-io-base nic))
      (simple-irq-attach (rtl8168-irq-handler nic))
      (setf (pci:pci-bus-master-enabled (rtl8168-pci-location nic)) t)
      ;; Mask and ack interrupts.
      (setf (rtl8168-reg/16 nic +rtl8168-register-IMR+) #x0000
            (rtl8168-reg/16 nic +rtl8168-register-ISR+) #xFFFF)
      ;; Soft reset NIC by setting the reset bit.
      (setf (rtl8168-reg/8 nic +rtl8168-register-CR+) (ash 1 +rtl8168-CR-RST+))
      ;; Check that the chip has finished the reset. It will automatically clear the reset bit.
      (loop
         repeat 100
         do
           (when (not (logbitp +rtl8168-CR-RST+ (rtl8168-reg/8 nic +rtl8168-register-CR+)))
             (return))
           (sleep 0.01)
         finally
           (debug-print-line "RTL8168 reset timed out!")
           (return-from rtl8168-initialize))
      ;; Read the MAC.
      (loop
         with mac = 0
  
negative.code:     (sync:mailbox-send data (rtl8168-tx-mailbox nic))))
  
  (defmethod nic:statistics ((nic rtl8168))
    (values (rtl8168-rx-octets nic)
            (rtl8168-rx-count nic)
            0
            (rtl8168-tx-octets nic)
            (rtl8168-tx-count nic)
            0
            0))
  
  (defun tx-descriptors-available-p (nic)
    (not (eql (rtl8168-tx-used-count nic) +rtl8168-n-tx-descriptors+)))
  
  (defmacro with-rtl8168-access ((nic) &body body)
    `(sup:with-device-access ((rtl8168-boot-id ,nic)
                              (throw 'disconnect nil))
       ,@body))
  
  (defun rtl8168-receive-processing (nic)
    ;; Perform receive handling. Remove packets from the RX ring
    ;; until there are none left.
    (loop
       (let ((current (rtl8168-rx-current nic)))
         (with-rtl8168-access (nic)
           (when (logbitp +rtl8168-descriptor-OWN+ (rtl8168-rx-desc-flags nic current))
             ;; Current descriptor owned by the NIC, no more packets to receive.
             ;; Break out of the RX loop.
             (return)))
         #+(or)(debug-print-line "RTL8168 receive on " current)
         ;; Receiving one packet.
         ;; Allocate a buffer. Try to minimize the amount of work done in a device-access region, hence the dropping in and out.
         (let ((buffer (make-array +rtl8168-mtu+ :element-type '(unsigned-byte 8))))
           (with-rtl8168-access (nic)
             ;; Copy the packet into the receive buffer.
             (let ((address (+ (rtl8168-rx-bounce-virt nic)
                               (* current (mezzano.supervisor::align-up +rtl8168-mtu+ 128))))
                   (frame-len (min +rtl8168-mtu+
                                   (ldb (byte 16 +rtl8168-descriptor-Frame_Length+)
                                        (rtl8168-rx-desc-flags nic current)))))
               (dotimes (i frame-len)
                 (setf (aref buffer i) (sys.int::memref-unsigned-byte-8 address i)))
               (incf (rtl8168-rx-octets nic) frame-len)
               (incf (rtl8168-rx-count nic)))
             ;; Reset the descriptor.
             (setf (rtl8168-rx-desc-flags nic current) (logior (ash +rtl8168-mtu+ +rtl8168-descriptor-Frame_Length+)
                                                               (ash 1 +rtl8168-descriptor-OWN+)
                                                               (if (eql current (1- +rtl8168-n-rx-descriptors+))
                                                                   (ash 1 +rtl8168-descriptor-EOR+)
                                                                   0))
                   (rtl8168-rx-desc-vlan nic current) 0))
           (nic:device-received-packet nic buffer))
         ;; Advance Current.
         (setf (rtl8168-rx-current nic) (rem (1+ current) +rtl8168-n-rx-descriptors+)))))
  
  (defun rtl8168-transmit-processing (nic)
    ;; Transmit handling.
    ;; Recover free descriptors.
    (with-rtl8168-access (nic)
      (loop
         (when (eql (rtl8168-tx-used-count nic) 0)
           ;; All pending descriptors processed.
           (return))
         (when (logbitp +rtl8168-descriptor-OWN+ (rtl8168-tx-desc-flags nic (rtl8168-tx-tail nic)))
           ;; Reached the descriptor that the card is processing.
           #+(or)(debug-print-line "RTL8168 still processing " (rtl8168-tx-tail nic))
           (return))
         (decf (rtl8168-tx-used-count nic))
         (setf (rtl8168-tx-tail nic) (rem (1+ (rtl8168-tx-tail nic)) +rtl8168-n-tx-descriptors+))
         #+(or)(debug-print-line "RTL8168 transmitted packet on descriptor " (rtl8168-tx-tail nic))))
    ;; Send pending packets.
    (loop
       (when (not (tx-descriptors-available-p nic))
         ;; Don't transmit when there are no free descriptors.
         #+(or)(debug-print-line "RTL8168 not transmitting - no free descriptors.")
         (return))
       (let ((to-send (sync:mailbox-receive (rtl8168-tx-mailbox nic) :wait-p nil))
             (current (rtl8168-tx-current nic)))
         (when (not to-send)
           (return))
         #+(or)(debug-print-line "RTL8168 transmitting packet " to-send " on descriptor " current)
         (with-rtl8168-access (nic)
           (incf (rtl8168-tx-octets nic) (length to-send))
           (incf (rtl8168-tx-count nic))
           ;; Copy packet to buffer.
           (let ((address (+ (rtl8168-tx-bounce-virt nic)
                             (* current (mezzano.supervisor::align-up +rtl8168-mtu+ 128)))))
             (dotimes (i (min +rtl8168-mtu+
                              (length to-send)))
               (setf (sys.int::memref-unsigned-byte-8 address i) (aref to-send i))))
           ;; Configure the descriptor.
           (setf (rtl8168-tx-desc-flags nic current) (logior (ash (min +rtl8168-mtu+ (length to-send))
                                                                  +rtl8168-descriptor-Frame_Length+)
                                                             (ash 1 +rtl8168-descriptor-OWN+)
                                                             (if (eql current (1- +rtl8168-n-tx-descriptors+))
                                                                 (ash 1 +rtl8168-descriptor-EOR+)
                                                                 0)
                                                             ;; This is the first & last segment.
                                                             (ash 1 +rtl8168-descriptor-FS+)
                                                             (ash 1 +rtl8168-descriptor-LS+))
                 (rtl8168-tx-desc-vlan nic current) 0)
           ;; Notify the card.
           (setf (rtl8168-reg/8 nic +rtl8168-register-TPPoll+) (ash 1 +rtl8168-TPPoll-NPQ+)))
         ;; One used.
         (incf (rtl8168-tx-used-count nic))
         ;; Advance current.
         (setf (rtl8168-tx-current nic) (rem (1+ current) +rtl8168-n-tx-descriptors+)))))
  
  ;; TODO: Get the remaining registers.
  (defun dump (nic)
    (describe nic)
    (format t " ID: ~2,'0X:~2,'0X:~2,'0X:~2,'0X:~2,'0X:~2,'0X~%"
            (rtl8168-reg/8 nic +rtl8168-register-ID0+)
            (rtl8168-reg/8 nic (+ +rtl8168-register-ID0+ 1))
            (rtl8168-reg/8 nic (+ +rtl8168-register-ID0+ 2))
            (rtl8168-reg/8 nic (+ +rtl8168-register-ID0+ 3))
            (rtl8168-reg/8 nic (+ +rtl8168-register-ID0+ 4))
            (rtl8168-reg/8 nic (+ +rtl8168-register-ID0+ 5)))
    (format t " MAR: ~2,'0X ~2,'0X ~2,'0X ~2,'0X ~2,'0X ~2,'0X ~2,'0X ~2,'0X~%"
            (rtl8168-reg/8 nic +rtl8168-register-MAR0+)
            (rtl8168-reg/8 nic (+ +rtl8168-register-MAR0+ 1))
            (rtl8168-reg/8 nic (+ +rtl8168-register-MAR0+ 2))
            (rtl8168-reg/8 nic (+ +rtl8168-register-MAR0+ 3))
            (rtl8168-reg/8 nic (+ +rtl8168-register-MAR0+ 4))
            (rtl8168-reg/8 nic (+ +rtl8168-register-MAR0+ 5))
            (rtl8168-reg/8 nic (+ +rtl8168-register-MAR0+ 6))
            (rtl8168-reg/8 nic (+ +rtl8168-register-MAR0+ 7))))
  
  (defun rtl8168-worker-body (nic)
    ;; Wait for something to happen.
    ;; Either an interrupt, a request to send, or the device's boot epoch expiring.
    (if (tx-descriptors-available-p nic)
        (sync:wait-for-objects (rtl8168-irq-handler nic)
                               (rtl8168-tx-mailbox nic)
                               (rtl8168-boot-id nic))
        ;; Don't look in the TX mailbox if all descriptors are full.
        (sync:wait-for-objects (rtl8168-irq-handler nic)
                               (rtl8168-boot-id nic)))
    ;; Ack the interrupt and check for errors.
    (with-rtl8168-access (nic)
      (let ((isr (rtl8168-reg/16 nic +rtl8168-register-ISR+)))
        (when (logbitp +ISR-FOVW+ isr)
          (format t "~S: Rx FIFO overflow! Resetting!~%" nic)
          (rtl8168-reset nic)
          ;; Abandon this work iteration.
          (return-from rtl8168-worker-body))
        ;; Acknowledge IRQ.
        (setf (rtl8168-reg/16 nic +rtl8168-register-ISR+) isr)))
    (rtl8168-receive-processing nic)
    (rtl8168-transmit-processing nic)
    (simple-irq-unmask (rtl8168-irq-handler nic)))
  
  (defun rtl8168-worker (nic)
    (when (not (rtl8168-initialize nic))
      (return-from rtl8168-worker))
    (catch 'disconnect
      (unwind-protect
           (loop
              (rtl8168-worker-body nic))
        (nic:unregister-network-card nic))))
  
  (defun rtl8168-allocate-ring (name size)
  