Convert UHCI to DMA framework.

* grub-core/bus/usb/uhci.c (grub_uhci): Add chunk and phys members.
	(grub_uhci_pci_iter): Fill new members
	(grub_alloc_td): Use P2V and V2P functions.
	(grub_free_queue): Likewise.
	(grub_alloc_qh): Likewise.
	(grub_uhci_setup_transfer): Likewise.
	(grub_uhci_check_transfer): Likewise.
This commit is contained in:
Vladimir 'phcoder' Serbinenko 2012-02-09 15:00:05 +01:00
parent 432069398f
commit 01783768d2
2 changed files with 63 additions and 63 deletions

View file

@ -1,3 +1,15 @@
2012-02-09 Vladimir Serbinenko <phcoder@gmail.com>
Convert UHCI to DMA framework.
* grub-core/bus/usb/uhci.c (grub_uhci): Add chunk and phys members.
(grub_uhci_pci_iter): Fill new members
(grub_alloc_td): Use P2V and V2P functions.
(grub_free_queue): Likewise.
(grub_alloc_qh): Likewise.
(grub_uhci_setup_transfer): Likewise.
(grub_uhci_check_transfer): Likewise.
2012-02-09 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/video/colors.c (grub_video_parse_color): Fix error message.

View file

@ -23,8 +23,9 @@
#include <grub/usb.h>
#include <grub/usbtrans.h>
#include <grub/pci.h>
#include <grub/i386/io.h>
#include <grub/cpu/io.h>
#include <grub/time.h>
#include <grub/cpu/pci.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -125,13 +126,19 @@ typedef volatile struct grub_uhci_qh *grub_uhci_qh_t;
struct grub_uhci
{
int iobase;
grub_uint32_t *framelist;
volatile grub_uint32_t *framelist_virt;
grub_uint32_t framelist_phys;
struct grub_pci_dma_chunk *framelist_chunk;
/* N_QH Queue Heads. */
grub_uhci_qh_t qh;
struct grub_pci_dma_chunk *qh_chunk;
volatile grub_uhci_qh_t qh_virt;
grub_uint32_t qh_phys;
/* N_TD Transfer Descriptors. */
grub_uhci_td_t td;
struct grub_pci_dma_chunk *td_chunk;
volatile grub_uhci_td_t td_virt;
grub_uint32_t td_phys;
/* Free Transfer Descriptors. */
grub_uhci_td_t tdfree;
@ -236,90 +243,71 @@ grub_uhci_pci_iter (grub_pci_device_t dev,
grub_uhci_readreg16(u, GRUB_UHCI_REG_USBCMD);
/* Reserve a page for the frame list. */
u->framelist = grub_memalign (4096, 4096);
if (! u->framelist)
u->framelist_chunk = grub_memalign_dma32 (4096, 4096);
if (! u->framelist_chunk)
goto fail;
u->framelist_virt = grub_dma_get_virt (u->framelist_chunk);
u->framelist_phys = grub_dma_get_phys (u->framelist_chunk);
grub_dprintf ("uhci", "class=0x%02x 0x%02x interface 0x%02x base=0x%x framelist=%p\n",
class, subclass, interf, u->iobase, u->framelist);
/* The framelist pointer of UHCI is only 32 bits, make sure this
code works on on 64 bits architectures. */
#if GRUB_CPU_SIZEOF_VOID_P == 8
if ((grub_uint64_t) u->framelist >> 32)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY,
"allocated frame list memory not <4GB");
goto fail;
}
#endif
grub_dprintf ("uhci",
"class=0x%02x 0x%02x interface 0x%02x base=0x%x framelist=%p\n",
class, subclass, interf, u->iobase, u->framelist_virt);
/* The QH pointer of UHCI is only 32 bits, make sure this
code works on on 64 bits architectures. */
u->qh = (grub_uhci_qh_t) grub_memalign (4096, sizeof(struct grub_uhci_qh)*N_QH);
if (! u->qh)
u->qh_chunk = grub_memalign_dma32 (4096, sizeof(struct grub_uhci_qh) * N_QH);
if (! u->qh_chunk)
goto fail;
#if GRUB_CPU_SIZEOF_VOID_P == 8
if ((grub_uint64_t) u->qh >> 32)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, "allocated QH memory not <4GB");
goto fail;
}
#endif
u->qh_virt = grub_dma_get_virt (u->qh_chunk);
u->qh_phys = grub_dma_get_phys (u->qh_chunk);
/* The TD pointer of UHCI is only 32 bits, make sure this
code works on on 64 bits architectures. */
u->td = (grub_uhci_td_t) grub_memalign (4096, sizeof(struct grub_uhci_td)*N_TD);
if (! u->td)
u->td_chunk = grub_memalign_dma32 (4096, sizeof(struct grub_uhci_td) * N_TD);
if (! u->td_chunk)
goto fail;
#if GRUB_CPU_SIZEOF_VOID_P == 8
if ((grub_uint64_t) u->td >> 32)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, "allocated TD memory not <4GB");
goto fail;
}
#endif
u->td_virt = grub_dma_get_virt (u->td_chunk);
u->td_phys = grub_dma_get_phys (u->td_chunk);
grub_dprintf ("uhci", "QH=%p, TD=%p\n",
u->qh, u->td);
u->qh_virt, u->td_virt);
/* Link all Transfer Descriptors in a list of available Transfer
Descriptors. */
for (i = 0; i < N_TD; i++)
u->td[i].linkptr = (grub_uint32_t) (grub_addr_t) &u->td[i + 1];
u->td[N_TD - 2].linkptr = 0;
u->tdfree = u->td;
u->td_virt[i].linkptr = u->td_phys + (i + 1) * sizeof(struct grub_uhci_td);
u->td_virt[N_TD - 2].linkptr = 0;
u->tdfree = u->td_virt;
/* Setup the frame list pointers. Since no isochronous transfers
are and will be supported, they all point to the (same!) queue
head. */
fp = (grub_uint32_t) (grub_addr_t) u->qh & (~15);
fp = u->qh_phys & (~15);
/* Mark this as a queue head. */
fp |= 2;
for (i = 0; i < 1024; i++)
u->framelist[i] = fp;
u->framelist_virt[i] = fp;
/* Program the framelist address into the UHCI controller. */
grub_uhci_writereg32 (u, GRUB_UHCI_REG_FLBASEADD,
(grub_uint32_t) (grub_addr_t) u->framelist);
grub_uhci_writereg32 (u, GRUB_UHCI_REG_FLBASEADD, u->framelist_phys);
/* Make the Queue Heads point to each other. */
for (i = 0; i < N_QH; i++)
{
/* Point to the next QH. */
u->qh[i].linkptr = (grub_uint32_t) (grub_addr_t) (&u->qh[i + 1]) & (~15);
u->qh_virt[i].linkptr = ((u->qh_phys
+ (i + 1) * sizeof(struct grub_uhci_qh))
& (~15));
/* This is a QH. */
u->qh[i].linkptr |= GRUB_UHCI_LINK_QUEUE_HEAD;
u->qh_virt[i].linkptr |= GRUB_UHCI_LINK_QUEUE_HEAD;
/* For the moment, do not point to a Transfer Descriptor. These
are set at transfer time, so just terminate it. */
u->qh[i].elinkptr = 1;
u->qh_virt[i].elinkptr = 1;
}
/* The last Queue Head should terminate. */
u->qh[N_QH - 1].linkptr = 1;
u->qh_virt[N_QH - 1].linkptr = 1;
/* Enable UHCI again. */
grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD,
@ -352,8 +340,8 @@ grub_uhci_pci_iter (grub_pci_device_t dev,
fail:
if (u)
{
grub_free ((void *) u->qh);
grub_free (u->framelist);
grub_dma_free (u->qh_chunk);
grub_dma_free (u->framelist_chunk);
}
grub_free (u);
@ -376,7 +364,7 @@ grub_alloc_td (struct grub_uhci *u)
return NULL;
ret = u->tdfree;
u->tdfree = (grub_uhci_td_t) (grub_addr_t) u->tdfree->linkptr;
u->tdfree = grub_dma_phys2virt (u->tdfree->linkptr, u->td_chunk);
return ret;
}
@ -384,7 +372,7 @@ grub_alloc_td (struct grub_uhci *u)
static void
grub_free_td (struct grub_uhci *u, grub_uhci_td_t td)
{
td->linkptr = (grub_uint32_t) (grub_addr_t) u->tdfree;
td->linkptr = grub_dma_virt2phys (u->tdfree, u->td_chunk);
u->tdfree = td;
}
@ -394,7 +382,7 @@ grub_free_queue (struct grub_uhci *u, grub_uhci_qh_t qh, grub_uhci_td_t td,
{
int i; /* Index of TD in transfer */
u->qh_busy[qh - u->qh] = 0;
u->qh_busy[qh - u->qh_virt] = 0;
*actual = 0;
@ -411,7 +399,7 @@ grub_free_queue (struct grub_uhci *u, grub_uhci_qh_t qh, grub_uhci_td_t td,
/* Unlink the queue. */
tdprev = td;
td = (grub_uhci_td_t) (grub_addr_t) td->linkptr2;
td = grub_dma_phys2virt (td->linkptr2, u->td_chunk);
/* Free the TD. */
grub_free_td (u, tdprev);
@ -439,7 +427,7 @@ grub_alloc_qh (struct grub_uhci *u,
if (!u->qh_busy[i])
break;
}
qh = &u->qh[i];
qh = &u->qh_virt[i];
if (i == N_QH)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY,
@ -447,7 +435,7 @@ grub_alloc_qh (struct grub_uhci *u,
return NULL;
}
u->qh_busy[qh - u->qh] = 1;
u->qh_busy[qh - u->qh_virt] = 1;
return qh;
}
@ -561,8 +549,8 @@ grub_uhci_setup_transfer (grub_usb_controller_t dev,
cdata->td_first = td;
else
{
td_prev->linkptr2 = (grub_uint32_t) (grub_addr_t) td;
td_prev->linkptr = (grub_uint32_t) (grub_addr_t) td;
td_prev->linkptr2 = grub_dma_virt2phys (td, u->td_chunk);
td_prev->linkptr = grub_dma_virt2phys (td, u->td_chunk);
td_prev->linkptr |= 4;
}
td_prev = td;
@ -574,7 +562,7 @@ grub_uhci_setup_transfer (grub_usb_controller_t dev,
/* Link it into the queue and terminate. Now the transaction can
take place. */
cdata->qh->elinkptr = (grub_uint32_t) (grub_addr_t) cdata->td_first;
cdata->qh->elinkptr = grub_dma_virt2phys (cdata->td_first, u->td_chunk);
grub_dprintf ("uhci", "initiate transaction\n");
@ -594,7 +582,7 @@ grub_uhci_check_transfer (grub_usb_controller_t dev,
*actual = 0;
errtd = (grub_uhci_td_t) (grub_addr_t) (cdata->qh->elinkptr & ~0x0f);
errtd = grub_dma_phys2virt (cdata->qh->elinkptr & ~0x0f, u->qh_chunk);
grub_dprintf ("uhci", ">t status=0x%02x data=0x%02x td=%p\n",
errtd->ctrl_status, errtd->buffer & (~15), errtd);