13703f53bSSrinivas Pandruvada /* 23703f53bSSrinivas Pandruvada * ISHTP DMA I/F functions 33703f53bSSrinivas Pandruvada * 43703f53bSSrinivas Pandruvada * Copyright (c) 2003-2016, Intel Corporation. 53703f53bSSrinivas Pandruvada * 63703f53bSSrinivas Pandruvada * This program is free software; you can redistribute it and/or modify it 73703f53bSSrinivas Pandruvada * under the terms and conditions of the GNU General Public License, 83703f53bSSrinivas Pandruvada * version 2, as published by the Free Software Foundation. 93703f53bSSrinivas Pandruvada * 103703f53bSSrinivas Pandruvada * This program is distributed in the hope it will be useful, but WITHOUT 113703f53bSSrinivas Pandruvada * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 123703f53bSSrinivas Pandruvada * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 133703f53bSSrinivas Pandruvada * more details. 143703f53bSSrinivas Pandruvada * 153703f53bSSrinivas Pandruvada */ 163703f53bSSrinivas Pandruvada 173703f53bSSrinivas Pandruvada #include <linux/slab.h> 183703f53bSSrinivas Pandruvada #include <linux/sched.h> 193703f53bSSrinivas Pandruvada #include <linux/wait.h> 203703f53bSSrinivas Pandruvada #include <linux/delay.h> 213703f53bSSrinivas Pandruvada #include <linux/dma-mapping.h> 223703f53bSSrinivas Pandruvada #include "ishtp-dev.h" 233703f53bSSrinivas Pandruvada #include "client.h" 243703f53bSSrinivas Pandruvada 253703f53bSSrinivas Pandruvada /** 263703f53bSSrinivas Pandruvada * ishtp_cl_alloc_dma_buf() - Allocate DMA RX and TX buffer 273703f53bSSrinivas Pandruvada * @dev: ishtp device 283703f53bSSrinivas Pandruvada * 293703f53bSSrinivas Pandruvada * Allocate RX and TX DMA buffer once during bus setup. 303703f53bSSrinivas Pandruvada * It allocates 1MB, RX and TX DMA buffer, which are divided 313703f53bSSrinivas Pandruvada * into slots. 323703f53bSSrinivas Pandruvada */ 333703f53bSSrinivas Pandruvada void ishtp_cl_alloc_dma_buf(struct ishtp_device *dev) 343703f53bSSrinivas Pandruvada { 353703f53bSSrinivas Pandruvada dma_addr_t h; 363703f53bSSrinivas Pandruvada 373703f53bSSrinivas Pandruvada if (dev->ishtp_host_dma_tx_buf) 383703f53bSSrinivas Pandruvada return; 393703f53bSSrinivas Pandruvada 403703f53bSSrinivas Pandruvada dev->ishtp_host_dma_tx_buf_size = 1024*1024; 413703f53bSSrinivas Pandruvada dev->ishtp_host_dma_rx_buf_size = 1024*1024; 423703f53bSSrinivas Pandruvada 433703f53bSSrinivas Pandruvada /* Allocate Tx buffer and init usage bitmap */ 443703f53bSSrinivas Pandruvada dev->ishtp_host_dma_tx_buf = dma_alloc_coherent(dev->devc, 453703f53bSSrinivas Pandruvada dev->ishtp_host_dma_tx_buf_size, 463703f53bSSrinivas Pandruvada &h, GFP_KERNEL); 473703f53bSSrinivas Pandruvada if (dev->ishtp_host_dma_tx_buf) 483703f53bSSrinivas Pandruvada dev->ishtp_host_dma_tx_buf_phys = h; 493703f53bSSrinivas Pandruvada 503703f53bSSrinivas Pandruvada dev->ishtp_dma_num_slots = dev->ishtp_host_dma_tx_buf_size / 513703f53bSSrinivas Pandruvada DMA_SLOT_SIZE; 523703f53bSSrinivas Pandruvada 533703f53bSSrinivas Pandruvada dev->ishtp_dma_tx_map = kcalloc(dev->ishtp_dma_num_slots, 543703f53bSSrinivas Pandruvada sizeof(uint8_t), 553703f53bSSrinivas Pandruvada GFP_KERNEL); 563703f53bSSrinivas Pandruvada spin_lock_init(&dev->ishtp_dma_tx_lock); 573703f53bSSrinivas Pandruvada 583703f53bSSrinivas Pandruvada /* Allocate Rx buffer */ 593703f53bSSrinivas Pandruvada dev->ishtp_host_dma_rx_buf = dma_alloc_coherent(dev->devc, 603703f53bSSrinivas Pandruvada dev->ishtp_host_dma_rx_buf_size, 613703f53bSSrinivas Pandruvada &h, GFP_KERNEL); 623703f53bSSrinivas Pandruvada 633703f53bSSrinivas Pandruvada if (dev->ishtp_host_dma_rx_buf) 643703f53bSSrinivas Pandruvada dev->ishtp_host_dma_rx_buf_phys = h; 653703f53bSSrinivas Pandruvada } 663703f53bSSrinivas Pandruvada 673703f53bSSrinivas Pandruvada /** 683703f53bSSrinivas Pandruvada * ishtp_cl_free_dma_buf() - Free DMA RX and TX buffer 693703f53bSSrinivas Pandruvada * @dev: ishtp device 703703f53bSSrinivas Pandruvada * 713703f53bSSrinivas Pandruvada * Free DMA buffer when all clients are released. This is 723703f53bSSrinivas Pandruvada * only happens during error path in ISH built in driver 733703f53bSSrinivas Pandruvada * model 743703f53bSSrinivas Pandruvada */ 753703f53bSSrinivas Pandruvada void ishtp_cl_free_dma_buf(struct ishtp_device *dev) 763703f53bSSrinivas Pandruvada { 773703f53bSSrinivas Pandruvada dma_addr_t h; 783703f53bSSrinivas Pandruvada 793703f53bSSrinivas Pandruvada if (dev->ishtp_host_dma_tx_buf) { 803703f53bSSrinivas Pandruvada h = dev->ishtp_host_dma_tx_buf_phys; 813703f53bSSrinivas Pandruvada dma_free_coherent(dev->devc, dev->ishtp_host_dma_tx_buf_size, 823703f53bSSrinivas Pandruvada dev->ishtp_host_dma_tx_buf, h); 833703f53bSSrinivas Pandruvada } 843703f53bSSrinivas Pandruvada 853703f53bSSrinivas Pandruvada if (dev->ishtp_host_dma_rx_buf) { 863703f53bSSrinivas Pandruvada h = dev->ishtp_host_dma_rx_buf_phys; 873703f53bSSrinivas Pandruvada dma_free_coherent(dev->devc, dev->ishtp_host_dma_rx_buf_size, 883703f53bSSrinivas Pandruvada dev->ishtp_host_dma_rx_buf, h); 893703f53bSSrinivas Pandruvada } 903703f53bSSrinivas Pandruvada 913703f53bSSrinivas Pandruvada kfree(dev->ishtp_dma_tx_map); 923703f53bSSrinivas Pandruvada dev->ishtp_host_dma_tx_buf = NULL; 933703f53bSSrinivas Pandruvada dev->ishtp_host_dma_rx_buf = NULL; 943703f53bSSrinivas Pandruvada dev->ishtp_dma_tx_map = NULL; 953703f53bSSrinivas Pandruvada } 963703f53bSSrinivas Pandruvada 973703f53bSSrinivas Pandruvada /* 983703f53bSSrinivas Pandruvada * ishtp_cl_get_dma_send_buf() - Get a DMA memory slot 993703f53bSSrinivas Pandruvada * @dev: ishtp device 1003703f53bSSrinivas Pandruvada * @size: Size of memory to get 1013703f53bSSrinivas Pandruvada * 1023703f53bSSrinivas Pandruvada * Find and return free address of "size" bytes in dma tx buffer. 1033703f53bSSrinivas Pandruvada * the function will mark this address as "in-used" memory. 1043703f53bSSrinivas Pandruvada * 1053703f53bSSrinivas Pandruvada * Return: NULL when no free buffer else a buffer to copy 1063703f53bSSrinivas Pandruvada */ 1073703f53bSSrinivas Pandruvada void *ishtp_cl_get_dma_send_buf(struct ishtp_device *dev, 1083703f53bSSrinivas Pandruvada uint32_t size) 1093703f53bSSrinivas Pandruvada { 1103703f53bSSrinivas Pandruvada unsigned long flags; 1113703f53bSSrinivas Pandruvada int i, j, free; 1123703f53bSSrinivas Pandruvada /* additional slot is needed if there is rem */ 1133703f53bSSrinivas Pandruvada int required_slots = (size / DMA_SLOT_SIZE) 1143703f53bSSrinivas Pandruvada + 1 * (size % DMA_SLOT_SIZE != 0); 1153703f53bSSrinivas Pandruvada 1163703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->ishtp_dma_tx_lock, flags); 1173703f53bSSrinivas Pandruvada for (i = 0; i <= (dev->ishtp_dma_num_slots - required_slots); i++) { 1183703f53bSSrinivas Pandruvada free = 1; 1193703f53bSSrinivas Pandruvada for (j = 0; j < required_slots; j++) 1203703f53bSSrinivas Pandruvada if (dev->ishtp_dma_tx_map[i+j]) { 1213703f53bSSrinivas Pandruvada free = 0; 1223703f53bSSrinivas Pandruvada i += j; 1233703f53bSSrinivas Pandruvada break; 1243703f53bSSrinivas Pandruvada } 1253703f53bSSrinivas Pandruvada if (free) { 1263703f53bSSrinivas Pandruvada /* mark memory as "caught" */ 1273703f53bSSrinivas Pandruvada for (j = 0; j < required_slots; j++) 1283703f53bSSrinivas Pandruvada dev->ishtp_dma_tx_map[i+j] = 1; 1293703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->ishtp_dma_tx_lock, flags); 1303703f53bSSrinivas Pandruvada return (i * DMA_SLOT_SIZE) + 1313703f53bSSrinivas Pandruvada (unsigned char *)dev->ishtp_host_dma_tx_buf; 1323703f53bSSrinivas Pandruvada } 1333703f53bSSrinivas Pandruvada } 1343703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->ishtp_dma_tx_lock, flags); 1353703f53bSSrinivas Pandruvada dev_err(dev->devc, "No free DMA buffer to send msg\n"); 1363703f53bSSrinivas Pandruvada return NULL; 1373703f53bSSrinivas Pandruvada } 1383703f53bSSrinivas Pandruvada 1393703f53bSSrinivas Pandruvada /* 1403703f53bSSrinivas Pandruvada * ishtp_cl_release_dma_acked_mem() - Release DMA memory slot 1413703f53bSSrinivas Pandruvada * @dev: ishtp device 1423703f53bSSrinivas Pandruvada * @msg_addr: message address of slot 1433703f53bSSrinivas Pandruvada * @size: Size of memory to get 1443703f53bSSrinivas Pandruvada * 1453703f53bSSrinivas Pandruvada * Release_dma_acked_mem - returnes the acked memory to free list. 1463703f53bSSrinivas Pandruvada * (from msg_addr, size bytes long) 1473703f53bSSrinivas Pandruvada */ 1483703f53bSSrinivas Pandruvada void ishtp_cl_release_dma_acked_mem(struct ishtp_device *dev, 1493703f53bSSrinivas Pandruvada void *msg_addr, 1503703f53bSSrinivas Pandruvada uint8_t size) 1513703f53bSSrinivas Pandruvada { 1523703f53bSSrinivas Pandruvada unsigned long flags; 1533703f53bSSrinivas Pandruvada int acked_slots = (size / DMA_SLOT_SIZE) 1543703f53bSSrinivas Pandruvada + 1 * (size % DMA_SLOT_SIZE != 0); 1553703f53bSSrinivas Pandruvada int i, j; 1563703f53bSSrinivas Pandruvada 1573703f53bSSrinivas Pandruvada if ((msg_addr - dev->ishtp_host_dma_tx_buf) % DMA_SLOT_SIZE) { 1583703f53bSSrinivas Pandruvada dev_err(dev->devc, "Bad DMA Tx ack address\n"); 1593703f53bSSrinivas Pandruvada return; 1603703f53bSSrinivas Pandruvada } 1613703f53bSSrinivas Pandruvada 1623703f53bSSrinivas Pandruvada i = (msg_addr - dev->ishtp_host_dma_tx_buf) / DMA_SLOT_SIZE; 1633703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->ishtp_dma_tx_lock, flags); 1643703f53bSSrinivas Pandruvada for (j = 0; j < acked_slots; j++) { 1653703f53bSSrinivas Pandruvada if ((i + j) >= dev->ishtp_dma_num_slots || 1663703f53bSSrinivas Pandruvada !dev->ishtp_dma_tx_map[i+j]) { 1673703f53bSSrinivas Pandruvada /* no such slot, or memory is already free */ 1683703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->ishtp_dma_tx_lock, flags); 1693703f53bSSrinivas Pandruvada dev_err(dev->devc, "Bad DMA Tx ack address\n"); 1703703f53bSSrinivas Pandruvada return; 1713703f53bSSrinivas Pandruvada } 1723703f53bSSrinivas Pandruvada dev->ishtp_dma_tx_map[i+j] = 0; 1733703f53bSSrinivas Pandruvada } 1743703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->ishtp_dma_tx_lock, flags); 1753703f53bSSrinivas Pandruvada } 176