1/* 2 * Earthsoft PT3 driver 3 * 4 * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation version 2. 9 * 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16#include <linux/dma-mapping.h> 17#include <linux/kernel.h> 18#include <linux/pci.h> 19 20#include "pt3.h" 21 22#define PT3_ACCESS_UNIT (TS_PACKET_SZ * 128) 23#define PT3_BUF_CANARY (0x74) 24 25static u32 get_dma_base(int idx) 26{ 27 int i; 28 29 i = (idx == 1 || idx == 2) ? 3 - idx : idx; 30 return REG_DMA_BASE + 0x18 * i; 31} 32 33int pt3_stop_dma(struct pt3_adapter *adap) 34{ 35 struct pt3_board *pt3 = adap->dvb_adap.priv; 36 u32 base; 37 u32 stat; 38 int retry; 39 40 base = get_dma_base(adap->adap_idx); 41 stat = ioread32(pt3->regs[0] + base + OFST_STATUS); 42 if (!(stat & 0x01)) 43 return 0; 44 45 iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL); 46 for (retry = 0; retry < 5; retry++) { 47 stat = ioread32(pt3->regs[0] + base + OFST_STATUS); 48 if (!(stat & 0x01)) 49 return 0; 50 msleep(50); 51 } 52 return -EIO; 53} 54 55int pt3_start_dma(struct pt3_adapter *adap) 56{ 57 struct pt3_board *pt3 = adap->dvb_adap.priv; 58 u32 base = get_dma_base(adap->adap_idx); 59 60 iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL); 61 iowrite32(lower_32_bits(adap->desc_buf[0].b_addr), 62 pt3->regs[0] + base + OFST_DMA_DESC_L); 63 iowrite32(upper_32_bits(adap->desc_buf[0].b_addr), 64 pt3->regs[0] + base + OFST_DMA_DESC_H); 65 iowrite32(0x01, pt3->regs[0] + base + OFST_DMA_CTL); 66 return 0; 67} 68 69 70static u8 *next_unit(struct pt3_adapter *adap, int *idx, int *ofs) 71{ 72 *ofs += PT3_ACCESS_UNIT; 73 if (*ofs >= DATA_BUF_SZ) { 74 *ofs -= DATA_BUF_SZ; 75 (*idx)++; 76 if (*idx == adap->num_bufs) 77 *idx = 0; 78 } 79 return &adap->buffer[*idx].data[*ofs]; 80} 81 82int pt3_proc_dma(struct pt3_adapter *adap) 83{ 84 int idx, ofs; 85 86 idx = adap->buf_idx; 87 ofs = adap->buf_ofs; 88 89 if (adap->buffer[idx].data[ofs] == PT3_BUF_CANARY) 90 return 0; 91 92 while (*next_unit(adap, &idx, &ofs) != PT3_BUF_CANARY) { 93 u8 *p; 94 95 p = &adap->buffer[adap->buf_idx].data[adap->buf_ofs]; 96 if (adap->num_discard > 0) 97 adap->num_discard--; 98 else if (adap->buf_ofs + PT3_ACCESS_UNIT > DATA_BUF_SZ) { 99 dvb_dmx_swfilter_packets(&adap->demux, p, 100 (DATA_BUF_SZ - adap->buf_ofs) / TS_PACKET_SZ); 101 dvb_dmx_swfilter_packets(&adap->demux, 102 adap->buffer[idx].data, ofs / TS_PACKET_SZ); 103 } else 104 dvb_dmx_swfilter_packets(&adap->demux, p, 105 PT3_ACCESS_UNIT / TS_PACKET_SZ); 106 107 *p = PT3_BUF_CANARY; 108 adap->buf_idx = idx; 109 adap->buf_ofs = ofs; 110 } 111 return 0; 112} 113 114void pt3_init_dmabuf(struct pt3_adapter *adap) 115{ 116 int idx, ofs; 117 u8 *p; 118 119 idx = 0; 120 ofs = 0; 121 p = adap->buffer[0].data; 122 /* mark the whole buffers as "not written yet" */ 123 while (idx < adap->num_bufs) { 124 p[ofs] = PT3_BUF_CANARY; 125 ofs += PT3_ACCESS_UNIT; 126 if (ofs >= DATA_BUF_SZ) { 127 ofs -= DATA_BUF_SZ; 128 idx++; 129 p = adap->buffer[idx].data; 130 } 131 } 132 adap->buf_idx = 0; 133 adap->buf_ofs = 0; 134} 135 136void pt3_free_dmabuf(struct pt3_adapter *adap) 137{ 138 struct pt3_board *pt3; 139 int i; 140 141 pt3 = adap->dvb_adap.priv; 142 for (i = 0; i < adap->num_bufs; i++) 143 dma_free_coherent(&pt3->pdev->dev, DATA_BUF_SZ, 144 adap->buffer[i].data, adap->buffer[i].b_addr); 145 adap->num_bufs = 0; 146 147 for (i = 0; i < adap->num_desc_bufs; i++) 148 dma_free_coherent(&pt3->pdev->dev, PAGE_SIZE, 149 adap->desc_buf[i].descs, adap->desc_buf[i].b_addr); 150 adap->num_desc_bufs = 0; 151} 152 153 154int pt3_alloc_dmabuf(struct pt3_adapter *adap) 155{ 156 struct pt3_board *pt3; 157 void *p; 158 int i, j; 159 int idx, ofs; 160 int num_desc_bufs; 161 dma_addr_t data_addr, desc_addr; 162 struct xfer_desc *d; 163 164 pt3 = adap->dvb_adap.priv; 165 adap->num_bufs = 0; 166 adap->num_desc_bufs = 0; 167 for (i = 0; i < pt3->num_bufs; i++) { 168 p = dma_alloc_coherent(&pt3->pdev->dev, DATA_BUF_SZ, 169 &adap->buffer[i].b_addr, GFP_KERNEL); 170 if (p == NULL) 171 goto failed; 172 adap->buffer[i].data = p; 173 adap->num_bufs++; 174 } 175 pt3_init_dmabuf(adap); 176 177 /* build circular-linked pointers (xfer_desc) to the data buffers*/ 178 idx = 0; 179 ofs = 0; 180 num_desc_bufs = 181 DIV_ROUND_UP(adap->num_bufs * DATA_BUF_XFERS, DESCS_IN_PAGE); 182 for (i = 0; i < num_desc_bufs; i++) { 183 p = dma_alloc_coherent(&pt3->pdev->dev, PAGE_SIZE, 184 &desc_addr, GFP_KERNEL); 185 if (p == NULL) 186 goto failed; 187 adap->num_desc_bufs++; 188 adap->desc_buf[i].descs = p; 189 adap->desc_buf[i].b_addr = desc_addr; 190 191 if (i > 0) { 192 d = &adap->desc_buf[i - 1].descs[DESCS_IN_PAGE - 1]; 193 d->next_l = lower_32_bits(desc_addr); 194 d->next_h = upper_32_bits(desc_addr); 195 } 196 for (j = 0; j < DESCS_IN_PAGE; j++) { 197 data_addr = adap->buffer[idx].b_addr + ofs; 198 d = &adap->desc_buf[i].descs[j]; 199 d->addr_l = lower_32_bits(data_addr); 200 d->addr_h = upper_32_bits(data_addr); 201 d->size = DATA_XFER_SZ; 202 203 desc_addr += sizeof(struct xfer_desc); 204 d->next_l = lower_32_bits(desc_addr); 205 d->next_h = upper_32_bits(desc_addr); 206 207 ofs += DATA_XFER_SZ; 208 if (ofs >= DATA_BUF_SZ) { 209 ofs -= DATA_BUF_SZ; 210 idx++; 211 if (idx >= adap->num_bufs) { 212 desc_addr = adap->desc_buf[0].b_addr; 213 d->next_l = lower_32_bits(desc_addr); 214 d->next_h = upper_32_bits(desc_addr); 215 return 0; 216 } 217 } 218 } 219 } 220 return 0; 221 222failed: 223 pt3_free_dmabuf(adap); 224 return -ENOMEM; 225} 226