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:
parent
432069398f
commit
01783768d2
2 changed files with 63 additions and 63 deletions
12
ChangeLog
12
ChangeLog
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue