From f94f8f792c37fe2abd7db8d6eaf70929580bf62f Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 29 Apr 2013 12:05:19 +0200 Subject: [PATCH 387/471] * grub-core/bus/usb/uhci.c: Fix DMA handling and enable on all PCI platforms. --- ChangeLog | 5 ++++ grub-core/Makefile.core.def | 2 +- grub-core/bus/usb/uhci.c | 70 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 59 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9dacb19..99a049a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2013-04-29 Vladimir Serbinenko + * grub-core/bus/usb/uhci.c: Fix DMA handling and enable on all PCI + platforms. + +2013-04-29 Vladimir Serbinenko + * grub-core/script/execute.c (grub_script_arglist_to_argv): Fix handling of variables containing backslash. diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 2e73d89..dcb92ef 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -482,7 +482,7 @@ module = { module = { name = uhci; common = bus/usb/uhci.c; - enable = x86; + enable = pci; }; module = { diff --git a/grub-core/bus/usb/uhci.c b/grub-core/bus/usb/uhci.c index 3639c42..a314637 100644 --- a/grub-core/bus/usb/uhci.c +++ b/grub-core/bus/usb/uhci.c @@ -26,6 +26,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -44,12 +45,22 @@ typedef enum GRUB_UHCI_REG_USBLEGSUP = 0xc0 } grub_uhci_reg_t; +enum + { + GRUB_UHCI_DETECT_CHANGED = (1 << 1), + GRUB_UHCI_DETECT_HAVE_DEVICE = 1, + GRUB_UHCI_DETECT_LOW_SPEED = (1 << 8) + }; + /* R/WC legacy support bits */ -#define GRUB_UHCI_LEGSUP_END_A20GATE (1 << 15) -#define GRUB_UHCI_TRAP_BY_64H_WSTAT (1 << 11) -#define GRUB_UHCI_TRAP_BY_64H_RSTAT (1 << 10) -#define GRUB_UHCI_TRAP_BY_60H_WSTAT (1 << 9) -#define GRUB_UHCI_TRAP_BY_60H_RSTAT (1 << 8) +enum + { + GRUB_UHCI_LEGSUP_END_A20GATE = (1 << 15), + GRUB_UHCI_TRAP_BY_64H_WSTAT = (1 << 11), + GRUB_UHCI_TRAP_BY_64H_RSTAT = (1 << 10), + GRUB_UHCI_TRAP_BY_60H_WSTAT = (1 << 9), + GRUB_UHCI_TRAP_BY_60H_RSTAT = (1 << 8) + }; /* Reset all legacy support - clear all R/WC bits and all R/W bits */ #define GRUB_UHCI_RESET_LEGSUP_SMI ( GRUB_UHCI_LEGSUP_END_A20GATE \ @@ -125,7 +136,7 @@ typedef volatile struct grub_uhci_qh *grub_uhci_qh_t; struct grub_uhci { - int iobase; + grub_port_t iobase; volatile grub_uint32_t *framelist_virt; grub_uint32_t framelist_phys; struct grub_pci_dma_chunk *framelist_chunk; @@ -213,22 +224,36 @@ grub_uhci_pci_iter (grub_pci_device_t dev, /* Set bus master - needed for coreboot or broken BIOSes */ addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND); - grub_pci_write_word(addr, - GRUB_PCI_COMMAND_BUS_MASTER | grub_pci_read_word(addr)); + grub_pci_write_word(addr, GRUB_PCI_COMMAND_IO_ENABLED + | GRUB_PCI_COMMAND_BUS_MASTER + | grub_pci_read_word (addr)); /* Determine IO base address. */ addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG4); base = grub_pci_read (addr); /* Stop if there is no IO space base address defined. */ - if (! (base & 1)) + if ((base & GRUB_PCI_ADDR_SPACE_MASK) != GRUB_PCI_ADDR_SPACE_IO) return 0; + if ((base & GRUB_UHCI_IOMASK) == 0) + { +#if defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_QEMU) + static int ndevs = 0; + base = 0x1800 + ndevs++ * 0x100; + grub_pci_write (addr, base | GRUB_PCI_ADDR_SPACE_IO); +#else + return 0; +#endif + } + + grub_dprintf ("uhci", "base = %x\n", base); + /* Allocate memory for the controller and register it. */ u = grub_zalloc (sizeof (*u)); if (! u) return 1; - u->iobase = base & GRUB_UHCI_IOMASK; + u->iobase = (base & GRUB_UHCI_IOMASK) + GRUB_MACHINE_PCI_IO_BASE; /* Reset PIRQ and SMI */ addr = grub_pci_make_address (dev, GRUB_UHCI_REG_USBLEGSUP); @@ -392,6 +417,7 @@ grub_free_queue (struct grub_uhci *u, grub_uhci_qh_t qh, grub_uhci_td_t td, { grub_uhci_td_t tdprev; + grub_dprintf ("uhci", "Freeing %p\n", td); /* Check state of TD and possibly set last_trans */ if (transfer && (td->linkptr & 1)) transfer->last_trans = i; @@ -400,7 +426,10 @@ grub_free_queue (struct grub_uhci *u, grub_uhci_qh_t qh, grub_uhci_td_t td, /* Unlink the queue. */ tdprev = td; - td = grub_dma_phys2virt (td->linkptr2, u->td_chunk); + if (!td->linkptr2) + td = 0; + else + td = grub_dma_phys2virt (td->linkptr2, u->td_chunk); /* Free the TD. */ grub_free_td (u, tdprev); @@ -583,10 +612,17 @@ grub_uhci_check_transfer (grub_usb_controller_t dev, *actual = 0; - errtd = grub_dma_phys2virt (cdata->qh->elinkptr & ~0x0f, u->qh_chunk); + if (cdata->qh->elinkptr & ~0x0f) + errtd = grub_dma_phys2virt (cdata->qh->elinkptr & ~0x0f, u->qh_chunk); + else + errtd = 0; - grub_dprintf ("uhci", ">t status=0x%02x data=0x%02x td=%p\n", - errtd->ctrl_status, errtd->buffer & (~15), errtd); + if (errtd) + { + grub_dprintf ("uhci", ">t status=0x%02x data=0x%02x td=%p, %x\n", + errtd->ctrl_status, errtd->buffer & (~15), errtd, + cdata->qh->elinkptr); + } /* Check if the transaction completed. */ if (cdata->qh->elinkptr & 1) @@ -788,7 +824,7 @@ grub_uhci_detect_dev (grub_usb_controller_t dev, int port, int *changed) grub_dprintf ("uhci", "detect=0x%02x port=%d\n", status, port); /* Connect Status Change bit - it detects change of connection */ - if (status & (1 << 1)) + if (status & GRUB_UHCI_DETECT_CHANGED) { *changed = 1; /* Reset bit Connect Status Change */ @@ -798,9 +834,9 @@ grub_uhci_detect_dev (grub_usb_controller_t dev, int port, int *changed) else *changed = 0; - if (! (status & 1)) + if (! (status & GRUB_UHCI_DETECT_HAVE_DEVICE)) return GRUB_USB_SPEED_NONE; - else if (status & (1 << 8)) + else if (status & GRUB_UHCI_DETECT_LOW_SPEED) return GRUB_USB_SPEED_LOW; else return GRUB_USB_SPEED_FULL; -- 1.8.2.1