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