* grub-core/bus/usb/uhci.c: Fix DMA handling and enable on all PCI

platforms.
This commit is contained in:
Vladimir 'phcoder' Serbinenko 2013-04-29 12:05:19 +02:00
parent bdc4add8ca
commit f7bf6c31f3
3 changed files with 59 additions and 18 deletions

View file

@ -1,3 +1,8 @@
2013-04-29 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/bus/usb/uhci.c: Fix DMA handling and enable on all PCI
platforms.
2013-04-29 Vladimir Serbinenko <phcoder@gmail.com> 2013-04-29 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/script/execute.c (grub_script_arglist_to_argv): Fix * grub-core/script/execute.c (grub_script_arglist_to_argv): Fix

View file

@ -482,7 +482,7 @@ module = {
module = { module = {
name = uhci; name = uhci;
common = bus/usb/uhci.c; common = bus/usb/uhci.c;
enable = x86; enable = pci;
}; };
module = { module = {

View file

@ -26,6 +26,7 @@
#include <grub/cpu/io.h> #include <grub/cpu/io.h>
#include <grub/time.h> #include <grub/time.h>
#include <grub/cpu/pci.h> #include <grub/cpu/pci.h>
#include <grub/disk.h>
GRUB_MOD_LICENSE ("GPLv3+"); GRUB_MOD_LICENSE ("GPLv3+");
@ -44,12 +45,22 @@ typedef enum
GRUB_UHCI_REG_USBLEGSUP = 0xc0 GRUB_UHCI_REG_USBLEGSUP = 0xc0
} grub_uhci_reg_t; } 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 */ /* R/WC legacy support bits */
#define GRUB_UHCI_LEGSUP_END_A20GATE (1 << 15) enum
#define GRUB_UHCI_TRAP_BY_64H_WSTAT (1 << 11) {
#define GRUB_UHCI_TRAP_BY_64H_RSTAT (1 << 10) GRUB_UHCI_LEGSUP_END_A20GATE = (1 << 15),
#define GRUB_UHCI_TRAP_BY_60H_WSTAT (1 << 9) GRUB_UHCI_TRAP_BY_64H_WSTAT = (1 << 11),
#define GRUB_UHCI_TRAP_BY_60H_RSTAT (1 << 8) 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 */ /* 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 \ #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 struct grub_uhci
{ {
int iobase; grub_port_t iobase;
volatile grub_uint32_t *framelist_virt; volatile grub_uint32_t *framelist_virt;
grub_uint32_t framelist_phys; grub_uint32_t framelist_phys;
struct grub_pci_dma_chunk *framelist_chunk; 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 */ /* Set bus master - needed for coreboot or broken BIOSes */
addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND); addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
grub_pci_write_word(addr, grub_pci_write_word(addr, GRUB_PCI_COMMAND_IO_ENABLED
GRUB_PCI_COMMAND_BUS_MASTER | grub_pci_read_word(addr)); | GRUB_PCI_COMMAND_BUS_MASTER
| grub_pci_read_word (addr));
/* Determine IO base address. */ /* Determine IO base address. */
addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG4); addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG4);
base = grub_pci_read (addr); base = grub_pci_read (addr);
/* Stop if there is no IO space base address defined. */ /* 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; 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. */ /* Allocate memory for the controller and register it. */
u = grub_zalloc (sizeof (*u)); u = grub_zalloc (sizeof (*u));
if (! u) if (! u)
return 1; return 1;
u->iobase = base & GRUB_UHCI_IOMASK; u->iobase = (base & GRUB_UHCI_IOMASK) + GRUB_MACHINE_PCI_IO_BASE;
/* Reset PIRQ and SMI */ /* Reset PIRQ and SMI */
addr = grub_pci_make_address (dev, GRUB_UHCI_REG_USBLEGSUP); 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_uhci_td_t tdprev;
grub_dprintf ("uhci", "Freeing %p\n", td);
/* Check state of TD and possibly set last_trans */ /* Check state of TD and possibly set last_trans */
if (transfer && (td->linkptr & 1)) if (transfer && (td->linkptr & 1))
transfer->last_trans = i; transfer->last_trans = i;
@ -400,6 +426,9 @@ grub_free_queue (struct grub_uhci *u, grub_uhci_qh_t qh, grub_uhci_td_t td,
/* Unlink the queue. */ /* Unlink the queue. */
tdprev = td; tdprev = td;
if (!td->linkptr2)
td = 0;
else
td = grub_dma_phys2virt (td->linkptr2, u->td_chunk); td = grub_dma_phys2virt (td->linkptr2, u->td_chunk);
/* Free the TD. */ /* Free the TD. */
@ -583,10 +612,17 @@ grub_uhci_check_transfer (grub_usb_controller_t dev,
*actual = 0; *actual = 0;
if (cdata->qh->elinkptr & ~0x0f)
errtd = grub_dma_phys2virt (cdata->qh->elinkptr & ~0x0f, u->qh_chunk); 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", if (errtd)
errtd->ctrl_status, errtd->buffer & (~15), 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. */ /* Check if the transaction completed. */
if (cdata->qh->elinkptr & 1) 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); grub_dprintf ("uhci", "detect=0x%02x port=%d\n", status, port);
/* Connect Status Change bit - it detects change of connection */ /* Connect Status Change bit - it detects change of connection */
if (status & (1 << 1)) if (status & GRUB_UHCI_DETECT_CHANGED)
{ {
*changed = 1; *changed = 1;
/* Reset bit Connect Status Change */ /* Reset bit Connect Status Change */
@ -798,9 +834,9 @@ grub_uhci_detect_dev (grub_usb_controller_t dev, int port, int *changed)
else else
*changed = 0; *changed = 0;
if (! (status & 1)) if (! (status & GRUB_UHCI_DETECT_HAVE_DEVICE))
return GRUB_USB_SPEED_NONE; return GRUB_USB_SPEED_NONE;
else if (status & (1 << 8)) else if (status & GRUB_UHCI_DETECT_LOW_SPEED)
return GRUB_USB_SPEED_LOW; return GRUB_USB_SPEED_LOW;
else else
return GRUB_USB_SPEED_FULL; return GRUB_USB_SPEED_FULL;