1f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/*
2f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Copyright (c) 2006, 2009, 2010 QLogic, Corporation. All rights reserved.
3f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *
4f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * This software is available to you under a choice of one of two
5f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * licenses.  You may choose to be licensed under the terms of the GNU
6f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * General Public License (GPL) Version 2, available from the file
7f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * COPYING in the main directory of this source tree, or the
8f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * OpenIB.org BSD license below:
9f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *
10f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *     Redistribution and use in source and binary forms, with or
11f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *     without modification, are permitted provided that the following
12f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *     conditions are met:
13f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *
14f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *      - Redistributions of source code must retain the above
15f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *        copyright notice, this list of conditions and the following
16f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *        disclaimer.
17f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *
18f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *      - Redistributions in binary form must reproduce the above
19f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *        copyright notice, this list of conditions and the following
20f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *        disclaimer in the documentation and/or other materials
21f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *        provided with the distribution.
22f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *
23f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * SOFTWARE.
31f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */
32f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell#include <linux/types.h>
33f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell#include <linux/scatterlist.h>
34f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
35f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell#include "qib_verbs.h"
36f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
37f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell#define BAD_DMA_ADDRESS ((u64) 0)
38f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
39f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/*
40f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * The following functions implement driver specific replacements
41f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * for the ib_dma_*() functions.
42f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *
43f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * These functions return kernel virtual addresses instead of
44f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * device bus addresses since the driver uses the CPU to copy
45f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * data instead of using hardware DMA.
46f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */
47f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
48f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic int qib_mapping_error(struct ib_device *dev, u64 dma_addr)
49f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{
50f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	return dma_addr == BAD_DMA_ADDRESS;
51f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}
52f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
53f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic u64 qib_dma_map_single(struct ib_device *dev, void *cpu_addr,
54f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell			      size_t size, enum dma_data_direction direction)
55f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{
56f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	BUG_ON(!valid_dma_direction(direction));
57f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	return (u64) cpu_addr;
58f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}
59f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
60f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic void qib_dma_unmap_single(struct ib_device *dev, u64 addr, size_t size,
61f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell				 enum dma_data_direction direction)
62f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{
63f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	BUG_ON(!valid_dma_direction(direction));
64f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}
65f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
66f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic u64 qib_dma_map_page(struct ib_device *dev, struct page *page,
67f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell			    unsigned long offset, size_t size,
68f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell			    enum dma_data_direction direction)
69f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{
70f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	u64 addr;
71f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
72f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	BUG_ON(!valid_dma_direction(direction));
73f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
74f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	if (offset + size > PAGE_SIZE) {
75f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell		addr = BAD_DMA_ADDRESS;
76f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell		goto done;
77f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	}
78f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
79f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	addr = (u64) page_address(page);
80f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	if (addr)
81f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell		addr += offset;
82f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	/* TODO: handle highmem pages */
83f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
84f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbelldone:
85f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	return addr;
86f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}
87f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
88f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic void qib_dma_unmap_page(struct ib_device *dev, u64 addr, size_t size,
89f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell			       enum dma_data_direction direction)
90f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{
91f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	BUG_ON(!valid_dma_direction(direction));
92f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}
93f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
94f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic int qib_map_sg(struct ib_device *dev, struct scatterlist *sgl,
95f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell		      int nents, enum dma_data_direction direction)
96f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{
97f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	struct scatterlist *sg;
98f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	u64 addr;
99f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	int i;
100f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	int ret = nents;
101f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
102f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	BUG_ON(!valid_dma_direction(direction));
103f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
104f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	for_each_sg(sgl, sg, nents, i) {
105f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell		addr = (u64) page_address(sg_page(sg));
106f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell		/* TODO: handle highmem pages */
107f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell		if (!addr) {
108f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell			ret = 0;
109f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell			break;
110f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell		}
111f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	}
112f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	return ret;
113f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}
114f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
115f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic void qib_unmap_sg(struct ib_device *dev,
116f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell			 struct scatterlist *sg, int nents,
117f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell			 enum dma_data_direction direction)
118f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{
119f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	BUG_ON(!valid_dma_direction(direction));
120f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}
121f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
122f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic u64 qib_sg_dma_address(struct ib_device *dev, struct scatterlist *sg)
123f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{
124f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	u64 addr = (u64) page_address(sg_page(sg));
125f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
126f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	if (addr)
127f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell		addr += sg->offset;
128f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	return addr;
129f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}
130f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
131f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic unsigned int qib_sg_dma_len(struct ib_device *dev,
132f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell				   struct scatterlist *sg)
133f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{
134f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	return sg->length;
135f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}
136f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
137f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic void qib_sync_single_for_cpu(struct ib_device *dev, u64 addr,
138f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell				    size_t size, enum dma_data_direction dir)
139f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{
140f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}
141f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
142f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic void qib_sync_single_for_device(struct ib_device *dev, u64 addr,
143f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell				       size_t size,
144f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell				       enum dma_data_direction dir)
145f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{
146f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}
147f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
148f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic void *qib_dma_alloc_coherent(struct ib_device *dev, size_t size,
149f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell				    u64 *dma_handle, gfp_t flag)
150f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{
151f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	struct page *p;
152f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	void *addr = NULL;
153f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
154f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	p = alloc_pages(flag, get_order(size));
155f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	if (p)
156f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell		addr = page_address(p);
157f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	if (dma_handle)
158f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell		*dma_handle = (u64) addr;
159f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	return addr;
160f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}
161f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
162f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic void qib_dma_free_coherent(struct ib_device *dev, size_t size,
163f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell				  void *cpu_addr, u64 dma_handle)
164f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{
165f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	free_pages((unsigned long) cpu_addr, get_order(size));
166f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}
167f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell
168f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstruct ib_dma_mapping_ops qib_dma_mapping_ops = {
169f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	.mapping_error = qib_mapping_error,
170f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	.map_single = qib_dma_map_single,
171f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	.unmap_single = qib_dma_unmap_single,
172f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	.map_page = qib_dma_map_page,
173f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	.unmap_page = qib_dma_unmap_page,
174f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	.map_sg = qib_map_sg,
175f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	.unmap_sg = qib_unmap_sg,
176f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	.dma_address = qib_sg_dma_address,
177f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	.dma_len = qib_sg_dma_len,
178f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	.sync_single_for_cpu = qib_sync_single_for_cpu,
179f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	.sync_single_for_device = qib_sync_single_for_device,
180f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	.alloc_coherent = qib_dma_alloc_coherent,
181f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell	.free_coherent = qib_dma_free_coherent
182f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell};
183