Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

dmaengine: dw-edma: Create a new dw_edma_core_ops structure to abstract controller operation

The structure dw_edma_core_ops has a set of the pointers
abstracting out the DW eDMA vX and DW HDMA Native controllers.
And use dw_edma_v0_core_register to set up operation.

Signed-off-by: Cai Huoqing <cai.huoqing@linux.dev>
Reviewed-by: Serge Semin <fancer.lancer@gmail.com>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Tested-by: Serge Semin <fancer.lancer@gmail.com>
Link: https://lore.kernel.org/r/20230520050854.73160-3-cai.huoqing@linux.dev
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Cai Huoqing and committed by
Vinod Koul
f9c3403f 48751755

+158 -83
+26 -58
drivers/dma/dw-edma/dw-edma-core.c
··· 183 183 184 184 static int dw_edma_start_transfer(struct dw_edma_chan *chan) 185 185 { 186 + struct dw_edma *dw = chan->dw; 186 187 struct dw_edma_chunk *child; 187 188 struct dw_edma_desc *desc; 188 189 struct virt_dma_desc *vd; ··· 201 200 if (!child) 202 201 return 0; 203 202 204 - dw_edma_v0_core_start(child, !desc->xfer_sz); 203 + dw_edma_core_start(dw, child, !desc->xfer_sz); 205 204 desc->xfer_sz += child->ll_region.sz; 206 205 dw_edma_free_burst(child); 207 206 list_del(&child->list); ··· 288 287 chan->configured = false; 289 288 } else if (chan->status == EDMA_ST_IDLE) { 290 289 chan->configured = false; 291 - } else if (dw_edma_v0_core_ch_status(chan) == DMA_COMPLETE) { 290 + } else if (dw_edma_core_ch_status(chan) == DMA_COMPLETE) { 292 291 /* 293 292 * The channel is in a false BUSY state, probably didn't 294 293 * receive or lost an interrupt ··· 600 599 struct virt_dma_desc *vd; 601 600 unsigned long flags; 602 601 603 - dw_edma_v0_core_clear_done_int(chan); 604 - 605 602 spin_lock_irqsave(&chan->vc.lock, flags); 606 603 vd = vchan_next_desc(&chan->vc); 607 604 if (vd) { ··· 640 641 struct virt_dma_desc *vd; 641 642 unsigned long flags; 642 643 643 - dw_edma_v0_core_clear_abort_int(chan); 644 - 645 644 spin_lock_irqsave(&chan->vc.lock, flags); 646 645 vd = vchan_next_desc(&chan->vc); 647 646 if (vd) { ··· 651 654 chan->status = EDMA_ST_IDLE; 652 655 } 653 656 654 - static irqreturn_t dw_edma_interrupt(int irq, void *data, bool write) 655 - { 656 - struct dw_edma_irq *dw_irq = data; 657 - struct dw_edma *dw = dw_irq->dw; 658 - unsigned long total, pos, val; 659 - unsigned long off; 660 - u32 mask; 661 - 662 - if (write) { 663 - total = dw->wr_ch_cnt; 664 - off = 0; 665 - mask = dw_irq->wr_mask; 666 - } else { 667 - total = dw->rd_ch_cnt; 668 - off = dw->wr_ch_cnt; 669 - mask = dw_irq->rd_mask; 670 - } 671 - 672 - val = dw_edma_v0_core_status_done_int(dw, write ? 673 - EDMA_DIR_WRITE : 674 - EDMA_DIR_READ); 675 - val &= mask; 676 - for_each_set_bit(pos, &val, total) { 677 - struct dw_edma_chan *chan = &dw->chan[pos + off]; 678 - 679 - dw_edma_done_interrupt(chan); 680 - } 681 - 682 - val = dw_edma_v0_core_status_abort_int(dw, write ? 683 - EDMA_DIR_WRITE : 684 - EDMA_DIR_READ); 685 - val &= mask; 686 - for_each_set_bit(pos, &val, total) { 687 - struct dw_edma_chan *chan = &dw->chan[pos + off]; 688 - 689 - dw_edma_abort_interrupt(chan); 690 - } 691 - 692 - return IRQ_HANDLED; 693 - } 694 - 695 657 static inline irqreturn_t dw_edma_interrupt_write(int irq, void *data) 696 658 { 697 - return dw_edma_interrupt(irq, data, true); 659 + struct dw_edma_irq *dw_irq = data; 660 + 661 + return dw_edma_core_handle_int(dw_irq, EDMA_DIR_WRITE, 662 + dw_edma_done_interrupt, 663 + dw_edma_abort_interrupt); 698 664 } 699 665 700 666 static inline irqreturn_t dw_edma_interrupt_read(int irq, void *data) 701 667 { 702 - return dw_edma_interrupt(irq, data, false); 668 + struct dw_edma_irq *dw_irq = data; 669 + 670 + return dw_edma_core_handle_int(dw_irq, EDMA_DIR_READ, 671 + dw_edma_done_interrupt, 672 + dw_edma_abort_interrupt); 703 673 } 704 674 705 675 static irqreturn_t dw_edma_interrupt_common(int irq, void *data) 706 676 { 707 - dw_edma_interrupt(irq, data, true); 708 - dw_edma_interrupt(irq, data, false); 677 + irqreturn_t ret = IRQ_NONE; 709 678 710 - return IRQ_HANDLED; 679 + ret |= dw_edma_interrupt_write(irq, data); 680 + ret |= dw_edma_interrupt_read(irq, data); 681 + 682 + return ret; 711 683 } 712 684 713 685 static int dw_edma_alloc_chan_resources(struct dma_chan *dchan) ··· 777 811 778 812 vchan_init(&chan->vc, dma); 779 813 780 - dw_edma_v0_core_device_config(chan); 814 + dw_edma_core_ch_config(chan); 781 815 } 782 816 783 817 /* Set DMA channel capabilities */ ··· 922 956 923 957 dw->chip = chip; 924 958 959 + dw_edma_v0_core_register(dw); 960 + 925 961 raw_spin_lock_init(&dw->lock); 926 962 927 963 dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt, 928 - dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE)); 964 + dw_edma_core_ch_count(dw, EDMA_DIR_WRITE)); 929 965 dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH); 930 966 931 967 dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt, 932 - dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ)); 968 + dw_edma_core_ch_count(dw, EDMA_DIR_READ)); 933 969 dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH); 934 970 935 971 if (!dw->wr_ch_cnt && !dw->rd_ch_cnt) ··· 950 982 dev_name(chip->dev)); 951 983 952 984 /* Disable eDMA, only to establish the ideal initial conditions */ 953 - dw_edma_v0_core_off(dw); 985 + dw_edma_core_off(dw); 954 986 955 987 /* Request IRQs */ 956 988 err = dw_edma_irq_request(dw, &wr_alloc, &rd_alloc); ··· 963 995 goto err_irq_free; 964 996 965 997 /* Turn debugfs on */ 966 - dw_edma_v0_core_debugfs_on(dw); 998 + dw_edma_core_debugfs_on(dw); 967 999 968 1000 chip->dw = dw; 969 1001 ··· 989 1021 return -ENODEV; 990 1022 991 1023 /* Disable eDMA */ 992 - dw_edma_v0_core_off(dw); 1024 + dw_edma_core_off(dw); 993 1025 994 1026 /* Free irqs */ 995 1027 for (i = (dw->nr_irqs - 1); i >= 0; i--)
+58
drivers/dma/dw-edma/dw-edma-core.h
··· 111 111 raw_spinlock_t lock; /* Only for legacy */ 112 112 113 113 struct dw_edma_chip *chip; 114 + 115 + const struct dw_edma_core_ops *core; 116 + }; 117 + 118 + typedef void (*dw_edma_handler_t)(struct dw_edma_chan *); 119 + 120 + struct dw_edma_core_ops { 121 + void (*off)(struct dw_edma *dw); 122 + u16 (*ch_count)(struct dw_edma *dw, enum dw_edma_dir dir); 123 + enum dma_status (*ch_status)(struct dw_edma_chan *chan); 124 + irqreturn_t (*handle_int)(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, 125 + dw_edma_handler_t done, dw_edma_handler_t abort); 126 + void (*start)(struct dw_edma_chunk *chunk, bool first); 127 + void (*ch_config)(struct dw_edma_chan *chan); 128 + void (*debugfs_on)(struct dw_edma *dw); 114 129 }; 115 130 116 131 struct dw_edma_sg { ··· 161 146 struct dw_edma_chan *dchan2dw_edma_chan(struct dma_chan *dchan) 162 147 { 163 148 return vc2dw_edma_chan(to_virt_chan(dchan)); 149 + } 150 + 151 + static inline 152 + void dw_edma_core_off(struct dw_edma *dw) 153 + { 154 + dw->core->off(dw); 155 + } 156 + 157 + static inline 158 + u16 dw_edma_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir) 159 + { 160 + return dw->core->ch_count(dw, dir); 161 + } 162 + 163 + static inline 164 + enum dma_status dw_edma_core_ch_status(struct dw_edma_chan *chan) 165 + { 166 + return chan->dw->core->ch_status(chan); 167 + } 168 + 169 + static inline irqreturn_t 170 + dw_edma_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, 171 + dw_edma_handler_t done, dw_edma_handler_t abort) 172 + { 173 + return dw_irq->dw->core->handle_int(dw_irq, dir, done, abort); 174 + } 175 + 176 + static inline 177 + void dw_edma_core_start(struct dw_edma *dw, struct dw_edma_chunk *chunk, bool first) 178 + { 179 + dw->core->start(chunk, first); 180 + } 181 + 182 + static inline 183 + void dw_edma_core_ch_config(struct dw_edma_chan *chan) 184 + { 185 + chan->dw->core->ch_config(chan); 186 + } 187 + 188 + static inline 189 + void dw_edma_core_debugfs_on(struct dw_edma *dw) 190 + { 191 + dw->core->debugfs_on(dw); 164 192 } 165 193 166 194 #endif /* _DW_EDMA_CORE_H */
+72 -13
drivers/dma/dw-edma/dw-edma-v0-core.c
··· 7 7 */ 8 8 9 9 #include <linux/bitfield.h> 10 - 10 + #include <linux/irqreturn.h> 11 11 #include <linux/io-64-nonatomic-lo-hi.h> 12 12 13 13 #include "dw-edma-core.h" ··· 160 160 readl_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name)) 161 161 162 162 /* eDMA management callbacks */ 163 - void dw_edma_v0_core_off(struct dw_edma *dw) 163 + static void dw_edma_v0_core_off(struct dw_edma *dw) 164 164 { 165 165 SET_BOTH_32(dw, int_mask, 166 166 EDMA_V0_DONE_INT_MASK | EDMA_V0_ABORT_INT_MASK); ··· 169 169 SET_BOTH_32(dw, engine_en, 0); 170 170 } 171 171 172 - u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir) 172 + static u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir) 173 173 { 174 174 u32 num_ch; 175 175 ··· 186 186 return (u16)num_ch; 187 187 } 188 188 189 - enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan) 189 + static enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan) 190 190 { 191 191 struct dw_edma *dw = chan->dw; 192 192 u32 tmp; ··· 202 202 return DMA_ERROR; 203 203 } 204 204 205 - void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan) 205 + static void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan) 206 206 { 207 207 struct dw_edma *dw = chan->dw; 208 208 ··· 210 210 FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id))); 211 211 } 212 212 213 - void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan) 213 + static void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan) 214 214 { 215 215 struct dw_edma *dw = chan->dw; 216 216 ··· 218 218 FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id))); 219 219 } 220 220 221 - u32 dw_edma_v0_core_status_done_int(struct dw_edma *dw, enum dw_edma_dir dir) 221 + static u32 dw_edma_v0_core_status_done_int(struct dw_edma *dw, enum dw_edma_dir dir) 222 222 { 223 223 return FIELD_GET(EDMA_V0_DONE_INT_MASK, 224 224 GET_RW_32(dw, dir, int_status)); 225 225 } 226 226 227 - u32 dw_edma_v0_core_status_abort_int(struct dw_edma *dw, enum dw_edma_dir dir) 227 + static u32 dw_edma_v0_core_status_abort_int(struct dw_edma *dw, enum dw_edma_dir dir) 228 228 { 229 229 return FIELD_GET(EDMA_V0_ABORT_INT_MASK, 230 230 GET_RW_32(dw, dir, int_status)); 231 + } 232 + 233 + static irqreturn_t 234 + dw_edma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, 235 + dw_edma_handler_t done, dw_edma_handler_t abort) 236 + { 237 + struct dw_edma *dw = dw_irq->dw; 238 + unsigned long total, pos, val; 239 + irqreturn_t ret = IRQ_NONE; 240 + struct dw_edma_chan *chan; 241 + unsigned long off; 242 + u32 mask; 243 + 244 + if (dir == EDMA_DIR_WRITE) { 245 + total = dw->wr_ch_cnt; 246 + off = 0; 247 + mask = dw_irq->wr_mask; 248 + } else { 249 + total = dw->rd_ch_cnt; 250 + off = dw->wr_ch_cnt; 251 + mask = dw_irq->rd_mask; 252 + } 253 + 254 + val = dw_edma_v0_core_status_done_int(dw, dir); 255 + val &= mask; 256 + for_each_set_bit(pos, &val, total) { 257 + chan = &dw->chan[pos + off]; 258 + 259 + dw_edma_v0_core_clear_done_int(chan); 260 + done(chan); 261 + 262 + ret = IRQ_HANDLED; 263 + } 264 + 265 + val = dw_edma_v0_core_status_abort_int(dw, dir); 266 + val &= mask; 267 + for_each_set_bit(pos, &val, total) { 268 + chan = &dw->chan[pos + off]; 269 + 270 + dw_edma_v0_core_clear_abort_int(chan); 271 + abort(chan); 272 + 273 + ret = IRQ_HANDLED; 274 + } 275 + 276 + return ret; 231 277 } 232 278 233 279 static void dw_edma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i, ··· 346 300 dw_edma_v0_write_ll_link(chunk, i, control, chunk->ll_region.paddr); 347 301 } 348 302 349 - void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first) 303 + static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first) 350 304 { 351 305 struct dw_edma_chan *chan = chunk->chan; 352 306 struct dw_edma *dw = chan->dw; ··· 417 371 FIELD_PREP(EDMA_V0_DOORBELL_CH_MASK, chan->id)); 418 372 } 419 373 420 - int dw_edma_v0_core_device_config(struct dw_edma_chan *chan) 374 + static void dw_edma_v0_core_ch_config(struct dw_edma_chan *chan) 421 375 { 422 376 struct dw_edma *dw = chan->dw; 423 377 u32 tmp = 0; ··· 484 438 SET_RW_32(dw, chan->dir, ch67_imwr_data, tmp); 485 439 break; 486 440 } 487 - 488 - return 0; 489 441 } 490 442 491 443 /* eDMA debugfs callbacks */ 492 - void dw_edma_v0_core_debugfs_on(struct dw_edma *dw) 444 + static void dw_edma_v0_core_debugfs_on(struct dw_edma *dw) 493 445 { 494 446 dw_edma_v0_debugfs_on(dw); 447 + } 448 + 449 + static const struct dw_edma_core_ops dw_edma_v0_core = { 450 + .off = dw_edma_v0_core_off, 451 + .ch_count = dw_edma_v0_core_ch_count, 452 + .ch_status = dw_edma_v0_core_ch_status, 453 + .handle_int = dw_edma_v0_core_handle_int, 454 + .start = dw_edma_v0_core_start, 455 + .ch_config = dw_edma_v0_core_ch_config, 456 + .debugfs_on = dw_edma_v0_core_debugfs_on, 457 + }; 458 + 459 + void dw_edma_v0_core_register(struct dw_edma *dw) 460 + { 461 + dw->core = &dw_edma_v0_core; 495 462 }
+2 -12
drivers/dma/dw-edma/dw-edma-v0-core.h
··· 11 11 12 12 #include <linux/dma/edma.h> 13 13 14 - /* eDMA management callbacks */ 15 - void dw_edma_v0_core_off(struct dw_edma *chan); 16 - u16 dw_edma_v0_core_ch_count(struct dw_edma *chan, enum dw_edma_dir dir); 17 - enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan); 18 - void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan); 19 - void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan); 20 - u32 dw_edma_v0_core_status_done_int(struct dw_edma *chan, enum dw_edma_dir dir); 21 - u32 dw_edma_v0_core_status_abort_int(struct dw_edma *chan, enum dw_edma_dir dir); 22 - void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first); 23 - int dw_edma_v0_core_device_config(struct dw_edma_chan *chan); 24 - /* eDMA debug fs callbacks */ 25 - void dw_edma_v0_core_debugfs_on(struct dw_edma *dw); 14 + /* eDMA core register */ 15 + void dw_edma_v0_core_register(struct dw_edma *dw); 26 16 27 17 #endif /* _DW_EDMA_V0_CORE_H */