From 0f076d75d04d76ab83e8472715eec71da0cb55ff Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Tue, 23 Feb 2016 12:06:48 +0100 Subject: [PATCH] ehci: Fix memory coherence This is a no-op on x86 but necessarry on ARM and may be necessarry on MIPS. --- grub-core/bus/usb/ehci.c | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/grub-core/bus/usb/ehci.c b/grub-core/bus/usb/ehci.c index ae1efb214..5f4297bb2 100644 --- a/grub-core/bus/usb/ehci.c +++ b/grub-core/bus/usb/ehci.c @@ -29,6 +29,7 @@ #include #include #include +#include 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; } -- 2.39.5