]> git.proxmox.com Git - grub2.git/commitdiff
ehci: Fix memory coherence
authorVladimir Serbinenko <phcoder@gmail.com>
Tue, 23 Feb 2016 11:06:48 +0000 (12:06 +0100)
committerVladimir Serbinenko <phcoder@gmail.com>
Sat, 27 Feb 2016 12:40:52 +0000 (13:40 +0100)
This is a no-op on x86 but necessarry on ARM and may be necessarry on MIPS.

grub-core/bus/usb/ehci.c

index ae1efb2143381340ed3a9a0a5220399b21c6a0f1..5f4297bb21ec4c28824abb0c442a87a3dd4a872e 100644 (file)
@@ -29,6 +29,7 @@
 #include <grub/loader.h>
 #include <grub/cs5536.h>
 #include <grub/disk.h>
+#include <grub/cache.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -337,6 +338,21 @@ struct grub_ehci
 
 static struct grub_ehci *ehci;
 
+static void
+sync_all_caches (struct grub_ehci *e)
+{
+  if (!e)
+    return;
+  if (e->td_virt)
+    grub_arch_sync_dma_caches (e->td_virt, sizeof (struct grub_ehci_td) *
+                              GRUB_EHCI_N_TD);
+  if (e->qh_virt)
+    grub_arch_sync_dma_caches (e->qh_virt, sizeof (struct grub_ehci_qh) *
+                              GRUB_EHCI_N_QH);
+  if (e->framelist_virt)
+    grub_arch_sync_dma_caches (e->framelist_virt, 4096);
+}
+
 /* EHCC registers access functions */
 static inline grub_uint32_t
 grub_ehci_ehcc_read32 (struct grub_ehci *e, grub_uint32_t addr)
@@ -437,6 +453,8 @@ grub_ehci_reset (struct grub_ehci *e)
 {
   grub_uint64_t maxtime;
 
+  sync_all_caches (e);
+
   grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
                          GRUB_EHCI_CMD_HC_RESET
                          | grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
@@ -840,6 +858,8 @@ grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
   e->next = ehci;
   ehci = e;
 
+  sync_all_caches (e);
+
   grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: OK at all\n");
 
   grub_dprintf ("ehci",
@@ -1020,6 +1040,7 @@ grub_ehci_find_qh (struct grub_ehci *e, grub_usb_transfer_t transfer)
          /* Found proper existing (and linked) QH, do setup of QH */
          grub_dprintf ("ehci", "find_qh: found, QH=%p\n", qh_iter);
          grub_ehci_setup_qh (qh_iter, transfer);
+         sync_all_caches (e);
          return qh_iter;
        }
 
@@ -1291,6 +1312,8 @@ grub_ehci_setup_transfer (grub_usb_controller_t dev,
   struct grub_ehci_transfer_controller_data *cdata;
   grub_uint32_t status;
 
+  sync_all_caches (e);
+
   /* Check if EHCI is running and AL is enabled */
   status = grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS);
   if ((status & GRUB_EHCI_ST_HC_HALTED) != 0)
@@ -1399,6 +1422,8 @@ grub_ehci_setup_transfer (grub_usb_controller_t dev,
    * i.e. reset token */
   cdata->qh_virt->td_overlay.token = grub_cpu_to_le32_compile_time (0);
 
+  sync_all_caches (e);
+
   /* Finito */
   transfer->controller_data = cdata;
 
@@ -1447,6 +1472,8 @@ grub_ehci_parse_notrun (grub_usb_controller_t dev,
   grub_ehci_free_td (e, cdata->td_alt_virt);
   grub_free (cdata);
 
+  sync_all_caches (e);
+
   /* Additionally, do something with EHCI to make it running (what?) */
   /* Try enable EHCI and AL */
   grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
@@ -1482,6 +1509,8 @@ grub_ehci_parse_halt (grub_usb_controller_t dev,
   grub_ehci_free_td (e, cdata->td_alt_virt);
   grub_free (cdata);
 
+  sync_all_caches (e);
+
   /* Evaluation of error code - currently we don't have GRUB USB error
    * codes for some EHCI states, GRUB_USB_ERR_DATA is used for them.
    * Order of evaluation is critical, specially bubble/stall. */
@@ -1515,6 +1544,8 @@ grub_ehci_parse_success (grub_usb_controller_t dev,
   grub_ehci_free_td (e, cdata->td_alt_virt);
   grub_free (cdata);
 
+  sync_all_caches (e);
+
   return GRUB_USB_ERR_NONE;
 }
 
@@ -1528,6 +1559,8 @@ grub_ehci_check_transfer (grub_usb_controller_t dev,
     transfer->controller_data;
   grub_uint32_t token, token_ftd;
 
+  sync_all_caches (e);
+
   grub_dprintf ("ehci",
                "check_transfer: EHCI STATUS=%08x, cdata=%p, qh=%p\n",
                grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS),
@@ -1594,6 +1627,9 @@ grub_ehci_cancel_transfer (grub_usb_controller_t dev,
   int i;
   grub_uint64_t maxtime;
   grub_uint32_t qh_phys;
+
+  sync_all_caches (e);
+
   grub_uint32_t interrupt =
     cdata->qh_virt->ep_cap & GRUB_EHCI_SMASK_MASK;
 
@@ -1613,6 +1649,7 @@ grub_ehci_cancel_transfer (grub_usb_controller_t dev,
       grub_ehci_free_tds (e, cdata->td_first_virt, transfer, &actual);
       grub_ehci_free_td (e, cdata->td_alt_virt);
       grub_free (cdata);
+      sync_all_caches (e);
       grub_dprintf ("ehci", "cancel_transfer: end - EHCI not running\n");
       return GRUB_USB_ERR_NONE;
     }
@@ -1635,6 +1672,8 @@ grub_ehci_cancel_transfer (grub_usb_controller_t dev,
   /* Unlink QH from AL */
   e->qh_virt[i].qh_hptr = cdata->qh_virt->qh_hptr;
 
+  sync_all_caches (e);
+
   /* If this is an interrupt transfer, we just wait for the periodic
    * schedule to advance a few times and then assume that the EHCI
    * controller has read the updated QH. */
@@ -1689,6 +1728,8 @@ grub_ehci_cancel_transfer (grub_usb_controller_t dev,
 
   grub_dprintf ("ehci", "cancel_transfer: end\n");
 
+  sync_all_caches (e);
+
   return GRUB_USB_ERR_NONE;
 }