From: Vegard Nossum <vegard.nossum@oracle.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Vegard Nossum <vegard.nossum@oracle.com>,
user-mode-linux-devel@lists.sourceforge.net,
Richard Weinberger <richard@nod.at>,
James McMechan <James_McMechan@hotmail.com>,
linux-usb@vger.kernel.org, Alan Stern <stern@rowland.harvard.edu>,
Martin Schwidefsky <schwidefsky@de.ibm.com>
Subject: [uml-devel] [PATCH 1/2] usb: support building without CONFIG_HAS_DMA
Date: Mon, 15 Feb 2016 11:41:40 +0100 [thread overview]
Message-ID: <1455532901-5852-1-git-send-email-vegard.nossum@oracle.com> (raw)
Some platforms don't have DMA, but we should still be able to build
USB drivers for these platforms. They could still be used through
vhci_hcd, usbip_host, or maybe something like USB passthrough in UML
from a capable host.
This is admittedly ugly with the #ifdefs, but those are necessary to
get around linker errors like these:
drivers/built-in.o: In function `dma_unmap_sg_attrs':
include/linux/dma-mapping.h:183: undefined reference to `bad_dma_ops'
drivers/built-in.o: In function `dma_unmap_single_attrs':
include/linux/dma-mapping.h:148: undefined reference to `bad_dma_ops'
drivers/built-in.o: In function `dma_map_sg_attrs':
include/linux/dma-mapping.h:168: undefined reference to `bad_dma_ops'
drivers/built-in.o: In function `dma_map_page':
include/linux/dma-mapping.h:196: undefined reference to `bad_dma_ops'
drivers/built-in.o: In function `dma_mapping_error':
include/linux/dma-mapping.h:430: undefined reference to `bad_dma_ops'
drivers/built-in.o:include/linux/dma-mapping.h:131: more undefined references to `bad_dma_ops' follow
Greg KG suggested just defining these for UML [1] but according to
Richard Weinberger this has come up before and it was decided not to
do that just for the sake of making drivers build [2].
[1]: http://www.spinics.net/lists/linux-usb/msg136306.html
[2]: http://www.spinics.net/lists/linux-usb/msg136308.html
If any of the new warnings trigger, the correct solution is almost
certainly to add a CONFIG_HAS_DMA dependency in the Kconfig menu for
the responsible driver -- that driver's functions will hopefully
appear somewhere in the stack trace.
v2: Reduce the number of #ifdefs by moving code out into helpers.
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
---
drivers/usb/core/buffer.c | 94 ++++++++++++-----
drivers/usb/core/hcd.c | 257 ++++++++++++++++++++++++++++++++++------------
include/linux/usb/hcd.h | 6 ++
3 files changed, 266 insertions(+), 91 deletions(-)
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index 89f2e77..17f416d 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -44,6 +44,28 @@ void __init usb_init_pool_max(void)
/* SETUP primitives */
+static int _hcd_buffer_create(struct usb_hcd *hcd)
+{
+#ifdef CONFIG_HAS_DMA
+ char name[16];
+ int i, size;
+
+ for (i = 0; i < HCD_BUFFER_POOLS; i++) {
+ size = pool_max[i];
+ if (!size)
+ continue;
+ snprintf(name, sizeof(name), "buffer-%d", size);
+ hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
+ size, size, 0);
+ if (!hcd->pool[i]) {
+ hcd_buffer_destroy(hcd);
+ return -ENOMEM;
+ }
+ }
+#endif
+ return 0;
+}
+
/**
* hcd_buffer_create - initialize buffer pools
* @hcd: the bus whose buffer pools are to be initialized
@@ -59,26 +81,11 @@ void __init usb_init_pool_max(void)
*/
int hcd_buffer_create(struct usb_hcd *hcd)
{
- char name[16];
- int i, size;
-
if (!hcd->self.controller->dma_mask &&
!(hcd->driver->flags & HCD_LOCAL_MEM))
return 0;
- for (i = 0; i < HCD_BUFFER_POOLS; i++) {
- size = pool_max[i];
- if (!size)
- continue;
- snprintf(name, sizeof(name), "buffer-%d", size);
- hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
- size, size, 0);
- if (!hcd->pool[i]) {
- hcd_buffer_destroy(hcd);
- return -ENOMEM;
- }
- }
- return 0;
+ return _hcd_buffer_create(hcd);
}
@@ -91,6 +98,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
*/
void hcd_buffer_destroy(struct usb_hcd *hcd)
{
+#ifdef CONFIG_HAS_DMA
int i;
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
@@ -101,6 +109,7 @@ void hcd_buffer_destroy(struct usb_hcd *hcd)
hcd->pool[i] = NULL;
}
}
+#endif
}
@@ -108,6 +117,27 @@ void hcd_buffer_destroy(struct usb_hcd *hcd)
* better sharing and to leverage mm/slab.c intelligence.
*/
+static void *_hcd_buffer_alloc(
+ struct usb_hcd *hcd,
+ size_t size,
+ gfp_t mem_flags,
+ dma_addr_t *dma
+)
+{
+#ifdef CONFIG_HAS_DMA
+ int i;
+
+ for (i = 0; i < HCD_BUFFER_POOLS; i++) {
+ if (size <= pool_max[i])
+ return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
+ }
+ return dma_alloc_coherent(hcd->self.controller, size, dma, mem_flags);
+#else
+ WARN_ON_NO_DMA();
+ return NULL;
+#endif
+}
+
void *hcd_buffer_alloc(
struct usb_bus *bus,
size_t size,
@@ -116,7 +146,6 @@ void *hcd_buffer_alloc(
)
{
struct usb_hcd *hcd = bus_to_hcd(bus);
- int i;
/* some USB hosts just use PIO */
if (!bus->controller->dma_mask &&
@@ -125,11 +154,27 @@ void *hcd_buffer_alloc(
return kmalloc(size, mem_flags);
}
+ return _hcd_buffer_alloc(hcd, size, mem_flags, dma);
+}
+
+static void _hcd_buffer_free(
+ struct usb_hcd *hcd,
+ size_t size,
+ void *addr,
+ dma_addr_t dma
+)
+{
+#ifdef CONFIG_HAS_DMA
+ int i;
+
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
- if (size <= pool_max[i])
- return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
+ if (size <= pool_max[i]) {
+ dma_pool_free(hcd->pool[i], addr, dma);
+ return;
+ }
}
- return dma_alloc_coherent(hcd->self.controller, size, dma, mem_flags);
+ dma_free_coherent(hcd->self.controller, size, addr, dma);
+#endif
}
void hcd_buffer_free(
@@ -140,7 +185,6 @@ void hcd_buffer_free(
)
{
struct usb_hcd *hcd = bus_to_hcd(bus);
- int i;
if (!addr)
return;
@@ -151,11 +195,5 @@ void hcd_buffer_free(
return;
}
- for (i = 0; i < HCD_BUFFER_POOLS; i++) {
- if (size <= pool_max[i]) {
- dma_pool_free(hcd->pool[i], addr, dma);
- return;
- }
- }
- dma_free_coherent(hcd->self.controller, size, addr, dma);
+ _hcd_buffer_free(hcd, size, addr, dma);
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index df0e3b9..157592c 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1406,13 +1406,76 @@ static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle,
*dma_handle = 0;
}
+#ifdef CONFIG_HAS_DMA
+static void _usb_hcd_unmap_urb_setup_for_dma_single(struct usb_hcd *hcd,
+ struct urb *urb)
+{
+ dma_unmap_single(hcd->self.controller,
+ urb->setup_dma,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+}
+
+static void _usb_hcd_unmap_urb_for_dma_sg(struct usb_hcd *hcd,
+ struct urb *urb,
+ enum dma_data_direction dir)
+{
+ dma_unmap_sg(hcd->self.controller,
+ urb->sg,
+ urb->num_sgs,
+ dir);
+}
+
+static void _usb_hcd_unmap_urb_for_dma_page(struct usb_hcd *hcd,
+ struct urb *urb,
+ enum dma_data_direction dir)
+{
+ dma_unmap_page(hcd->self.controller,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ dir);
+}
+
+static void _usb_hcd_unmap_urb_for_dma_single(struct usb_hcd *hcd,
+ struct urb *urb,
+ enum dma_data_direction dir)
+{
+ dma_unmap_single(hcd->self.controller,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ dir);
+}
+
+#else /* !CONFIG_HAS_DMA */
+
+static void _usb_hcd_unmap_urb_setup_for_dma_single(struct usb_hcd *hcd,
+ struct urb *urb)
+{
+}
+
+static void _usb_hcd_unmap_urb_for_dma_sg(struct usb_hcd *hcd,
+ struct urb *urb,
+ enum dma_data_direction dir)
+{
+}
+
+static void _usb_hcd_unmap_urb_for_dma_page(struct usb_hcd *hcd,
+ struct urb *urb,
+ enum dma_data_direction dir)
+{
+}
+
+static void _usb_hcd_unmap_urb_for_dma_single(struct usb_hcd *hcd,
+ struct urb *urb,
+ enum dma_data_direction dir)
+{
+}
+#endif
+
void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
if (urb->transfer_flags & URB_SETUP_MAP_SINGLE)
- dma_unmap_single(hcd->self.controller,
- urb->setup_dma,
- sizeof(struct usb_ctrlrequest),
- DMA_TO_DEVICE);
+ _usb_hcd_unmap_urb_setup_for_dma_single(hcd, urb);
else if (urb->transfer_flags & URB_SETUP_MAP_LOCAL)
hcd_free_coherent(urb->dev->bus,
&urb->setup_dma,
@@ -1441,20 +1504,11 @@ void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
if (urb->transfer_flags & URB_DMA_MAP_SG)
- dma_unmap_sg(hcd->self.controller,
- urb->sg,
- urb->num_sgs,
- dir);
+ _usb_hcd_unmap_urb_for_dma_sg(hcd, urb, dir);
else if (urb->transfer_flags & URB_DMA_MAP_PAGE)
- dma_unmap_page(hcd->self.controller,
- urb->transfer_dma,
- urb->transfer_buffer_length,
- dir);
+ _usb_hcd_unmap_urb_for_dma_page(hcd, urb, dir);
else if (urb->transfer_flags & URB_DMA_MAP_SINGLE)
- dma_unmap_single(hcd->self.controller,
- urb->transfer_dma,
- urb->transfer_buffer_length,
- dir);
+ _usb_hcd_unmap_urb_for_dma_single(hcd, urb, dir);
else if (urb->transfer_flags & URB_MAP_LOCAL)
hcd_free_coherent(urb->dev->bus,
&urb->transfer_dma,
@@ -1477,6 +1531,124 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
}
+#ifdef CONFIG_HAS_DMA
+static int _usb_hcd_map_urb_setup_for_dma_single(struct usb_hcd *hcd,
+ struct urb *urb)
+{
+ int ret = 0;
+
+ urb->setup_dma = dma_map_single(
+ hcd->self.controller,
+ urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(hcd->self.controller,
+ urb->setup_dma))
+ ret = -EAGAIN;
+ else
+ urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
+
+ return ret;
+}
+
+static int _usb_hcd_map_urb_for_dma_sg(struct usb_hcd *hcd, struct urb *urb,
+ enum dma_data_direction dir)
+{
+ int ret = 0;
+ int n;
+
+ n = dma_map_sg(
+ hcd->self.controller,
+ urb->sg,
+ urb->num_sgs,
+ dir);
+ if (n <= 0)
+ ret = -EAGAIN;
+ else
+ urb->transfer_flags |= URB_DMA_MAP_SG;
+
+ urb->num_mapped_sgs = n;
+ if (n != urb->num_sgs)
+ urb->transfer_flags |=
+ URB_DMA_SG_COMBINED;
+
+ return ret;
+}
+
+static int _usb_hcd_map_urb_for_dma_page(struct usb_hcd *hcd, struct urb *urb,
+ enum dma_data_direction dir)
+{
+ int ret = 0;
+ struct scatterlist *sg = urb->sg;
+
+ urb->transfer_dma = dma_map_page(
+ hcd->self.controller,
+ sg_page(sg),
+ sg->offset,
+ urb->transfer_buffer_length,
+ dir);
+ if (dma_mapping_error(hcd->self.controller,
+ urb->transfer_dma))
+ ret = -EAGAIN;
+ else
+ urb->transfer_flags |= URB_DMA_MAP_PAGE;
+
+ return ret;
+}
+
+static int _usb_hcd_map_urb_for_dma_single(struct usb_hcd *hcd,
+ struct urb *urb,
+ enum dma_data_direction dir)
+{
+ int ret = 0;
+
+ urb->transfer_dma = dma_map_single(
+ hcd->self.controller,
+ urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ dir);
+ if (dma_mapping_error(hcd->self.controller,
+ urb->transfer_dma))
+ ret = -EAGAIN;
+ else
+ urb->transfer_flags |= URB_DMA_MAP_SINGLE;
+
+ return ret;
+}
+
+
+#else /* !CONFIG_HAS_DMA */
+
+static int _usb_hcd_map_urb_setup_for_dma_single(struct usb_hcd *hcd,
+ struct urb *urb)
+{
+ WARN_ON_NO_DMA();
+ return -EINVAL;
+}
+
+static int _usb_hcd_map_urb_for_dma_sg(struct usb_hcd *hcd, struct urb *urb,
+ enum dma_data_direction dir)
+{
+ WARN_ON_NO_DMA();
+ return -EINVAL;
+}
+
+static int _usb_hcd_map_urb_for_dma_page(struct usb_hcd *hcd, struct urb *urb,
+ enum dma_data_direction dir)
+{
+ WARN_ON_NO_DMA();
+ return -EINVAL;
+}
+
+static int _usb_hcd_map_urb_for_dma_single(struct usb_hcd *hcd,
+ struct urb *urb,
+ enum dma_data_direction dir)
+{
+ WARN_ON_NO_DMA();
+ return -EINVAL;
+}
+#endif
+
int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags)
{
@@ -1493,15 +1665,9 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
if (hcd->self.uses_pio_for_control)
return ret;
if (hcd->self.uses_dma) {
- urb->setup_dma = dma_map_single(
- hcd->self.controller,
- urb->setup_packet,
- sizeof(struct usb_ctrlrequest),
- DMA_TO_DEVICE);
- if (dma_mapping_error(hcd->self.controller,
- urb->setup_dma))
- return -EAGAIN;
- urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
+ ret = _usb_hcd_map_urb_setup_for_dma_single(hcd, urb);
+ if (ret)
+ return ret;
} else if (hcd->driver->flags & HCD_LOCAL_MEM) {
ret = hcd_alloc_coherent(
urb->dev->bus, mem_flags,
@@ -1520,54 +1686,19 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
if (hcd->self.uses_dma) {
if (urb->num_sgs) {
- int n;
-
/* We don't support sg for isoc transfers ! */
if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
WARN_ON(1);
return -EINVAL;
}
-
- n = dma_map_sg(
- hcd->self.controller,
- urb->sg,
- urb->num_sgs,
- dir);
- if (n <= 0)
- ret = -EAGAIN;
- else
- urb->transfer_flags |= URB_DMA_MAP_SG;
- urb->num_mapped_sgs = n;
- if (n != urb->num_sgs)
- urb->transfer_flags |=
- URB_DMA_SG_COMBINED;
+ ret = _usb_hcd_map_urb_for_dma_sg(hcd, urb, dir);
} else if (urb->sg) {
- struct scatterlist *sg = urb->sg;
- urb->transfer_dma = dma_map_page(
- hcd->self.controller,
- sg_page(sg),
- sg->offset,
- urb->transfer_buffer_length,
- dir);
- if (dma_mapping_error(hcd->self.controller,
- urb->transfer_dma))
- ret = -EAGAIN;
- else
- urb->transfer_flags |= URB_DMA_MAP_PAGE;
+ ret = _usb_hcd_map_urb_for_dma_page(hcd, urb, dir);
} else if (is_vmalloc_addr(urb->transfer_buffer)) {
WARN_ONCE(1, "transfer buffer not dma capable\n");
ret = -EAGAIN;
} else {
- urb->transfer_dma = dma_map_single(
- hcd->self.controller,
- urb->transfer_buffer,
- urb->transfer_buffer_length,
- dir);
- if (dma_mapping_error(hcd->self.controller,
- urb->transfer_dma))
- ret = -EAGAIN;
- else
- urb->transfer_flags |= URB_DMA_MAP_SINGLE;
+ ret = _usb_hcd_map_urb_for_dma_single(hcd, urb, dir);
}
} else if (hcd->driver->flags & HCD_LOCAL_MEM) {
ret = hcd_alloc_coherent(
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 4dcf844..1e90e59 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -409,6 +409,12 @@ static inline bool hcd_periodic_completion_in_progress(struct usb_hcd *hcd,
return hcd->high_prio_bh.completing_ep == ep;
}
+#ifndef CONFIG_HAS_DMA
+/* If this ever triggers, the correct fix is almost certainly
+ * to add a CONFIG_HAS_DMA dependency in the Kconfig for that driver. */
+#define WARN_ON_NO_DMA() WARN_ONCE(1, "HCD driver tried to use DMA memory")
+#endif
+
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
int status);
--
1.9.1
------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance
APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month
Monitor end-to-end web transactions and take corrective actions now
Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140
_______________________________________________
User-mode-linux-devel mailing list
User-mode-linux-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/user-mode-linux-devel
next reply other threads:[~2016-02-15 10:42 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-02-15 10:41 Vegard Nossum [this message]
2016-02-15 10:41 ` [uml-devel] [PATCH 2/2] usb: remove HAS_IOMEM dependency from USB_SUPPORT Vegard Nossum
2016-02-15 11:17 ` [uml-devel] [PATCH 1/2] usb: support building without CONFIG_HAS_DMA Geert Uytterhoeven
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1455532901-5852-1-git-send-email-vegard.nossum@oracle.com \
--to=vegard.nossum@oracle.com \
--cc=James_McMechan@hotmail.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-usb@vger.kernel.org \
--cc=richard@nod.at \
--cc=schwidefsky@de.ibm.com \
--cc=stern@rowland.harvard.edu \
--cc=user-mode-linux-devel@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).