/****************************************************************************** * * * License Agreement * * * * Copyright (c) 2014 Altera Corporation, San Jose, California, USA. * * All rights reserved. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the "Software"), * * to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, * * and/or sell copies of the Software, and to permit persons to whom the * * Software is furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * * DEALINGS IN THE SOFTWARE. * * * * This agreement shall be governed in all respects by the laws of the State * * of California and by the laws of the United States of America. * * * ******************************************************************************/ #include #include #include #include #include "altera_msgdma_descriptor_regs.h" #include "altera_msgdma_csr_regs.h" #include "altera_msgdma_response_regs.h" #include "io.h" #include "altera_msgdma.h" #include "priv/alt_busy_sleep.h" #include "sys/alt_errno.h" #include "sys/alt_irq.h" #include "sys/alt_stdio.h" /******************************************************************************* * Private API ******************************************************************************/ static int alt_msgdma_write_standard_descriptor ( alt_u32 *csr_base, alt_u32 *descriptor_base, alt_msgdma_standard_descriptor *descriptor); static int alt_msgdma_write_extended_descriptor ( alt_u32 *csr_base, alt_u32 *descriptor_base, alt_msgdma_extended_descriptor *descriptor); static void alt_msgdma_irq(void *context); static int alt_msgdma_construct_standard_descriptor( alt_msgdma_dev *dev, alt_msgdma_standard_descriptor *descriptor, alt_u32 *read_address, alt_u32 *write_address, alt_u32 length, alt_u32 control); static int alt_msgdma_construct_extended_descriptor( alt_msgdma_dev *dev, alt_msgdma_extended_descriptor *descriptor, alt_u32 *read_address, alt_u32 *write_address, alt_u32 length, alt_u32 control, alt_u16 sequence_number, alt_u8 read_burst_count, alt_u8 write_burst_count, alt_u16 read_stride, alt_u16 write_stride); static int alt_msgdma_descriptor_async_transfer ( alt_msgdma_dev *dev, alt_msgdma_standard_descriptor *standard_desc, alt_msgdma_extended_descriptor *extended_desc); static int alt_msgdma_descriptor_sync_transfer ( alt_msgdma_dev *dev, alt_msgdma_standard_descriptor *standard_desc, alt_msgdma_extended_descriptor *extended_desc); /* The list of registered msgdma components */ ALT_LLIST_HEAD(alt_msgdma_list); /* * Functions for writing descriptor structure to the dispatcher. If you disable * some of the extended features in the hardware then you should pass in 0 for * that particular descriptor element. These disabled elements will not be * buffered by the dispatcher block. * * This function is non-blocking and will return an error code if there is no * room to write another descriptor to the dispatcher. It is recommended to call * 'read_descriptor_buffer_full' and make sure it returns '0' before calling * this function. */ static int alt_msgdma_write_standard_descriptor ( alt_u32 *csr_base, alt_u32 *descriptor_base, alt_msgdma_standard_descriptor *descriptor) { if (0 != (IORD_ALTERA_MSGDMA_CSR_STATUS(csr_base) & ALTERA_MSGDMA_CSR_DESCRIPTOR_BUFFER_FULL_MASK)) { /*at least one descriptor buffer is full, returning so that this function is non-blocking*/ return -ENOSPC; } IOWR_ALTERA_MSGDMA_DESCRIPTOR_READ_ADDRESS(descriptor_base, (alt_u32)descriptor->read_address); IOWR_ALTERA_MSGDMA_DESCRIPTOR_WRITE_ADDRESS(descriptor_base, ( alt_u32)descriptor->write_address); IOWR_ALTERA_MSGDMA_DESCRIPTOR_LENGTH(descriptor_base, descriptor->transfer_length); IOWR_ALTERA_MSGDMA_DESCRIPTOR_CONTROL_STANDARD(descriptor_base, descriptor->control); return 0; } /* * This function is used for writing extended descriptors to the dispatcher. It handles only 32-bit descriptors. */ static int alt_msgdma_write_extended_descriptor ( alt_u32 *csr_base, alt_u32 *descriptor_base, alt_msgdma_extended_descriptor *descriptor) { if (0 != (IORD_ALTERA_MSGDMA_CSR_STATUS(csr_base) & ALTERA_MSGDMA_CSR_DESCRIPTOR_BUFFER_FULL_MASK)) { /*at least one descriptor buffer is full, returning so that this function is non-blocking*/ return -ENOSPC; } IOWR_ALTERA_MSGDMA_DESCRIPTOR_READ_ADDRESS( descriptor_base, (alt_u32)descriptor->read_address_low); IOWR_ALTERA_MSGDMA_DESCRIPTOR_WRITE_ADDRESS( descriptor_base, (alt_u32)descriptor->write_address_low); IOWR_ALTERA_MSGDMA_DESCRIPTOR_LENGTH( descriptor_base, descriptor->transfer_length); IOWR_ALTERA_MSGDMA_DESCRIPTOR_SEQUENCE_NUMBER( descriptor_base, descriptor->sequence_number); IOWR_ALTERA_MSGDMA_DESCRIPTOR_READ_BURST( descriptor_base, descriptor->read_burst_count); IOWR_ALTERA_MSGDMA_DESCRIPTOR_WRITE_BURST( descriptor_base, descriptor->write_burst_count); IOWR_ALTERA_MSGDMA_DESCRIPTOR_READ_STRIDE( descriptor_base, descriptor->read_stride); IOWR_ALTERA_MSGDMA_DESCRIPTOR_WRITE_STRIDE( descriptor_base, descriptor->write_stride); IOWR_ALTERA_MSGDMA_DESCRIPTOR_READ_ADDRESS_HIGH(descriptor_base, 0); IOWR_ALTERA_MSGDMA_DESCRIPTOR_WRITE_ADDRESS_HIGH(descriptor_base, 0); IOWR_ALTERA_MSGDMA_DESCRIPTOR_CONTROL_ENHANCED( descriptor_base, descriptor->control); return 0; } /* * alt_msgdma_irq() * * Interrupt handler for the Modular Scatter-Gather DMA controller. */ static void alt_msgdma_irq(void *context) { alt_msgdma_dev *dev = (alt_msgdma_dev *) context; alt_irq_context cpu_sr; alt_u32 temporary_control; /* disable global interrupt*/ if (dev->prefetcher_enable) { temporary_control = IORD_ALT_MSGDMA_PREFETCHER_CONTROL(dev->prefetcher_base) & ALT_MSGDMA_PREFETCHER_CTRL_GLOBAL_INTR_EN_CLR_MASK; IOWR_ALT_MSGDMA_PREFETCHER_CONTROL(dev->prefetcher_base, temporary_control); /* clear the IRQ status- W1C */ IOWR_ALT_MSGDMA_PREFETCHER_STATUS(dev->prefetcher_base, ALT_MSGDMA_PREFETCHER_STATUS_IRQ_SET_MASK); } else { temporary_control = IORD_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base) & (~ALTERA_MSGDMA_CSR_GLOBAL_INTERRUPT_MASK); IOWR_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base, temporary_control); /* clear the IRQ status */ IOWR_ALTERA_MSGDMA_CSR_STATUS(dev->csr_base, ALTERA_MSGDMA_CSR_IRQ_SET_MASK); } /* * Other interrupts are explicitly disabled if callbacks * are registered because there is no guarantee that they are * pre-emption-safe. This allows the driver to support * interrupt pre-emption. */ if(dev->callback) { cpu_sr = alt_irq_disable_all(); dev->callback (dev->callback_context); alt_irq_enable_all(cpu_sr); } /* enable global interrupt */ if (dev->prefetcher_enable) { temporary_control = IORD_ALT_MSGDMA_PREFETCHER_CONTROL(dev->prefetcher_base) | ALT_MSGDMA_PREFETCHER_CTRL_GLOBAL_INTR_EN_SET_MASK; IOWR_ALT_MSGDMA_PREFETCHER_CONTROL(dev->prefetcher_base, temporary_control); } else { temporary_control = IORD_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base) | (ALTERA_MSGDMA_CSR_GLOBAL_INTERRUPT_MASK); IOWR_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base, temporary_control); } return; } /* * Helper functions for constructing mm_to_st, st_to_mm, mm_to_mm standard * descriptors. Unnecessary elements are set to 0 for completeness and will be * ignored by the hardware. * Returns: * - status: return 0 (success) * return -EINVAL (invalid argument, could be due to argument which * has larger value than hardware setting value) */ static int alt_msgdma_construct_standard_descriptor( alt_msgdma_dev *dev, alt_msgdma_standard_descriptor *descriptor, alt_u32 *read_address, alt_u32 *write_address, alt_u32 length, alt_u32 control) { if(dev->max_byte < length || dev->enhanced_features != 0 ) { return -EINVAL; } descriptor->read_address = read_address; descriptor->write_address = write_address; descriptor->transfer_length = length; descriptor->control = control | ALTERA_MSGDMA_DESCRIPTOR_CONTROL_GO_MASK; return 0; } /* * Helper functions for constructing mm_to_st, st_to_mm, mm_to_mm extended * descriptors. Unnecessary elements are set to 0 for completeness and will be * ignored by the hardware. * Returns: * - status: return 0 (success) * return -EINVAL (invalid argument, could be due to argument which * has larger value than hardware setting value) */ static int alt_msgdma_construct_extended_descriptor( alt_msgdma_dev *dev, alt_msgdma_extended_descriptor *descriptor, alt_u32 *read_address, alt_u32 *write_address, alt_u32 length, alt_u32 control, alt_u16 sequence_number, alt_u8 read_burst_count, alt_u8 write_burst_count, alt_u16 read_stride, alt_u16 write_stride) { if(dev->max_byte < length || dev->max_stride < read_stride || dev->max_stride < write_stride || dev->enhanced_features != 1 ) { return -EINVAL; } descriptor->read_address_low = read_address; descriptor->write_address_low = write_address; descriptor->transfer_length = length; descriptor->sequence_number = sequence_number; descriptor->read_burst_count = read_burst_count; descriptor->write_burst_count = write_burst_count; descriptor->read_stride = read_stride; descriptor->write_stride = write_stride; descriptor->read_address_high = NULL; descriptor->write_address_high = NULL; descriptor->control = control | ALTERA_MSGDMA_DESCRIPTOR_CONTROL_GO_MASK; return 0 ; } /* * Helper functions for descriptor in async transfer. * Arguments:# This driver supports HAL types * - *dev: Pointer to msgdma device (instance) structure. * - *standard_desc: Pointer to single standard descriptor. * - *extended_desc: Pointer to single extended descriptor. * *note: Either one of both *standard_desc and *extended_desc must * be assigned with NULL, another with proper pointer value. * Failing to do so can cause the function return with "-EPERM " * * If a callback routine has been previously registered with this * particular msgdma controller, transfer will be set up to enable interrupt * generation. It is the responsibility of the application developer to check * source interruption, status completion and creating suitable interrupt * handling. Note: "stop on error" of CSR control register is always masking * within this function. The CSR control can be set by user through calling * "alt_register_callback" by passing user used defined control setting. * * Returns: * 0 -> success * -ENOSPC -> FIFO descriptor buffer is full * -EPERM -> operation not permitted due to descriptor type conflict * -ETIME -> Time out and skipping the looping after 5 msec. */ static int alt_msgdma_descriptor_async_transfer ( alt_msgdma_dev *dev, alt_msgdma_standard_descriptor *standard_desc, alt_msgdma_extended_descriptor *extended_desc) { alt_u32 control = 0; alt_irq_context context = 0; alt_u16 counter = 0; alt_u32 fifo_read_fill_level = ( IORD_ALTERA_MSGDMA_CSR_DESCRIPTOR_FILL_LEVEL(dev->csr_base) & ALTERA_MSGDMA_CSR_READ_FILL_LEVEL_MASK) >> ALTERA_MSGDMA_CSR_READ_FILL_LEVEL_OFFSET; alt_u32 fifo_write_fill_level = ( IORD_ALTERA_MSGDMA_CSR_DESCRIPTOR_FILL_LEVEL(dev->csr_base) & ALTERA_MSGDMA_CSR_WRITE_FILL_LEVEL_MASK) >> ALTERA_MSGDMA_CSR_WRITE_FILL_LEVEL_OFFSET; /* Return with error immediately if one of read/write buffer is full */ if((dev->descriptor_fifo_depth <= fifo_write_fill_level) || (dev->descriptor_fifo_depth <= fifo_read_fill_level)) { /*at least one write or read FIFO descriptor buffer is full, returning so that this function is non-blocking*/ return -ENOSPC; } /* * When running in a multi threaded environment, obtain the "regs_lock" * semaphore. This ensures that accessing registers is thread-safe. */ ALT_SEM_PEND (dev->regs_lock, 0); /* Stop the msgdma dispatcher from issuing more descriptors to the read or write masters */ /* stop issuing more descriptors */ control = ALTERA_MSGDMA_CSR_STOP_DESCRIPTORS_MASK; /* making sure the read-modify-write below can't be pre-empted */ context = alt_irq_disable_all(); IOWR_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base, control); /* * Clear any (previous) status register information * that might occlude our error checking later. */ IOWR_ALTERA_MSGDMA_CSR_STATUS( dev->csr_base, IORD_ALTERA_MSGDMA_CSR_STATUS(dev->csr_base)); alt_irq_enable_all(context); if (NULL != standard_desc && NULL == extended_desc) { /*writing descriptor structure to the dispatcher, wait until descriptor write is succeed*/ while(0 != alt_msgdma_write_standard_descriptor ( dev->csr_base, dev->descriptor_base, standard_desc)) { alt_busy_sleep(1); /* delay 1us */ if(5000 <= counter) /* time_out if waiting longer than 5 msec */ { alt_printf("time out after 5 msec while waiting" " free FIFO buffer for storing standard descriptor\n"); /* * Now that access to the registers is complete, release the * registers semaphore so that other threads can access the * registers. */ ALT_SEM_POST (dev->regs_lock); return -ETIME; } counter++; } } else if (NULL == standard_desc && NULL != extended_desc) { counter = 0; /* reset counter */ /*writing descriptor structure to the dispatcher, wait until descriptor write is succeed*/ while(0 != alt_msgdma_write_extended_descriptor ( dev->csr_base, dev->descriptor_base, extended_desc)) { alt_busy_sleep(1); /* delay 1us */ if(5000 <= counter) /* time_out if waiting longer than 5 msec */ { alt_printf("time out after 5 msec while waiting free FIFO buffer" " for storing extended descriptor\n"); /* * Now that access to the registers is complete, release the * registers semaphore so that other threads can access the * registers. */ ALT_SEM_POST (dev->regs_lock); return -ETIME; } counter++; } } else { /* * Now that access to the registers is complete, release the registers * semaphore so that other threads can access the registers. */ ALT_SEM_POST (dev->regs_lock); /* operation not permitted due to descriptor type conflict */ return -EPERM; } /* * If a callback routine has been previously registered which will be * called from the msgdma ISR. Set up controller to: * - Run * - Stop on an error with any particular descriptor */ if(dev->callback) { control |= (dev->control | ALTERA_MSGDMA_CSR_STOP_ON_ERROR_MASK | ALTERA_MSGDMA_CSR_GLOBAL_INTERRUPT_MASK ); control &= (~ALTERA_MSGDMA_CSR_STOP_DESCRIPTORS_MASK); /* making sure the read-modify-write below can't be pre-empted */ context = alt_irq_disable_all(); IOWR_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base, control); alt_irq_enable_all(context); } /* * No callback has been registered. Set up controller to: * - Run * - Stop on an error with any particular descriptor * - Disable interrupt generation */ else { control |= (dev->control | ALTERA_MSGDMA_CSR_STOP_ON_ERROR_MASK ); control &= (~ALTERA_MSGDMA_CSR_STOP_DESCRIPTORS_MASK) & (~ALTERA_MSGDMA_CSR_GLOBAL_INTERRUPT_MASK); /* making sure the read-modify-write below can't be pre-empted */ context = alt_irq_disable_all(); IOWR_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base, control); alt_irq_enable_all(context); } /* * Now that access to the registers is complete, release the registers * semaphore so that other threads can access the registers. */ ALT_SEM_POST (dev->regs_lock); return 0; } /* * Helper functions for descriptor in sync transfer. * Arguments: * - *dev: Pointer to msgdma device (instance) structure. * - *standard_desc: Pointer to single standard descriptor. * - *extended_desc: Pointer to single extended descriptor. * * Note: Either one of both *standard_desc and *extended_desc must * be assigned with NULL, another with proper pointer value. * Failing to do so can cause the function return with "-EPERM " * * "stop on error" of CSR control register is always being masked and interrupt * is always disabled within this function. * The CSR control can be set by user through calling "alt_register_callback" * with passing user defined control setting. * * Returns: * 0 -> success * error -> errors or conditions causing msgdma stop issuing commands to masters. * check the bit set in the error with CSR status register. * -EPERM -> operation not permitted due to descriptor type conflict * -ETIME -> Time out and skipping the looping after 5 msec. */ static int alt_msgdma_descriptor_sync_transfer ( alt_msgdma_dev *dev, alt_msgdma_standard_descriptor *standard_desc, alt_msgdma_extended_descriptor *extended_desc) { alt_u32 control=0; alt_irq_context context=0; alt_u32 csr_status = 0; alt_u16 counter = 0; alt_u32 fifo_read_fill_level = ( IORD_ALTERA_MSGDMA_CSR_DESCRIPTOR_FILL_LEVEL(dev->csr_base) & ALTERA_MSGDMA_CSR_READ_FILL_LEVEL_MASK) >> ALTERA_MSGDMA_CSR_READ_FILL_LEVEL_OFFSET; alt_u32 fifo_write_fill_level = ( IORD_ALTERA_MSGDMA_CSR_DESCRIPTOR_FILL_LEVEL(dev->csr_base) & ALTERA_MSGDMA_CSR_WRITE_FILL_LEVEL_MASK) >> ALTERA_MSGDMA_CSR_WRITE_FILL_LEVEL_OFFSET; alt_u32 error = ALTERA_MSGDMA_CSR_STOPPED_ON_ERROR_MASK | ALTERA_MSGDMA_CSR_STOPPED_ON_EARLY_TERMINATION_MASK | ALTERA_MSGDMA_CSR_STOP_STATE_MASK | ALTERA_MSGDMA_CSR_RESET_STATE_MASK; /* Wait for available FIFO buffer to store new descriptor*/ while ((dev->descriptor_fifo_depth <= fifo_write_fill_level) || (dev->descriptor_fifo_depth <= fifo_read_fill_level)) { alt_busy_sleep(1); /* delay 1us */ if(5000 <= counter) /* time_out if waiting longer than 5 msec */ { alt_printf("time out after 5 msec while waiting free FIFO buffer" " for storing descriptor\n"); return -ETIME; } counter++; fifo_read_fill_level = ( IORD_ALTERA_MSGDMA_CSR_DESCRIPTOR_FILL_LEVEL(dev->csr_base) & ALTERA_MSGDMA_CSR_READ_FILL_LEVEL_MASK) >> ALTERA_MSGDMA_CSR_READ_FILL_LEVEL_OFFSET; fifo_write_fill_level = ( IORD_ALTERA_MSGDMA_CSR_DESCRIPTOR_FILL_LEVEL(dev->csr_base) & ALTERA_MSGDMA_CSR_WRITE_FILL_LEVEL_MASK) >> ALTERA_MSGDMA_CSR_WRITE_FILL_LEVEL_OFFSET; } /* * When running in a multi threaded environment, obtain the "regs_lock" * semaphore. This ensures that accessing registers is thread-safe. */ ALT_SEM_PEND (dev->regs_lock, 0); /* Stop the msgdma dispatcher from issuing more descriptors to the read or write masters */ /* making sure the read-modify-write below can't be pre-empted */ context = alt_irq_disable_all(); IOWR_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base, ALTERA_MSGDMA_CSR_STOP_DESCRIPTORS_MASK); /* * Clear any (previous) status register information * that might occlude our error checking later. */ IOWR_ALTERA_MSGDMA_CSR_STATUS( dev->csr_base, IORD_ALTERA_MSGDMA_CSR_STATUS(dev->csr_base)); if (NULL != standard_desc && NULL == extended_desc) { counter = 0; /* reset counter */ /*writing descriptor structure to the dispatcher, wait until descriptor write is succeed*/ while(0 != alt_msgdma_write_standard_descriptor ( dev->csr_base, dev->descriptor_base, standard_desc)) { alt_busy_sleep(1); /* delay 1us */ if(5000 <= counter) /* time_out if waiting longer than 5 msec */ { alt_printf("time out after 5 msec while writing standard" " descriptor to FIFO\n"); /* * Now that access to the registers is complete, release the * registers semaphore so that other threads can access the * registers. */ ALT_SEM_POST (dev->regs_lock); return -ETIME; } counter++; } } else if (NULL == standard_desc && NULL != extended_desc) { counter = 0; /* reset counter */ /*writing descriptor structure to the dispatcher, wait until descriptor write is succeed*/ while(0 != alt_msgdma_write_extended_descriptor ( dev->csr_base, dev->descriptor_base, extended_desc)) { alt_busy_sleep(1); /* delay 1us */ if(5000 <= counter) /* time_out if waiting longer than 5 msec */ { alt_printf("time out after 5 msec while writing extended" " descriptor to FIFO\n"); /* * Now that access to the registers is complete, release the * registers semaphore so that other threads can access the * registers. */ ALT_SEM_POST (dev->regs_lock); return -ETIME; } counter++; } } else { /* * Now that access to the registers is complete, release the registers * semaphore so that other threads can access the registers. */ ALT_SEM_POST (dev->regs_lock); /* operation not permitted due to descriptor type conflict */ return -EPERM; } /* * Set up msgdma controller to: * - Disable interrupt generation * - Run once a valid descriptor is written to controller * - Stop on an error with any particular descriptor */ IOWR_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base, (dev->control | ALTERA_MSGDMA_CSR_STOP_ON_ERROR_MASK ) & (~ALTERA_MSGDMA_CSR_STOP_DESCRIPTORS_MASK) & (~ALTERA_MSGDMA_CSR_GLOBAL_INTERRUPT_MASK)) ; alt_irq_enable_all(context); counter = 0; /* reset counter */ csr_status = IORD_ALTERA_MSGDMA_CSR_STATUS(dev->csr_base); /* Wait for any pending transfers to complete or checking any errors or conditions causing descriptor to stop dispatching */ while (!(csr_status & error) && (csr_status & ALTERA_MSGDMA_CSR_BUSY_MASK)) { alt_busy_sleep(1); /* delay 1us */ if(5000 <= counter) /* time_out if waiting longer than 5 msec */ { alt_printf("time out after 5 msec while waiting for any pending" " transfer complete\n"); /* * Now that access to the registers is complete, release the registers * semaphore so that other threads can access the registers. */ ALT_SEM_POST (dev->regs_lock); return -ETIME; } counter++; csr_status = IORD_ALTERA_MSGDMA_CSR_STATUS(dev->csr_base); } /*Errors or conditions causing the dispatcher stopping issuing read/write commands to masters*/ if(0 != (csr_status & error)) { /* * Now that access to the registers is complete, release the registers * semaphore so that other threads can access the registers. */ ALT_SEM_POST (dev->regs_lock); return error; } /* Stop the msgdma dispatcher from issuing more descriptors to the read or write masters */ /* stop issuing more descriptors */ control = IORD_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base) | ALTERA_MSGDMA_CSR_STOP_DESCRIPTORS_MASK; /* making sure the read-modify-write below can't be pre-empted */ context = alt_irq_disable_all(); IOWR_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base, control); /* * Clear any (previous) status register information * that might occlude our error checking later. */ IOWR_ALTERA_MSGDMA_CSR_STATUS( dev->csr_base, IORD_ALTERA_MSGDMA_CSR_STATUS(dev->csr_base)); alt_irq_enable_all(context); /* * Now that access to the registers is complete, release the registers * semaphore so that other threads can access the registers. */ ALT_SEM_POST (dev->regs_lock); return 0; } /* * Functions for constructing standard descriptors. Unnecessary elements are * set to 0 for completeness and will be ignored by the hardware. * Returns: * - status: return 0 (success) * return -EINVAL (invalid argument, could be due to argument which * has larger value than hardware setting value) */ int alt_msgdma_construct_standard_st_to_mm_descriptor ( alt_msgdma_dev *dev, alt_msgdma_standard_descriptor *descriptor, alt_u32 *write_address, alt_u32 length, alt_u32 control) { return alt_msgdma_construct_standard_descriptor(dev, descriptor, NULL, write_address, length, control); } int alt_msgdma_construct_standard_mm_to_st_descriptor ( alt_msgdma_dev *dev, alt_msgdma_standard_descriptor *descriptor, alt_u32 *read_address, alt_u32 length, alt_u32 control) { return alt_msgdma_construct_standard_descriptor(dev, descriptor, read_address, NULL, length, control); } int alt_msgdma_construct_standard_mm_to_mm_descriptor ( alt_msgdma_dev *dev, alt_msgdma_standard_descriptor *descriptor, alt_u32 *read_address, alt_u32 *write_address, alt_u32 length, alt_u32 control) { return alt_msgdma_construct_standard_descriptor(dev, descriptor, read_address, write_address, length, control); } /* * Functions for constructing extended descriptors. If you disable some of the * extended features in the hardware then you should pass in 0 for that * particular descriptor element. These disabled elements will not be buffered * by the dispatcher block. * Returns: * - status: return 0 (success) * return -EINVAL (invalid argument, could be due to argument which * has larger value than hardware setting value) */ int alt_msgdma_construct_extended_st_to_mm_descriptor ( alt_msgdma_dev *dev, alt_msgdma_extended_descriptor *descriptor, alt_u32 *write_address, alt_u32 length, alt_u32 control, alt_u16 sequence_number, alt_u8 write_burst_count, alt_u16 write_stride) { return alt_msgdma_construct_extended_descriptor(dev, descriptor, NULL, write_address, length, control, sequence_number, 0, write_burst_count, 0, write_stride); } int alt_msgdma_construct_extended_mm_to_st_descriptor ( alt_msgdma_dev *dev, alt_msgdma_extended_descriptor *descriptor, alt_u32 *read_address, alt_u32 length, alt_u32 control, alt_u16 sequence_number, alt_u8 read_burst_count, alt_u16 read_stride) { return alt_msgdma_construct_extended_descriptor(dev, descriptor, read_address, NULL, length, control, sequence_number, read_burst_count, 0, read_stride, 0); } int alt_msgdma_construct_extended_mm_to_mm_descriptor ( alt_msgdma_dev *dev, alt_msgdma_extended_descriptor *descriptor, alt_u32 *read_address, alt_u32 *write_address, alt_u32 length, alt_u32 control, alt_u16 sequence_number, alt_u8 read_burst_count, alt_u8 write_burst_count, alt_u16 read_stride, alt_u16 write_stride) { return alt_msgdma_construct_extended_descriptor(dev, descriptor, read_address, write_address, length, control, sequence_number, read_burst_count, write_burst_count, read_stride, write_stride); } /********************** MSGDMA PREFETCHER PRIVATE APIs *************************/ /* * Base functions for constructing mm_to_st, st_to_mm, mm_to_mm standard * descriptors for the prefetcher. Unnecessary elements are set to 0 for * completeness and will be ignored by the hardware. * The descriptor created will be suitable for park since this API will set next_ptr * to itself as park_mode requires. Additionally OWN_BY_HW bit left as 0 (owned by sw) * until the prefetcher is started with this descriptor in the list. * Returns: * - status: return 0 (success) * return -EINVAL (invalid argument, could be due to argument which * has larger value than hardware setting value) */ static int alt_msgdma_construct_prefetcher_standard_descriptor( alt_msgdma_dev *dev, alt_msgdma_prefetcher_standard_descriptor *descriptor, alt_u32 read_address, alt_u32 write_address, alt_u32 length, alt_u32 control) { if(dev->max_byte < length || dev->enhanced_features != 0 ) { return -EINVAL; } descriptor->read_address = read_address; descriptor->write_address = write_address; descriptor->transfer_length = length; /* have descriptor point to itself for park_mode */ descriptor->next_desc_ptr = (alt_u32)descriptor; /* clear control own_by_hw bit field (SW owns this descriptor)*/ descriptor->control = (control & ALT_MSGDMA_PREFETCHER_DESCRIPTOR_CTRL_OWN_BY_HW_CLR_MASK) | ALTERA_MSGDMA_DESCRIPTOR_CONTROL_GO_MASK; return 0; } /* * Base functions for constructing mm_to_st, st_to_mm, mm_to_mm extended * descriptors. Unnecessary elements are set to 0 for completeness and will be * ignored by the hardware. The descriptor created will be suitable for park * mode since this API will set next_ptr to itself as park_mode requires. * Additionally OWN_BY_HW bit left as 0 (owned by sw) until the prefetcher is * started with this descriptor in the list. * Returns: * - status: return 0 (success) * return -EINVAL (invalid argument, could be due to argument which * has larger value than hardware setting value) */ static int alt_msgdma_construct_prefetcher_extended_descriptor( alt_msgdma_dev *dev, alt_msgdma_prefetcher_extended_descriptor *descriptor, alt_u32 read_address_high, alt_u32 read_address_low, alt_u32 write_address_high, alt_u32 write_address_low, alt_u32 length, alt_u32 control, alt_u16 sequence_number, alt_u8 read_burst_count, alt_u8 write_burst_count, alt_u16 read_stride, alt_u16 write_stride) { msgdma_addr64 node_addr; if(dev->max_byte < length || dev->max_stride < read_stride || dev->max_stride < write_stride || dev->enhanced_features != 1 ) { return -EINVAL; } descriptor->read_address_high = read_address_high; descriptor->read_address_low = read_address_low; descriptor->write_address_high = write_address_high; descriptor->write_address_low = write_address_low; descriptor->transfer_length = length; descriptor->sequence_number = sequence_number; descriptor->read_burst_count = read_burst_count; descriptor->write_burst_count = write_burst_count; descriptor->read_stride = read_stride; descriptor->write_stride = write_stride; /* have descriptor point to itself */ node_addr.u64 = (uintptr_t)descriptor; descriptor->next_desc_ptr_low = node_addr.u32[0]; descriptor->next_desc_ptr_high = node_addr.u32[1]; /* clear control own_by_hw bit field (SW still owns this descriptor). */ descriptor->control = (control & ALT_MSGDMA_PREFETCHER_DESCRIPTOR_CTRL_OWN_BY_HW_CLR_MASK) | ALTERA_MSGDMA_DESCRIPTOR_CONTROL_GO_MASK; return 0 ; } /********************** MSGDMA PREFETCHER PUBLIC APIs ************************/ /* * Functions for constructing standard descriptors. Unnecessary elements are * set to 0 for completeness and will be ignored by the hardware. * Returns: * - status: return 0 (success) * return -EINVAL (invalid argument, could be due to argument which * has larger value than hardware setting value) */ int alt_msgdma_construct_prefetcher_standard_mm_to_mm_descriptor ( alt_msgdma_dev *dev, alt_msgdma_prefetcher_standard_descriptor *descriptor, alt_u32 read_address, alt_u32 write_address, alt_u32 length, alt_u32 control) { return alt_msgdma_construct_prefetcher_standard_descriptor(dev, descriptor, read_address, write_address, length, control); } int alt_msgdma_construct_prefetcher_standard_st_to_mm_descriptor ( alt_msgdma_dev *dev, alt_msgdma_prefetcher_standard_descriptor *descriptor, alt_u32 write_address, alt_u32 length, alt_u32 control) { return alt_msgdma_construct_prefetcher_standard_descriptor(dev, descriptor, 0, write_address, length, control); } int alt_msgdma_construct_prefetcher_standard_mm_to_st_descriptor ( alt_msgdma_dev *dev, alt_msgdma_prefetcher_standard_descriptor *descriptor, alt_u32 read_address, alt_u32 length, alt_u32 control) { return alt_msgdma_construct_prefetcher_standard_descriptor(dev, descriptor, read_address, 0, length, control); } /* * Functions for constructing extended descriptors. If you disable some of the * extended features in the hardware then you should pass in 0 for that * particular descriptor element. These disabled elements will not be buffered * by the dispatcher block. * Returns: * - status: return 0 (success) * return -EINVAL (invalid argument, could be due to argument which * has larger value than hardware setting value) */ int alt_msgdma_construct_prefetcher_extended_st_to_mm_descriptor ( alt_msgdma_dev *dev, alt_msgdma_prefetcher_extended_descriptor *descriptor, alt_u32 write_address_high, alt_u32 write_address_low, alt_u32 length, alt_u32 control, alt_u16 sequence_number, alt_u8 write_burst_count, alt_u16 write_stride) { return alt_msgdma_construct_prefetcher_extended_descriptor(dev, descriptor, 0, 0, write_address_high, write_address_low, length, control, sequence_number, 0, write_burst_count, 0, write_stride); } int alt_msgdma_construct_prefetcher_extended_mm_to_st_descriptor ( alt_msgdma_dev *dev, alt_msgdma_prefetcher_extended_descriptor *descriptor, alt_u32 read_address_high, alt_u32 read_address_low, alt_u32 length, alt_u32 control, alt_u16 sequence_number, alt_u8 read_burst_count, alt_u16 read_stride) { return alt_msgdma_construct_prefetcher_extended_descriptor(dev, descriptor, read_address_high, read_address_low, 0, 0, length, control, sequence_number, read_burst_count, 0, read_stride, 0); } int alt_msgdma_construct_prefetcher_extended_mm_to_mm_descriptor ( alt_msgdma_dev *dev, alt_msgdma_prefetcher_extended_descriptor *descriptor, alt_u32 read_address_high, alt_u32 read_address_low, alt_u32 write_address_high, alt_u32 write_address_low, alt_u32 length, alt_u32 control, alt_u16 sequence_number, alt_u8 read_burst_count, alt_u8 write_burst_count, alt_u16 read_stride, alt_u16 write_stride) { return alt_msgdma_construct_prefetcher_extended_descriptor(dev, descriptor, read_address_high, read_address_low, write_address_high, write_address_low, length, control, sequence_number, read_burst_count, write_burst_count, read_stride, write_stride); } /* PREFETCHER linked list APIs */ /* * Function for adding standard descriptors to a standard descriptor list * Returns: * - status: return 0 (success) * return -EINVAL (invalid argument, could be due to descriptor * already being in the list, descriptor pointer being NULL, or * descriptor.next_ptr not pointing back to itslef) */ int alt_msgdma_prefetcher_add_standard_desc_to_list ( alt_msgdma_prefetcher_standard_descriptor** list, alt_msgdma_prefetcher_standard_descriptor* descriptor) { alt_msgdma_prefetcher_standard_descriptor *last_descr_ptr; if (descriptor == NULL) { return -EINVAL; /* this descriptor cannot be NULL */ } if (descriptor->next_desc_ptr != (alt_u32)descriptor) { return -EINVAL; /* descriptor.next_ptr must point to itself */ } if (*list == NULL) { *list = descriptor; /* make this root-node if list is empty */ printf("Making this as root node\n"); //printf("%x %x %x\n",list[0],list[1],list[2]); //int *ls = &list[0]; //printf("ls_0 = %x \n",ls[0]); return 0; /* successfully added */ } if (*list == descriptor) { return -EINVAL; /* this descriptor cannot already be root-node */ } /* get to last node in the list */ last_descr_ptr = *list; /* start at list root-node */ printf("last_descr_ptr=%x\n",last_descr_ptr); /* traverse list until you get the last node */ while (last_descr_ptr->next_desc_ptr != (alt_u32)*list) { printf("In while\n"); if (last_descr_ptr->next_desc_ptr == (alt_u32)descriptor) { return -EINVAL; /* descriptor cannot already be in the list */ } last_descr_ptr = (alt_msgdma_prefetcher_standard_descriptor*)(last_descr_ptr->next_desc_ptr); printf("last_descr_ptr=%x\n",last_descr_ptr); } printf("After while condition\n"); /* add this descriptor to end of list */ last_descr_ptr->next_desc_ptr = (alt_u32)((uintptr_t)descriptor); /* ensure new last pointer points the start of the list */ descriptor->next_desc_ptr = (alt_u32)((uintptr_t)*list); return 0; /* successfully added */ } int alt_msgdma_prefetcher_add_extended_desc_to_list ( alt_msgdma_prefetcher_extended_descriptor** list, alt_msgdma_prefetcher_extended_descriptor* descriptor) { alt_msgdma_prefetcher_extended_descriptor *last_descr_ptr; msgdma_addr64 root_node_addr, next_node_addr; if (descriptor == NULL) { return -EINVAL; /* this descriptor cannot be NULL */ } next_node_addr.u64 = (uintptr_t)descriptor; if( (descriptor->next_desc_ptr_low != next_node_addr.u32[0]) && (descriptor->next_desc_ptr_high != next_node_addr.u32[1])) { return -EINVAL; /* descriptor.next_ptr must point to itself */ } if (*list == NULL) { *list = descriptor; /* make this the root-node if list is empty */ return 0; } if (*list == descriptor) { return -EINVAL; /* this descriptor cannot already be root-node */ } /* get to last node in the list */ last_descr_ptr = *list; /* start at list root-node */ /* the last nodes next ptr should point to the root node*/ root_node_addr.u64 = (uintptr_t)*list; /* traverse list until you get the last node */ while ((last_descr_ptr->next_desc_ptr_low != root_node_addr.u32[0]) && (last_descr_ptr->next_desc_ptr_high != root_node_addr.u32[1])) { /* first check if descriptor already in the list */ next_node_addr.u64 = (uintptr_t)descriptor; if ((last_descr_ptr->next_desc_ptr_low == next_node_addr.u32[0]) && (last_descr_ptr->next_desc_ptr_high == next_node_addr.u32[1])) { return -EINVAL; /* descriptor cannot already be in the list */ } /* go to next node in list, using 64 bit address */ next_node_addr.u32[0] = last_descr_ptr->next_desc_ptr_low; next_node_addr.u32[1] = last_descr_ptr->next_desc_ptr_high; last_descr_ptr = (alt_msgdma_prefetcher_extended_descriptor*)((uintptr_t)next_node_addr.u64); } /* add this descriptor to end of list */ next_node_addr.u64 = (uintptr_t)descriptor; last_descr_ptr->next_desc_ptr_low = next_node_addr.u32[0]; last_descr_ptr->next_desc_ptr_high = next_node_addr.u32[1]; /* ensure new last pointer points the beginning of the list */ descriptor->next_desc_ptr_low = root_node_addr.u32[0]; descriptor->next_desc_ptr_high = root_node_addr.u32[1]; return 0; } /* * Functions to set all the own-by-hw bits, need to call right before starting * prefetcher since if used the create descriptor APIs the set_by_hw bits are * still set to SW owned. */ int alt_msgdma_prefetcher_set_std_list_own_by_hw_bits ( alt_msgdma_prefetcher_standard_descriptor *list) { printf("----------- in HW_OWN_BITS ---------------\n"); printf("list=%x\n",list); alt_u32 descriptor_control_field = 0; alt_msgdma_prefetcher_standard_descriptor *last_descr_ptr; if (list == NULL) { return -EINVAL; /* this list cannot be empty */ } /* update all nodes in the list */ last_descr_ptr = list; /* start at list root-node */ /* traverse list to update all of the nodes */ while (last_descr_ptr->next_desc_ptr != (alt_u32)list) { /* get current value */ descriptor_control_field = last_descr_ptr->control; /* update own_by_hw bit only */ last_descr_ptr->control = descriptor_control_field | ALT_MSGDMA_PREFETCHER_DESCRIPTOR_CTRL_OWN_BY_HW_SET_MASK; /* go to next node in list */ last_descr_ptr = (alt_msgdma_prefetcher_standard_descriptor*)(last_descr_ptr->next_desc_ptr); } /* update the last node in the list, currently last_descr_ptr after while loop */ descriptor_control_field = last_descr_ptr->control; /* get current value */ /* update own_by_hw bit only */ last_descr_ptr->control = descriptor_control_field | ALT_MSGDMA_PREFETCHER_DESCRIPTOR_CTRL_OWN_BY_HW_SET_MASK; return 0; } /* * Functions to set all the own-by-hw bits, need to call right before starting * prefetcher since if used the create descriptor APIs the set_by_hw bits are * still set to SW owned. */ int alt_msgdma_prefetcher_set_extd_list_own_by_hw_bits ( alt_msgdma_prefetcher_extended_descriptor *list) { alt_u32 descriptor_control_field = 0; msgdma_addr64 root_node_addr, next_node_addr; alt_msgdma_prefetcher_extended_descriptor *last_descr_ptr; if (list == NULL) { return -EINVAL; /* this list cannot be empty */ } /* update all nodes in the list */ last_descr_ptr = list; /* start at list root-node */ /* the last nodes next ptr should point to the root node*/ root_node_addr.u64 = (uintptr_t)list; /* traverse list until you get the last node */ while ((last_descr_ptr->next_desc_ptr_low != root_node_addr.u32[0]) && (last_descr_ptr->next_desc_ptr_high != root_node_addr.u32[1])) { /* start with current value */ descriptor_control_field = last_descr_ptr->control; /* update own_by_hw bit only */ last_descr_ptr->control = descriptor_control_field | ALT_MSGDMA_PREFETCHER_DESCRIPTOR_CTRL_OWN_BY_HW_SET_MASK; /* go to next node in list, using 64 bit address */ next_node_addr.u32[0] = last_descr_ptr->next_desc_ptr_low; next_node_addr.u32[1] = last_descr_ptr->next_desc_ptr_high; last_descr_ptr = (alt_msgdma_prefetcher_extended_descriptor*)((uintptr_t)next_node_addr.u64); } /* update the last node in the list, currently last_descr_ptr after while loop */ descriptor_control_field = last_descr_ptr->control; /* start with current value */ /* update own_by_hw bit only */ last_descr_ptr->control = descriptor_control_field | ALT_MSGDMA_PREFETCHER_DESCRIPTOR_CTRL_OWN_BY_HW_SET_MASK; return 0; } /* * Functions to start the prefetcher. Will return error if prefetcher already * started. * * Arguments:# This driver supports HAL types * - *dev: Pointer to msgdma device (instance) structure. * - *standard_desc: Pointer to single standard descriptor OR *extended_desc: * Pointer to single extended descriptor. * - park_mode_en: setting for prefetcher park mode * - poll_en: setting for poll_en (IF poll frequency still 0 this API will * also set that to a default non-zero value) * *note: Must call API specific to descriptor type. Either * alt_msgdma_start_prefetcher_with_std_desc_list OR * alt_msgdma_start_prefetcher_with_extd_desc_list * where the list paratmeter is the root-node of your linked list. Then those * APIs will call the base function accordingly. * * If a callback routine has been previously registered with this * particular msgdma controller, transfer will be set up to enable interrupt * generation. It is the responsibility of the application developer to check * source interruption, status completion and creating suitable interrupt * handling. * Note: "stop on error" of CSR control register is always masking within this * function. The CSR control can be set by user through calling * "alt_register_callback" by passing user used defined control setting. * * Returns: * 0 -> success * -EBUSY -> prefetcher busy processing list already, it is up to user to stop * prefetcher/dispatcher correctly before calling this function. * if already busy will always return error. */ /* * Base function to start prefetcher. */ int alt_msgdma_start_prefetcher_with_list_addr ( alt_msgdma_dev *dev, alt_u64 list_addr, alt_u8 park_mode_en, alt_u8 poll_en) { alt_u32 prefetcher_ctl = 0; alt_u32 dispatcher_ctl = 0; alt_irq_context context = 0; /* use helper struct to get easy access to hi/low address */ msgdma_addr64 root_node_addr; root_node_addr.u64 = list_addr; /* * When running in a multi threaded environment, obtain the "regs_lock" * semaphore. This ensures that accessing registers is thread-safe. */ ALT_SEM_PEND (dev->regs_lock, 0); /* case where prefetcher already started, return busy error */ prefetcher_ctl = IORD_ALT_MSGDMA_PREFETCHER_CONTROL(dev->prefetcher_base); if(ALT_MSGDMA_PREFETCHER_CTRL_RUN_GET(prefetcher_ctl)){ /* release the registers semaphore */ ALT_SEM_POST (dev->regs_lock); return -EBUSY; } /* Stop the msgdma dispatcher from issuing more descriptors to the read or write masters */ /* stop issuing more descriptors */ dispatcher_ctl = ALTERA_MSGDMA_CSR_STOP_DESCRIPTORS_MASK; /* making sure the read-modify-write below can't be pre-empted */ context = alt_irq_disable_all(); IOWR_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base, dispatcher_ctl); /* * Clear any (previous) status register information * that might occlude our error checking later. */ IOWR_ALTERA_MSGDMA_CSR_STATUS( dev->csr_base, IORD_ALTERA_MSGDMA_CSR_STATUS(dev->csr_base)); alt_irq_enable_all(context); /* * If a callback routine has been previously registered which will be * called from the msgdma ISR. Set up dispatcher to: * - Run * - Stop on an error with any particular descriptor */ if(dev->callback) { dispatcher_ctl |= (dev->control | ALTERA_MSGDMA_CSR_STOP_ON_ERROR_MASK | ALTERA_MSGDMA_CSR_GLOBAL_INTERRUPT_MASK ); dispatcher_ctl &= (~ALTERA_MSGDMA_CSR_STOP_DESCRIPTORS_MASK); prefetcher_ctl |= ALT_MSGDMA_PREFETCHER_CTRL_GLOBAL_INTR_EN_SET_MASK; /* making sure the read-modify-write below can't be pre-empted */ context = alt_irq_disable_all(); IOWR_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base, dispatcher_ctl); IOWR_ALT_MSGDMA_PREFETCHER_CONTROL(dev->prefetcher_base, prefetcher_ctl); alt_irq_enable_all(context); } /* * No callback has been registered. Set up dispatcher to: * - Run * - Stop on an error with any particular descriptor * - Disable interrupt generation */ else { dispatcher_ctl |= (dev->control | ALTERA_MSGDMA_CSR_STOP_ON_ERROR_MASK); dispatcher_ctl &= (~ALTERA_MSGDMA_CSR_STOP_DESCRIPTORS_MASK) & (~ALTERA_MSGDMA_CSR_GLOBAL_INTERRUPT_MASK); prefetcher_ctl &= ALT_MSGDMA_PREFETCHER_CTRL_GLOBAL_INTR_EN_CLR_MASK; /* making sure the read-modify-write below can't be pre-empted */ context = alt_irq_disable_all(); IOWR_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base, dispatcher_ctl); IOWR_ALT_MSGDMA_PREFETCHER_CONTROL(dev->prefetcher_base, prefetcher_ctl); alt_irq_enable_all(context); } /* set next descriptor registers to point to the list root-node */ IOWR_ALT_MSGDMA_PREFETCHER_NEXT_DESCRIPTOR_PTR_LOW(dev->prefetcher_base, root_node_addr.u32[0]); IOWR_ALT_MSGDMA_PREFETCHER_NEXT_DESCRIPTOR_PTR_HIGH(dev->prefetcher_base, root_node_addr.u32[1]); /* set park-mode */ if (park_mode_en){ prefetcher_ctl |= ALT_MSGDMA_PREFETCHER_CTRL_PARK_MODE_SET_MASK; } else { prefetcher_ctl &= ALT_MSGDMA_PREFETCHER_CTRL_PARK_MODE_CLR_MASK; } /* set poll-en */ if (poll_en){ prefetcher_ctl |= ALT_MSGDMA_PREFETCHER_CTRL_DESC_POLL_EN_MASK; if(IORD_ALT_MSGDMA_PREFETCHER_DESCRIPTOR_POLLING_FREQ( dev->prefetcher_base) == 0){ /* set poll frequency to some non-zero default value */ IOWR_ALT_MSGDMA_PREFETCHER_DESCRIPTOR_POLLING_FREQ( dev->prefetcher_base, 0xFF); } } else { prefetcher_ctl &= ALT_MSGDMA_PREFETCHER_CTRL_DESC_POLL_EN_CLR_MASK; } /* set the prefetcher run bit */ prefetcher_ctl |= ALT_MSGDMA_PREFETCHER_CTRL_RUN_SET_MASK; /* start the dma since run bit is set */ IOWR_ALT_MSGDMA_PREFETCHER_CONTROL(dev->prefetcher_base, prefetcher_ctl); /* * Now that access to the registers is complete, release the registers * semaphore so that other threads can access the registers. */ ALT_SEM_POST (dev->regs_lock); return 0; } /* * Public functions to start prefetcher. */ int alt_msgdma_start_prefetcher_with_std_desc_list ( alt_msgdma_dev *dev, alt_msgdma_prefetcher_standard_descriptor *list, alt_u8 park_mode_en, alt_u8 poll_en) { if (alt_msgdma_prefetcher_set_std_list_own_by_hw_bits(list) != 0){ return -EINVAL; } return alt_msgdma_start_prefetcher_with_list_addr (dev, (uintptr_t)list, park_mode_en, poll_en); } int alt_msgdma_start_prefetcher_with_extd_desc_list ( alt_msgdma_dev *dev, alt_msgdma_prefetcher_extended_descriptor *list, alt_u8 park_mode_en, alt_u8 poll_en) { if (alt_msgdma_prefetcher_set_extd_list_own_by_hw_bits(list) != 0){ return -EINVAL; } return alt_msgdma_start_prefetcher_with_list_addr (dev, (uintptr_t)list, park_mode_en, poll_en); } /* * alt_msgdma_open - Retrieve a pointer to the msgdma * * Search the list of registered msgdma for one with the supplied name. * * The return value will be NULL on failure, and non-NULL otherwise. * * Arguments: * - *name: Character pointer to name of msgdma peripheral as registered * with the HAL. For example, an msgdma controller named "msgdma_0" * in Qsys would be opened by asking for "/dev/msgdma_0_csr". * * Returns: * - Pointer to msgdma device instance structure, or null if the device * could not be opened. */ alt_msgdma_dev* alt_msgdma_open (const char* name) { alt_msgdma_dev* dev = NULL; dev = (alt_msgdma_dev*) alt_find_dev (name, &alt_msgdma_list); if (NULL == dev) { ALT_ERRNO = ENODEV; } return dev; } /* * alt_msgdma_init() * * Initializes the Modular Scatter-Gather DMA controller. This routine is called * from the ALTERA_MSGDMA_INIT macro and is called automatically * by alt_sys_init.c * * This routine disables interrupts, descriptor processing, * registers a specific instance of the device with the HAL, * and installs an interrupt handler for the device. */ void alt_msgdma_init (alt_msgdma_dev *dev, alt_u32 ic_id, alt_u32 irq) { extern alt_llist alt_msgdma_list; alt_u32 temporary_control; int error; if (dev->prefetcher_enable) { /* start prefetcher reset sequence */ IOWR_ALT_MSGDMA_PREFETCHER_CONTROL(dev->prefetcher_base, ALT_MSGDMA_PREFETCHER_CTRL_RESET_SET_MASK); /* wait until hw clears the bit */ while(ALT_MSGDMA_PREFETCHER_CTRL_RESET_GET( IORD_ALT_MSGDMA_PREFETCHER_CONTROL(dev->prefetcher_base))); /* * This reset is intended to be used along with reset dispatcher in * dispatcher core. Once the reset sequence in prefetcher core has * completed, software is expected to reset the dispatcher core, * and polls for dispatcherÂ’s reset sequence to be completed. */ } /* Reset the registers and FIFOs of the dispatcher and master modules */ /* set the reset bit, no need to read the control register first since this write is going to clear it out */ IOWR_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base, ALTERA_MSGDMA_CSR_RESET_MASK); while(0 != (IORD_ALTERA_MSGDMA_CSR_STATUS(dev->csr_base) & ALTERA_MSGDMA_CSR_RESET_STATE_MASK)); /* * Disable interrupts, halt descriptor processing, * and clear status register content */ /* disable global interrupt */ temporary_control = IORD_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base) & (~ALTERA_MSGDMA_CSR_GLOBAL_INTERRUPT_MASK); /* stopping descriptor */ temporary_control |= ALTERA_MSGDMA_CSR_STOP_DESCRIPTORS_MASK; IOWR_ALTERA_MSGDMA_CSR_CONTROL(dev->csr_base, temporary_control); /* clear the CSR status register */ IOWR_ALTERA_MSGDMA_CSR_STATUS(dev->csr_base, IORD_ALTERA_MSGDMA_CSR_STATUS(dev->csr_base)); if (dev->prefetcher_enable) { /* clear all status bits that are set, since theyre W1C */ IOWR_ALT_MSGDMA_PREFETCHER_STATUS(dev->prefetcher_base, IORD_ALT_MSGDMA_PREFETCHER_STATUS(dev->prefetcher_base)); } /* Register this instance of the msgdma controller with HAL */ alt_dev_llist_insert((alt_dev_llist*) dev, &alt_msgdma_list); /* * Creating semaphores used to protect access to the registers * when running in a multi-threaded environment. */ error = ALT_SEM_CREATE (&dev->regs_lock, 1); if (!error) { /* Install IRQ handler */ alt_ic_isr_register(ic_id, irq, alt_msgdma_irq, dev, 0x0); } else { alt_printf("failed to create semaphores\n"); } return; } /* * alt_msgdma_register_callback * * Associate a user-specific routine with the msgdma interrupt handler. * If a callback is registered, all non-blocking msgdma transfers will * enable interrupts that will cause the callback to be executed. * The callback runs as part of the interrupt service routine, and * great care must be taken to follow the guidelines for acceptable * interrupt service routine behaviour as described in the Nios II * Software Developer's Handbook.However, user can change some of the CSR * control setting in blocking transfer by calling this function. * * Note: To disable callbacks after registering one, this routine * may be called passing 0x0 to the callback argument. * * Arguments: * - *dev: Pointer to msgdma device (instance) structure. * - callback: Pointer to callback routine to execute at interrupt level * - control: For masking the source interruption and setting configuration in * control register */ void alt_msgdma_register_callback( alt_msgdma_dev *dev, alt_msgdma_callback callback, alt_u32 control, void *context) { dev->callback = callback; dev->callback_context = context; dev->control = control; return ; } /* * alt_msgdma_standard_descriptor_async_transfer * * Set up and commence a non-blocking transfer of one descriptors at a time. * * If the FIFO buffer for one of read/write is full at the time of this call, * the routine will immediately return -ENOSPC, the application can then decide * how to proceed without being blocked. * * Arguments: * - *dev: Pointer to msgdma device (instance) struct. * - *desc: Pointer to single (ready to run) descriptor. * * Returns: * 0 -> success * -ENOSPC -> FIFO descriptor buffer is full * -EPERM -> operation not permitted due to descriptor type conflict * -ETIME -> Time out and skipping the looping after 5 msec. */ int alt_msgdma_standard_descriptor_async_transfer( alt_msgdma_dev *dev, alt_msgdma_standard_descriptor *desc) { /* * Error detection/handling should be performed at the application * or callback level as appropriate. */ return alt_msgdma_descriptor_async_transfer(dev, desc, NULL); } /* * alt_msgdma_extended_descriptor_async_transfer * * Set up and commence a non-blocking transfer of one descriptors at a time. * * If the FIFO buffer for one of read/write is full at the time of this call, * the routine will immediately return -ENOSPC, the application can then * decide how to proceed without being blocked. * * Arguments: * - *dev: Pointer to msgdma device (instance) struct. * - *desc: Pointer to single (ready to run) descriptor. * * Returns: * 0 -> success * -ENOSPC -> FIFO descriptor buffer is full * -EPERM -> operation not permitted due to descriptor type conflict * -ETIME -> Time out and skipping the looping after 5 msec. */ int alt_msgdma_extended_descriptor_async_transfer( alt_msgdma_dev *dev, alt_msgdma_extended_descriptor *desc) { /* * Error detection/handling should be performed at the application * or callback level as appropriate. */ return alt_msgdma_descriptor_async_transfer(dev, NULL, desc); } /* * alt_msgdma_standard_descriptor_sync_transfer * * This function will start commencing a blocking transfer of one standard * descriptor at a time. If the FIFO buffer for one of read/write is full at the * time of this call, the routine will wait until free FIFO buffer available for * continue processing. * * The function will return "-1" if errors or conditions causing the dispatcher * stop issuing the commands to both read and write masters before both read and * write command buffers are empty. * * Additional error information is available in the status bits of * each descriptor that the msgdma processed; it is the responsibility * of the user's application to search through the descriptor * to gather specific error information. * * Arguments: * - *dev: Pointer to msgdma device (instance) structure. * - *desc: Pointer to single (ready to run) descriptor. * * Returns: * - status: return 0 (success) * return error (errors or conditions causing msgdma stop issuing * commands to masters) * Suggest suggest checking the bit set in the error with CSR status * register. * return -EPERM (operation not permitted due to descriptor type * conflict) * return -ETIME (Time out and skipping the looping after 5 msec) */ int alt_msgdma_standard_descriptor_sync_transfer( alt_msgdma_dev *dev, alt_msgdma_standard_descriptor *desc) { return alt_msgdma_descriptor_sync_transfer(dev, desc, NULL); } /* * alt_msgdma_extended_descriptor_sync_transfer * * This function will start commencing a blocking transfer of one extended * descriptor at a time. If the FIFO buffer for one of read/write is full at the * time of this call, the routine will wait until free FIFO buffer available for * continue processing. * * The function will return "-1" if errors or conditions causing the dispatcher * stop issuing the commands to both read and write masters before both read and * write command buffers are empty. * * Additional error information is available in the status bits of * each descriptor that the msgdma processed; it is the responsibility * of the user's application to search through the descriptor * to gather specific error information. * * * Arguments: * - *dev: Pointer to msgdma device (instance) structure. * - *desc: Pointer to single (ready to run) descriptor. * * Returns: * - status: return 0 (success) * return error (errors or conditions causing msgdma stop issuing * commands to masters) * Suggest suggest checking the bit set in the error with CSR status * register. * return -EPERM (operation not permitted due to descriptor type * conflict) * return -ETIME (Time out and skipping the looping after 5 msec) */ int alt_msgdma_extended_descriptor_sync_transfer( alt_msgdma_dev *dev, alt_msgdma_extended_descriptor *desc) { return alt_msgdma_descriptor_sync_transfer(dev, NULL, desc); }