]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
separate function to allocate DMA memory
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 5 May 2010 08:40:48 +0000 (10:40 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 5 May 2010 08:40:48 +0000 (10:40 +0200)
bus/pci.c
bus/usb/ohci.c
bus/usb/uhci.c
bus/usb/usbtrans.c
include/grub/pci.h
include/grub/usbtrans.h
kern/misc.c

index a08e53446106e7c19662967cc5897d1c41162a1d..2fe9d764ee07517b984bc55b8edc09b747b87e1a 100644 (file)
--- a/bus/pci.c
+++ b/bus/pci.c
 
 #include <grub/dl.h>
 #include <grub/pci.h>
+#include <grub/mm.h>
+
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
+struct grub_pci_dma_chunk *
+grub_memalign_dma32 (grub_size_t align, grub_size_t size)
+{
+  return grub_memalign (align, size);
+}
+
+void
+grub_dma_free (struct grub_pci_dma_chunk *ch)
+{
+  grub_free (ch);
+}
+#endif
+
+#ifdef GRUB_MACHINE_MIPS_YEELOONG
+void *
+grub_dma_get_virt (struct grub_pci_dma_chunk *ch)
+{
+  return (void *) ((((grub_uint32_t) ch) & 0x1fffffff) | 0xa0000000);
+}
+
+grub_uint32_t
+grub_dma_get_phys (struct grub_pci_dma_chunk *ch)
+{
+  return ((grub_uint32_t) ch) & 0x1fffffff;
+}
+#else
+
+void *
+grub_dma_get_virt (struct grub_pci_dma_chunk *ch)
+{
+  return (void *) ch;
+}
+
+grub_uint32_t
+grub_dma_get_phys (struct grub_pci_dma_chunk *ch)
+{
+  return (grub_uint32_t) ch;
+}
+
+#endif
 
 grub_pci_address_t
 grub_pci_make_address (grub_pci_device_t dev, int reg)
index de20a1491773bc79d451a404a56b6dbdfe95eb87..81ce3294d1ef974b421fa99ae26ef4dee932def5 100644 (file)
@@ -72,6 +72,7 @@ struct grub_ohci
   volatile grub_uint32_t *iobase;
   volatile struct grub_ohci_hcca *hcca;
   grub_uint32_t hcca_addr;
+  struct grub_pci_dma_chunk *hcca_chunk;
   struct grub_ohci *next;
 };
 
