ehci: Fix memory coherence

This is a no-op on x86 but necessarry on ARM and may be necessarry on MIPS.
This commit is contained in:
Vladimir Serbinenko 2016-02-23 12:06:48 +01:00
parent 86ef66d977
commit 0f076d75d0

View file

@ -29,6 +29,7 @@
#include <grub/loader.h> #include <grub/loader.h>
#include <grub/cs5536.h> #include <grub/cs5536.h>
#include <grub/disk.h> #include <grub/disk.h>
#include <grub/cache.h>
GRUB_MOD_LICENSE ("GPLv3+"); GRUB_MOD_LICENSE ("GPLv3+");
@ -337,6 +338,21 @@ struct grub_ehci
static struct grub_ehci *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 */ /* EHCC registers access functions */
static inline grub_uint32_t static inline grub_uint32_t
grub_ehci_ehcc_read32 (struct grub_ehci *e, grub_uint32_t addr) 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; grub_uint64_t maxtime;
sync_all_caches (e);
grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND, grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
GRUB_EHCI_CMD_HC_RESET GRUB_EHCI_CMD_HC_RESET
| grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND)); | 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; e->next = ehci;
ehci = e; ehci = e;
sync_all_caches (e);
grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: OK at all\n"); grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: OK at all\n");
grub_dprintf ("ehci", 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 */ /* Found proper existing (and linked) QH, do setup of QH */
grub_dprintf ("ehci", "find_qh: found, QH=%p\n", qh_iter); grub_dprintf ("ehci", "find_qh: found, QH=%p\n", qh_iter);
grub_ehci_setup_qh (qh_iter, transfer); grub_ehci_setup_qh (qh_iter, transfer);
sync_all_caches (e);
return qh_iter; return qh_iter;
} }
@ -1291,6 +1312,8 @@ grub_ehci_setup_transfer (grub_usb_controller_t dev,
struct grub_ehci_transfer_controller_data *cdata; struct grub_ehci_transfer_controller_data *cdata;
grub_uint32_t status; grub_uint32_t status;
sync_all_caches (e);
/* Check if EHCI is running and AL is enabled */ /* Check if EHCI is running and AL is enabled */
status = grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS); status = grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS);
if ((status & GRUB_EHCI_ST_HC_HALTED) != 0) 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 */ * i.e. reset token */
cdata->qh_virt->td_overlay.token = grub_cpu_to_le32_compile_time (0); cdata->qh_virt->td_overlay.token = grub_cpu_to_le32_compile_time (0);
sync_all_caches (e);
/* Finito */ /* Finito */
transfer->controller_data = cdata; 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_ehci_free_td (e, cdata->td_alt_virt);
grub_free (cdata); grub_free (cdata);
sync_all_caches (e);
/* Additionally, do something with EHCI to make it running (what?) */ /* Additionally, do something with EHCI to make it running (what?) */
/* Try enable EHCI and AL */ /* Try enable EHCI and AL */
grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND, 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_ehci_free_td (e, cdata->td_alt_virt);
grub_free (cdata); grub_free (cdata);
sync_all_caches (e);
/* Evaluation of error code - currently we don't have GRUB USB error /* 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. * codes for some EHCI states, GRUB_USB_ERR_DATA is used for them.
* Order of evaluation is critical, specially bubble/stall. */ * 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_ehci_free_td (e, cdata->td_alt_virt);
grub_free (cdata); grub_free (cdata);
sync_all_caches (e);
return GRUB_USB_ERR_NONE; return GRUB_USB_ERR_NONE;
} }
@ -1528,6 +1559,8 @@ grub_ehci_check_transfer (grub_usb_controller_t dev,
transfer->controller_data; transfer->controller_data;
grub_uint32_t token, token_ftd; grub_uint32_t token, token_ftd;
sync_all_caches (e);
grub_dprintf ("ehci", grub_dprintf ("ehci",
"check_transfer: EHCI STATUS=%08x, cdata=%p, qh=%p\n", "check_transfer: EHCI STATUS=%08x, cdata=%p, qh=%p\n",
grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS), grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS),
@ -1594,6 +1627,9 @@ grub_ehci_cancel_transfer (grub_usb_controller_t dev,
int i; int i;
grub_uint64_t maxtime; grub_uint64_t maxtime;
grub_uint32_t qh_phys; grub_uint32_t qh_phys;
sync_all_caches (e);
grub_uint32_t interrupt = grub_uint32_t interrupt =
cdata->qh_virt->ep_cap & GRUB_EHCI_SMASK_MASK; 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_tds (e, cdata->td_first_virt, transfer, &actual);
grub_ehci_free_td (e, cdata->td_alt_virt); grub_ehci_free_td (e, cdata->td_alt_virt);
grub_free (cdata); grub_free (cdata);
sync_all_caches (e);
grub_dprintf ("ehci", "cancel_transfer: end - EHCI not running\n"); grub_dprintf ("ehci", "cancel_transfer: end - EHCI not running\n");
return GRUB_USB_ERR_NONE; return GRUB_USB_ERR_NONE;
} }
@ -1635,6 +1672,8 @@ grub_ehci_cancel_transfer (grub_usb_controller_t dev,
/* Unlink QH from AL */ /* Unlink QH from AL */
e->qh_virt[i].qh_hptr = cdata->qh_virt->qh_hptr; 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 /* If this is an interrupt transfer, we just wait for the periodic
* schedule to advance a few times and then assume that the EHCI * schedule to advance a few times and then assume that the EHCI
* controller has read the updated QH. */ * 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"); grub_dprintf ("ehci", "cancel_transfer: end\n");
sync_all_caches (e);
return GRUB_USB_ERR_NONE; return GRUB_USB_ERR_NONE;
} }