/** exmimo_fw.c * * Initialization routines for * Shared Memory management for ExMIMO and PC(kernel) data exchange * (memory allocation, pointer management) * * There is now one pci_alloc_consistent for each RX and TX buffer * and one for all structures, including pointers, printk, firmware_dump and config * * Authors: Matthias Ihmig , 2012, 2013 * Riadh Ghaddab * Raymond Knopp * * Changelog: * 24.01.2013: added memory management functions for bigshm, lots of cleanups */ #include #include "extern.h" #include "defs.h" #include "pcie_interface.h" /***************************************************** * Private functions within this file */ void mem_SetPageReserved(void *kvirt_addr, unsigned int size_pages) { size_t temp_size = size_pages << PAGE_SHIFT; void *adr = kvirt_addr; while (temp_size > 0) { SetPageReserved( virt_to_page(adr) ); adr += PAGE_SIZE; temp_size -= PAGE_SIZE; } } void mem_ClearPageReserved(void *kvirt_addr, unsigned int size_pages) { size_t temp_size = size_pages << PAGE_SHIFT; void *adr = kvirt_addr; while (temp_size > 0) { ClearPageReserved( virt_to_page(adr) ); adr += PAGE_SIZE; temp_size -= PAGE_SIZE; } } // allocates big shared memory, to be used for structures, pointers, etc. // bigshm allocs a single larger memory block for shared structures and pointers, one per card, except: ADC+DAC buffers! // returns -1 on error, 0 on success int bigshm_init(int card) { printk("[openair][module] calling pci_alloc_consistent for card %d, bigshm (size: %u*%lu bytes)...\n", card, BIGSHM_SIZE_PAGES, PAGE_SIZE); if ( sizeof(dma_addr_t) != 4) printk("!!! WARNING: sizeof (dma_addr_t) = %d! Only 32bit mode (= 4) (also: no PAE) is supported at this time!\n", sizeof(dma_addr_t)); if ( bigshm_head[card] == NULL ) bigshm_head[card] = pci_alloc_consistent( pdev[card], BIGSHM_SIZE_PAGES< (BIGSHM_SIZE_PAGES<firmware_block_ptr)); printk("firmware_code_block_ptr : %p (phys = %08x)\n", exmimo_pci_kvirt[card_id].firmware_block_ptr, p_exmimo_pci_phys[card_id]->firmware_block_ptr); exmimo_pci_kvirt[card_id].printk_buffer_ptr = (char *) bigshm_assign( card_id, MAX_PRINTK_BUFFER_B, (dma_addr_t*)&(p_exmimo_pci_phys[card_id]->printk_buffer_ptr)); printk("printk_buffer_ptr : %p (phys = %08x)\n", exmimo_pci_kvirt[card_id].printk_buffer_ptr, p_exmimo_pci_phys[card_id]->printk_buffer_ptr); exmimo_pci_kvirt[card_id].exmimo_config_ptr = (exmimo_config_t *) bigshm_assign( card_id, sizeof(exmimo_config_t), (dma_addr_t*)&(p_exmimo_pci_phys[card_id]->exmimo_config_ptr)); printk("exmimo_config_ptr : %p (phys = %08x)\n", exmimo_pci_kvirt[card_id].exmimo_config_ptr, p_exmimo_pci_phys[card_id]->exmimo_config_ptr); exmimo_pci_kvirt[card_id].exmimo_id_ptr = (exmimo_id_t *) bigshm_assign( card_id, sizeof(exmimo_id_t), (dma_addr_t*)&(p_exmimo_pci_phys[card_id]->exmimo_id_ptr)); printk("exmimo_id_ptr : %p (phys = %08x)\n", exmimo_pci_kvirt[card_id].exmimo_id_ptr, p_exmimo_pci_phys[card_id]->exmimo_id_ptr); if ( p_exmimo_pci_phys[card_id] == NULL || exmimo_pci_kvirt[card_id].firmware_block_ptr == NULL || exmimo_pci_kvirt[card_id].printk_buffer_ptr == NULL || exmimo_pci_kvirt[card_id].exmimo_config_ptr == NULL || exmimo_pci_kvirt[card_id].exmimo_id_ptr == NULL ) return -1; for (j=0; jrxcnt_ptr[j]) ); printk("exmimo_pci_kvirt[%d].rxcnt_ptr[%d] = %p (phys = %08x)\n", card_id, j, exmimo_pci_kvirt[card_id].rxcnt_ptr[j], p_exmimo_pci_phys[card_id]->rxcnt_ptr[j]); exmimo_pci_kvirt[card_id].txcnt_ptr[j] = (uint32_t *) bigshm_assign( card_id, 4*4, (dma_addr_t*)&(p_exmimo_pci_phys[card_id]->txcnt_ptr[j]) ); printk("exmimo_pci_kvirt[%d].txcnt_ptr[%d] = %p (phys = %08x)\n", card_id, j, exmimo_pci_kvirt[card_id].txcnt_ptr[j], p_exmimo_pci_phys[card_id]->txcnt_ptr[j]); if ( exmimo_pci_kvirt[card_id].rxcnt_ptr[j] == NULL || exmimo_pci_kvirt[card_id].txcnt_ptr[j] == NULL) return -1; } } return 0; } // allocate memory for RX and TX chains for all antennas // returns -1 on error, 0 on success int exmimo_allocate_rx_tx_buffers(int card_id) { size_t size; int j; // Round up to the next PAGE_SIZE (typ. 4096 bytes) size = (ADAC_BUFFERSZ_PERCHAN_B >> PAGE_SHIFT) + 1; size <<= PAGE_SHIFT; for (j=0; jadc_head[j]) ); printk("exmimo_pci_kvirt[%d].adc_head[%d] = %p (phys = %08x)\n", card_id, j, exmimo_pci_kvirt[card_id].adc_head[j], p_exmimo_pci_phys[card_id]->adc_head[j]); if ( exmimo_pci_kvirt[card_id].adc_head[j] == NULL) return -1; mem_SetPageReserved( exmimo_pci_kvirt[card_id].adc_head[j], size >> PAGE_SHIFT ); memset( exmimo_pci_kvirt[card_id].adc_head[j], 0x10+j, size); exmimo_pci_kvirt[card_id].dac_head[j] = (uint32_t *)pci_alloc_consistent( pdev[card_id], size, (dma_addr_t*)&(p_exmimo_pci_phys[card_id]->dac_head[j]) ); printk("exmimo_pci_kvirt[%d].dac_head[%d] = %p (phys = %08x)\n", card_id, j, exmimo_pci_kvirt[card_id].dac_head[j], p_exmimo_pci_phys[card_id]->dac_head[j]); if ( exmimo_pci_kvirt[card_id].dac_head[j] == NULL) return -ENOMEM; mem_SetPageReserved( exmimo_pci_kvirt[card_id].dac_head[j], size >> PAGE_SHIFT ); memset( exmimo_pci_kvirt[card_id].dac_head[j], 0x20+j, size); } return 0; } /********************************************* * Public functions ExpressMIMO Interface */ /* Allocates buffer and assigns pointers * * return 0 on success */ int exmimo_memory_alloc(int card) { if ( bigshm_init( card ) ) { printk("exmimo_memory_alloc(): bigshm_init failed for card %d.\n", card); return -ENOMEM; } if ( exmimo_assign_shm_vars( card ) ) { printk("exmimo_memory_alloc(): exmimo_assign_shm_vars failed to assign enough shared memory for all variables and structures for card %i!\n", card); return -ENOMEM; } if ( exmimo_allocate_rx_tx_buffers( card ) ) { printk("exmimo_memory_alloc(): exmimo_allocate_rx_tx_buffers() failed to allocate enough memory for RX and TX buffers for card %i!\n", card); return -ENOMEM; } return 0; } /* * Copies pointer to Leon */ int exmimo_firmware_init(int card) { /* pci_dma_sync_single_for_device(pdev[card], pphys_exmimo_pci_phys[card], sizeof(exmimo_pci_interface_bot_t), PCI_DMA_TODEVICE); */ // put DMA pointer to exmimo_pci_interface_bot into LEON register iowrite32( pphys_exmimo_pci_phys[card], (bar[card]+PCIE_PCIBASEL) ); // lower 32bit of address iowrite32( 0, (bar[card]+PCIE_PCIBASEH) ); // higher 32bit of address if (exmimo_pci_kvirt[card].exmimo_id_ptr->board_swrev == BOARD_SWREV_CMDREGISTERS) iowrite32( EXMIMO_CONTROL2_COOKIE, bar[card]+ PCIE_CONTROL2); //printk("exmimo_firmware_init(): initializing Leon (EXMIMO_PCIE_INIT)...\n"); exmimo_send_pccmd(card, EXMIMO_PCIE_INIT); return 0; } /* * Free memory on unloading the kernel driver */ int exmimo_firmware_cleanup(int card) { size_t size; int j; // free exmimo_allocate_rx_tx_buffers size = (ADAC_BUFFERSZ_PERCHAN_B >> PAGE_SHIFT) + 1; size <<= PAGE_SHIFT; for (j=0; j> PAGE_SHIFT ); pci_free_consistent( pdev[card], size, exmimo_pci_kvirt[card].adc_head[j], p_exmimo_pci_phys[card]->adc_head[j] ); } if ( exmimo_pci_kvirt[card].dac_head[j] ) { mem_ClearPageReserved( exmimo_pci_kvirt[card].dac_head[j], size >> PAGE_SHIFT ); pci_free_consistent( pdev[card], size, exmimo_pci_kvirt[card].dac_head[j], p_exmimo_pci_phys[card]->dac_head[j] ); } } if ( bigshm_head[card] ) { printk("free bigshm_head[%d] pdev %p, size %u, head %p, phys %x\n", card, pdev[card], BIGSHM_SIZE_PAGES< sleep while (cnt<100 && ( ioread32(bar[card_id]+PCIE_CONTROL1) != EXMIMO_NOP )) { //printk("ctrl0: %08x, ctrl1: %08x, ctrl2: %08x, status: %08x\n", ioread32(bar[card_id]+PCIE_CONTROL0), ioread32(bar[card_id]+PCIE_CONTROL1), ioread32(bar[card_id]+PCIE_CONTROL2), ioread32(bar[card_id]+PCIE_STATUS)); msleep(100); cnt++; } if (cnt==100) printk("exmimo_send_pccmd error: Timeout: no EXMIMO_NOP received within 10sec for card%d, pccmd=%x\n", card_id, cmd); //printk("Ctrl0: %08x, ctrl1: %08x, ctrl2: %08x, status: %08x\n", ioread32(bar[card_id]+PCIE_CONTROL0), ioread32(bar[card_id]+PCIE_CONTROL1), ioread32(bar[card_id]+PCIE_CONTROL2), ioread32(bar[card_id]+PCIE_STATUS)); return(0); }