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