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> 2012-02-09 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/video/colors.c (grub_video_parse_color): Fix error message. * grub-core/video/colors.c (grub_video_parse_color): Fix error message.

View file

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