@@ -136,7 +137,6 @@ grub_ohci_pci_iter (grub_pci_device_t dev,
   grub_uint32_t revision;
   grub_uint32_t frame_interval;
   int cs5536;
-  grub_uint32_t hcca_addr;
 
   /* Determine IO base address.  */
   grub_dprintf ("ohci", "pciid = %x\n", pciid);
@@ -157,7 +157,6 @@ grub_ohci_pci_iter (grub_pci_device_t dev,
       basereg &= ~GRUB_CS5536_MSR_USB_BASE_PME_ENABLED;
       basereg &= ~GRUB_CS5536_MSR_USB_BASE_PME_STATUS;
       grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_USB_OHCI_BASE, basereg);
-
     }
   else
     {
@@ -198,14 +197,12 @@ grub_ohci_pci_iter (grub_pci_device_t dev,
 
   grub_dprintf ("ohci", "base=%p\n", o->iobase);
 
-  /* FIXME: create proper abstraction for this.  */
-#ifdef GRUB_MACHINE_MIPS_YEELOONG
-  hcca_addr = 0x05000100;
-#else
   /* Reserve memory for the HCCA.  */
-  hcca_addr = (grub_uint32_t) grub_memalign (256, 256);
-#endif
-  o->hcca = grub_pci_device_map_range (dev, hcca_addr, 256);
+  o->hcca_chunk = grub_memalign_dma32 (256, 256);
+  if (! o->hcca_chunk)
+    return 1;
+  o->hcca = grub_dma_get_virt (o->hcca_chunk);
+  o->hcca_addr = grub_dma_get_phys (o->hcca_chunk);
 
   /* Check if the OHCI revision is actually 1.0 as supported.  */
   revision = grub_ohci_readreg32 (o, GRUB_OHCI_REG_REVISION);
@@ -236,7 +233,7 @@ grub_ohci_pci_iter (grub_pci_device_t dev,
                        GRUB_OHCI_PERIODIC_START);
 
   /* Setup the HCCA.  */
-  grub_ohci_writereg32 (o, GRUB_OHCI_REG_HCCA, hcca_addr);
+  grub_ohci_writereg32 (o, GRUB_OHCI_REG_HCCA, o->hcca_addr);
   grub_dprintf ("ohci", "OHCI HCCA\n");
 
   /* Enable the OHCI.  */
@@ -289,7 +286,7 @@ grub_ohci_iterate (int (*hook) (grub_usb_controller_t dev))
 static void
 grub_ohci_transaction (grub_ohci_td_t td,
                       grub_transfer_type_t type, unsigned int toggle,
-                      grub_size_t size, char *data)
+                      grub_size_t size, grub_uint32_t data)
 {
   grub_uint32_t token;
   grub_uint32_t buffer;
@@ -321,7 +318,7 @@ grub_ohci_transaction (grub_ohci_td_t td,
   token |= toggle << 24;
   token |= 1 << 25;
 
-  buffer = (grub_uint32_t) data;
+  buffer = data;
   buffer_end = buffer + size - 1;
 
   td->token = grub_cpu_to_le32 (token);
@@ -336,7 +333,10 @@ grub_ohci_transfer (grub_usb_controller_t dev,
 {
   struct grub_ohci *o = (struct grub_ohci *) dev->data;
   grub_ohci_ed_t ed;
+  grub_uint32_t ed_addr;
+  struct grub_pci_dma_chunk *ed_chunk, *td_list_chunk;
   grub_ohci_td_t td_list;
+  grub_uint32_t td_list_addr;
   grub_uint32_t target;
   grub_uint32_t td_tail;
   grub_uint32_t td_head;
@@ -346,18 +346,23 @@ grub_ohci_transfer (grub_usb_controller_t dev,
   int i;
 
   /* Allocate an Endpoint Descriptor.  */
-  ed = grub_memalign (16, sizeof (*ed));
-  if (! ed)
+  ed_chunk = grub_memalign_dma32 (256, sizeof (*ed));
+  if (! ed_chunk)
     return GRUB_USB_ERR_INTERNAL;
+  ed = grub_dma_get_virt (ed_chunk);
+  ed_addr = grub_dma_get_phys (ed_chunk);
 
-  td_list = grub_memalign (16, sizeof (*td_list) * (transfer->transcnt + 1));
-  if (! td_list)
+  td_list_chunk = grub_memalign_dma32 (256, sizeof (*td_list)
+                                      * (transfer->transcnt + 1));
+  if (! td_list_chunk)
     {
-      grub_free ((void *) ed);
+      grub_dma_free (ed_chunk);
       return GRUB_USB_ERR_INTERNAL;
     }
+  td_list = grub_dma_get_virt (td_list_chunk);
+  td_list_addr = grub_dma_get_phys (td_list_chunk);
 
-  grub_dprintf ("ohci", "alloc=%p\n", td_list);
+  grub_dprintf ("ohci", "alloc=%p/0x%x\n", td_list, td_list_addr);
 
   /* Setup all Transfer Descriptors.  */
   for (i = 0; i < transfer->transcnt; i++)
@@ -367,7 +372,8 @@ grub_ohci_transfer (grub_usb_controller_t dev,
       grub_ohci_transaction (&td_list[i], tr->pid, tr->toggle,
                             tr->size, tr->data);
 
-      td_list[i].next_td = grub_cpu_to_le32 (&td_list[i + 1]);
+      td_list[i].next_td = grub_cpu_to_le32 (td_list_addr
+                                            + (i + 1) * sizeof (td_list[0]));
     }
 
   /* Setup the Endpoint Descriptor.  */
@@ -384,9 +390,9 @@ grub_ohci_transfer (grub_usb_controller_t dev,
   /* Set the maximum packet size.  */
   target |= transfer->max << 16;
 
-  td_head = (grub_uint32_t) td_list;
+  td_head = td_list_addr;
 
-  td_tail = (grub_uint32_t) &td_list[transfer->transcnt];
+  td_tail = td_list_addr + transfer->transcnt * sizeof (*td_list);
 
   ed->target = grub_cpu_to_le32 (target);
   ed->td_head = grub_cpu_to_le32 (td_head);
@@ -413,7 +419,7 @@ grub_ohci_transfer (grub_usb_controller_t dev,
        status &= ~(1 << 2);
        grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status);
 
-       grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, (grub_uint32_t) ed);
+       grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, ed_addr);
 
        /* Enable the Bulk list.  */
        control |= 1 << 5;
@@ -440,10 +446,9 @@ grub_ohci_transfer (grub_usb_controller_t dev,
        status &= ~(1 << 1);
        grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status);
 
-       grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD,
-                             (grub_uint32_t) ed);
+       grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, ed_addr);
        grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD+1,
-                             (grub_uint32_t) ed);
+                             ed_addr);
 
        /* Enable the Control list.  */
        control |= 1 << 4;
@@ -484,9 +489,12 @@ grub_ohci_transfer (grub_usb_controller_t dev,
     {
       grub_uint8_t errcode;
       grub_ohci_td_t tderr;
+      grub_uint32_t td_err_addr;
+
+      td_err_addr = grub_ohci_readreg32 (o, GRUB_OHCI_REG_DONEHEAD);
 
-      tderr = (grub_ohci_td_t) grub_ohci_readreg32 (o,
-                                                   GRUB_OHCI_REG_DONEHEAD);
+      tderr = (grub_ohci_td_t) ((char *) td_list
+                               + (td_err_addr - td_list_addr));
       errcode = tderr->token >> 28;
 
       switch (errcode)
index 947f2367b22179821ff5a690494dc5aaafc5059b..6e47c38eff8e8e78c8093a4585c7b0a3b5e734d4 100644 (file)
@@ -380,7 +380,7 @@ static grub_uhci_td_t
 grub_uhci_transaction (struct grub_uhci *u, unsigned int endp,
                       grub_transfer_type_t type, unsigned int addr,
                       unsigned int toggle, grub_size_t size,
-                      char *data)
+                      grub_uint32_t data)
 {
   grub_uhci_td_t td;
   static const unsigned int tf[] = { 0x69, 0xE1, 0x2D };
@@ -398,7 +398,7 @@ grub_uhci_transaction (struct grub_uhci *u, unsigned int endp,
     }
 
   grub_dprintf ("uhci",
-               "transaction: endp=%d, type=%d, addr=%d, toggle=%d, size=%d data=%p td=%p\n",
+               "transaction: endp=%d, type=%d, addr=%d, toggle=%d, size=%d data=0x%x td=%p\n",
                endp, type, addr, toggle, size, data, td);
 
   /* Don't point to any TD, just terminate.  */
@@ -418,7 +418,7 @@ grub_uhci_transaction (struct grub_uhci *u, unsigned int endp,
   td->token = ((size << 21) | (toggle << 19) | (endp << 15)
               | (addr << 8) | tf[type]);
 
-  td->buffer = (grub_uint32_t) data;
+  td->buffer = data;
 
   return td;
 }
index 09e7af83e1963531f35d4d5982b27de3e83cd9c8..f59d5ec77cbe04ad697606b0127f008e2aea397f 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <grub/dl.h>
+#include <grub/pci.h>
 #include <grub/mm.h>
 #include <grub/misc.h>
 #include <grub/usb.h>
@@ -29,30 +30,59 @@ grub_usb_control_msg (grub_usb_device_t dev,
                      grub_uint8_t request,
                      grub_uint16_t value,
                      grub_uint16_t index,
-                     grub_size_t size, char *data)
+                     grub_size_t size0, char *data_in)
 {
   int i;
   grub_usb_transfer_t transfer;
   int datablocks;
-  struct grub_usb_packet_setup setupdata;
+  struct grub_usb_packet_setup *setupdata;
+  grub_uint32_t setupdata_addr;
   grub_usb_err_t err;
   unsigned int max;
+  struct grub_pci_dma_chunk *data_chunk, *setupdata_chunk;
+  char *data;
+  grub_uint32_t data_addr;
+  grub_size_t size = size0;
+
+  /* FIXME: avoid allocation any kind of buffer in a first place.  */
+  data_chunk = grub_memalign_dma32 (128, size ? : 16);
+  if (!data_chunk)
+    return GRUB_USB_ERR_INTERNAL;
+  data = grub_dma_get_virt (data_chunk);
+  data_addr = grub_dma_get_phys (data_chunk);
+  grub_memcpy (data, data_in, size);
 
   grub_dprintf ("usb",
                "control: reqtype=0x%02x req=0x%02x val=0x%02x idx=0x%02x size=%d\n",
                reqtype, request,  value, index, size);
 
   /* Create a transfer.  */
-  transfer = grub_malloc (sizeof (struct grub_usb_transfer));
+  transfer = grub_malloc (sizeof (*transfer));
   if (! transfer)
-    return grub_errno;
+    {
+      grub_dma_free (data_chunk);
+      return grub_errno;
+    }
+
+  setupdata_chunk = grub_memalign_dma32 (32, sizeof (*setupdata));
+  if (! setupdata_chunk)
+    {
+      grub_free (transfer);
+      grub_dma_free (data_chunk);
+      return grub_errno;
+    }
+
+  setupdata = grub_dma_get_virt (setupdata_chunk);
+  setupdata_addr = grub_dma_get_phys (setupdata_chunk);
 
   /* Determine the maximum packet size.  */
-  if (dev->initialized)
+  if (dev->initialized && dev->descdev.maxsize0)
     max = dev->descdev.maxsize0;
   else
     max = 64;
 
+  grub_dprintf ("usb", "transfer = %p, dev = %p\n", transfer, dev);
+
   datablocks = (size + max - 1) / max;
 
   /* XXX: Discriminate between different types of control
@@ -71,18 +101,20 @@ grub_usb_control_msg (grub_usb_device_t dev,
   if (! transfer->transactions)
     {
       grub_free (transfer);
+      grub_dma_free (setupdata_chunk);
+      grub_dma_free (data_chunk);
       return grub_errno;
     }
 
   /* Build a Setup packet.  XXX: Endianness.  */
-  setupdata.reqtype = reqtype;
-  setupdata.request = request;
-  setupdata.value = value;
-  setupdata.index = index;
-  setupdata.length = size;
-  transfer->transactions[0].size = sizeof (setupdata);
+  setupdata->reqtype = reqtype;
+  setupdata->request = request;
+  setupdata->value = value;
+  setupdata->index = index;
+  setupdata->length = size;
+  transfer->transactions[0].size = sizeof (*setupdata);
   transfer->transactions[0].pid = GRUB_USB_TRANSFER_TYPE_SETUP;
-  transfer->transactions[0].data = (char *) &setupdata;
+  transfer->transactions[0].data = setupdata_addr;
   transfer->transactions[0].toggle = 0;
 
   /* Now the data...  XXX: Is this the right way to transfer control
@@ -99,13 +131,13 @@ grub_usb_control_msg (grub_usb_device_t dev,
        tr->pid = GRUB_USB_TRANSFER_TYPE_IN;
       else
        tr->pid = GRUB_USB_TRANSFER_TYPE_OUT;
-      tr->data = &data[i * max];
+      tr->data = data_addr + i * max;
       size -= max;
     }
 
   /* End with an empty OUT transaction.  */
   transfer->transactions[datablocks + 1].size = 0;
-  transfer->transactions[datablocks + 1].data = NULL;
+  transfer->transactions[datablocks + 1].data = 0;
   if (reqtype & 128)
     transfer->transactions[datablocks + 1].pid = GRUB_USB_TRANSFER_TYPE_OUT;
   else
@@ -117,13 +149,17 @@ grub_usb_control_msg (grub_usb_device_t dev,
 
   grub_free (transfer->transactions);
   grub_free (transfer);
+  grub_dma_free (data_chunk);
+  grub_dma_free (setupdata_chunk);
+
+  grub_memcpy (data_in, data, size0);
 
   return err;
 }
 
 static grub_usb_err_t
 grub_usb_bulk_readwrite (grub_usb_device_t dev,
-                        int endpoint, grub_size_t size, char *data,
+                        int endpoint, grub_size_t size0, char *data_in,
                         grub_transfer_type_t type)
 {
   int i;
@@ -132,6 +168,19 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev,
   unsigned int max;
   grub_usb_err_t err;
   int toggle = dev->toggle[endpoint];
+  char *data;
+  grub_uint32_t data_addr;
+  struct grub_pci_dma_chunk *data_chunk;
+  grub_size_t size = size0;
+
+  /* FIXME: avoid allocation any kind of buffer in a first place.  */
+  data_chunk = grub_memalign_dma32 (128, size);
+  if (!data_chunk)
+    return GRUB_USB_ERR_INTERNAL;
+  data = grub_dma_get_virt (data_chunk);
+  data_addr = grub_dma_get_phys (data_chunk);
+  if (type == GRUB_USB_TRANSFER_TYPE_OUT)
+    grub_memcpy (data, data_in, size);
 
   /* Use the maximum packet size given in the endpoint descriptor.  */
   if (dev->initialized)
@@ -150,7 +199,10 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev,
   /* Create a transfer.  */
   transfer = grub_malloc (sizeof (struct grub_usb_transfer));
   if (! transfer)
-    return grub_errno;
+    {
+      grub_dma_free (data_chunk);
+      return grub_errno;
+    }
 
   datablocks = ((size + max - 1) / max);
   transfer->transcnt = datablocks;
@@ -167,6 +219,7 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev,
   if (! transfer->transactions)
     {
       grub_free (transfer);
+      grub_dma_free (data_chunk);
       return grub_errno;
     }
 
@@ -181,7 +234,7 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev,
       tr->toggle = toggle;
       toggle = toggle ? 0 : 1;
       tr->pid = type;
-      tr->data = &data[i * max];
+      tr->data = data_addr + i * max;
       size -= tr->size;
     }
 
@@ -191,6 +244,10 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev,
 
   grub_free (transfer->transactions);
   grub_free (transfer);
+  grub_dma_free (data_chunk);
+
+  if (type == GRUB_USB_TRANSFER_TYPE_IN)
+    grub_memcpy (data_in, data, size0);
 
   return err;
 }
index 8a653c43ec17740040751396efbde7e881664f99..fff4d3e3a78ca5aecb3e65c5a9fb09686d528445 100644 (file)
@@ -109,6 +109,15 @@ grub_pci_address_t EXPORT_FUNC(grub_pci_make_address) (grub_pci_device_t dev,
                                                       int reg);
 
 void EXPORT_FUNC(grub_pci_iterate) (grub_pci_iteratefunc_t hook);
+
+struct grub_pci_dma_chunk;
+
+struct grub_pci_dma_chunk *EXPORT_FUNC(grub_memalign_dma32) (grub_size_t align,
+                                                            grub_size_t size);
+void EXPORT_FUNC(grub_dma_free) (struct grub_pci_dma_chunk *ch);
+void *EXPORT_FUNC(grub_dma_get_virt) (struct grub_pci_dma_chunk *ch);
+grub_uint32_t EXPORT_FUNC(grub_dma_get_phys) (struct grub_pci_dma_chunk *ch);
+
 #endif
 
 #endif /* GRUB_PCI_H */
index 7e4a9d7ee706dfc8bb9a3f947592f946fc48b15c..8c739684e212e9b1811632c96d88c142d8ce85fd 100644 (file)
@@ -37,7 +37,7 @@ struct grub_usb_transaction
   int size;
   int toggle;
   grub_transfer_type_t pid;
-  char *data;
+  grub_uint32_t data;
 };
 typedef struct grub_usb_transaction *grub_usb_transaction_t;
 
index 9d8fc70da1b189fd6ea909dc2767d0fa4954404e..e86043c15f3f1bc893b5dc19ed298852f6b03aa3 100644 (file)
@@ -189,7 +189,7 @@ grub_real_dprintf (const char *file, const int line, const char *condition,
   const char *debug = grub_env_get ("debug");
 
   if (! debug)
-    return;
+    debug = "usb,ohci";
 
   if (grub_strword (debug, "all") || grub_strword (debug, condition))
     {
@@ -197,6 +197,7 @@ grub_real_dprintf (const char *file, const int line, const char *condition,
       va_start (args, fmt);
       grub_vprintf (fmt, args);
       va_end (args);
+      grub_refresh ();
     }
 }