1// -*- Mode: C++ -*-
2// vim:ft=cpp
3/**
4 * \file
5 */
6/*
7 * (c) 2014 Alexander Warg <alexander.warg@kernkonzept.com>
8 *
9 * This file is part of TUD:OS and distributed under the terms of the
10 * GNU General Public License 2.
11 * Please see the COPYING-GPL-2 file for details.
12 *
13 * As a special exception, you may use this file as part of a free software
14 * library without restriction.  Specifically, if other files instantiate
15 * templates or use macros or inline functions from this file, or you compile
16 * this file and link it with other files to produce an executable, this
17 * file does not by itself cause the resulting executable to be covered by
18 * the GNU General Public License.  This exception does not however
19 * invalidate any other reasons why the executable file might be covered by
20 * the GNU General Public License.
21 */
22
23#pragma once
24
25#include <l4/sys/types.h>
26#include <l4/sys/l4int.h>
27#include <l4/sys/capability>
28#include <l4/re/dataspace>
29#include <l4/re/protocols.h>
30#include <l4/sys/cxx/types>
31#include <l4/sys/cxx/ipc_types>
32#include <l4/sys/cxx/ipc_iface>
33
34namespace L4Re
35{
36
37/**
38 * DMA Address Space.
39 *
40 * A Dma_space represents the DMA address space of a device.
41 * Whenever a device needs direct access to parts of an L4Re::Dataspace, that
42 * part of the data space must be mapped to the DMA address space that is
43 * assigned to that device. After the DMA accesses to the memory are finished
44 * the memory must be unmapped from the device's DMA address space.
45 *
46 * Mapping to a DMA address space, using map(), makes the given parts of
47 * the data space visible to the associated device at the returned
48 * DMA address.  As long as the memory is mapped into a DMA space it is 'pinned'
49 * and cannot be subject to dynamic memory management such as swapping.
50 * Additionally, map() is responsible for the necessary syncing operations before
51 * the DMA.
52 *
53 * unmap() is the reverse operation to map() and unmaps the given
54 * data-space part for the DMA address space. unmap() is responsible for the
55 * necessary sync operations after the DMA.
56 */
57class Dma_space :
58  public L4::Kobject_0t< Dma_space,
59                         L4RE_PROTO_DMA_SPACE,
60                         L4::Type_info::Demand_t<1> >
61{
62public:
63  /// Data type for DMA addresses.
64  typedef l4_uint64_t Dma_addr;
65
66  /**
67   * Direction of the DMA transfers
68   */
69  enum Direction
70  {
71    Bidirectional, ///< device reads and writes to the memory
72    To_device,     ///< device reads the memory
73    From_device,   ///< device writes to the memory
74    None           ///< device is coherently connected to the memory
75  };
76
77  /**
78   * Attributes used for the memory region during the transfer.
79   * \sa Attributes
80   */
81  enum Attribute
82  {
83    /**
84     * Do not sync the memory hierarchy.
85     *
86     * When this flag is _not set_ (default) the memory region shall be made
87     * coherent to the point-of-coherency of the device associated with this
88     * Dma_space.
89     * When using this attribute the client is responsible for syncing the
90     * memory hierarchy for DMA. This can either be done using the cache API
91     * or by another map() or unmap() operation of the same part of the data
92     * space (without the #No_sync attribute).
93     */
94    No_sync
95  };
96
97  /**
98   * Attributes for DMA mappings.
99   *
100   * \sa Attribute
101   */
102  typedef L4::Types::Flags<Attribute> Attributes;
103
104  /**
105   * Attributes assigned to the DMA space when associated with a
106   * specific device.
107   * \sa Space_attribs
108   */
109  enum Space_attrib
110  {
111    /**
112     * The device is connected coherently with the cache.
113     *
114     * This means that the map() and unmap() do not need to sync
115     * CPU caches before and after DMA.
116     */
117    Coherent,
118
119    /**
120     * The DMA space has no DMA task assigned and uses the CPUs
121     * physical memory.
122     */
123    Phys_space
124  };
125
126  /// Attributes used when configuring the DMA space.
127  typedef L4::Types::Flags<Space_attrib> Space_attribs;
128
129  /**
130   * Map the given part of this data space into the DMA address space.
131   *
132   * \caprights{R}
133   * \param[in]     src      Source data space (that describes the memory).
134   *                         Caller needs write rights to the data space.
135   * \param[in]     offset   The offset (bytes) within `src`.
136   * \param[in,out] size     The size (bytes) of the region to be mapped
137   *                         for DMA, after successful mapping the size
138   *                         returned is the size mapped for DMA as a single
139   *                         block. This size might be smaller than the
140   *                         original input size, in this case the caller might
141   *                         call map() again with a new offset and the
142   *                         remaining size.
143   * \param[in]     attrs    The attributes used for this DMA mapping
144   *                         (a combination of Dma_space::Attribute values).
145   * \param[in]     dir      The direction of the DMA transfer issued with
146   *                         this mapping. The same value must later be passed
147   *                         to unmap().
148   * \param[out]    dma_addr The DMA address to use for DMA with the associated
149   *                         device.
150   *
151   * \return 0 in the case of success, a negative error code otherwise.
152   */
153  L4_INLINE_RPC(
154      long, map, (L4::Ipc::Cap<L4Re::Dataspace> src,
155                  L4Re::Dataspace::Offset offset,
156                  L4::Ipc::In_out<l4_size_t *> size,
157                  Attributes attrs, Direction dir,
158                  Dma_addr *dma_addr));
159
160  /**
161   * Unmap the given part of this data space from the DMA address space.
162   * \caprights{R}
163   * \param dma_addr  The DMA address (returned by Dma_space::map()).
164   * \param size      The size (bytes) of the memory region to unmap.
165   * \param attrs     The attributes for the unmap (currently none).
166   * \param dir       The direction of the finished DMA operation.
167   */
168  L4_INLINE_RPC(
169      long, unmap, (Dma_addr dma_addr,
170                    l4_size_t size, Attributes attrs, Direction dir));
171
172  /**
173   * Associate a DMA task for a device to this Dma_space.
174   *
175   * \caprights{RW}
176   * \param[in]  dma_task  The DMA task used for the device that shall be
177   *                       associated with this DMA space. The dma_task might
178   *                       be an invalid capability when
179   *                       L4Re::Dma_space::Phys_space is set in
180   *                       `attr`, in this case the CPUs physical memory
181   *                       is used as DMA address space.
182   * \param[in]  attr      Attributes for this DMA space. See
183   *                       L4Re::Dma_space::Space_attrib.
184   */
185  L4_INLINE_RPC(
186      long, associate, (L4::Ipc::Opt<L4::Ipc::Cap<L4::Task> > dma_task,
187                        Space_attribs attr),
188      L4::Ipc::Call_t<L4_CAP_FPAGE_RW>);
189
190  /**
191   * Disassociate the DMA task from this Dma_space.
192   *
193   * \caprights{RW}
194   */
195  L4_INLINE_RPC(
196      long, disassociate, (),
197      L4::Ipc::Call_t<L4_CAP_FPAGE_RW>);
198
199  typedef L4::Typeid::Rpcs<map_t, unmap_t, associate_t, disassociate_t> Rpcs;
200};
201
202}
203