new driver for exmimo3
git-svn-id: http://svn.eurecom.fr/openair4G/trunk@5596 818b1a75-f10b-46b9-bf7c-635c3b92a50f
This commit is contained in:
Executable
+22
@@ -0,0 +1,22 @@
|
||||
CCC = gcc
|
||||
KERNEL_MAIN_TYPE=$(shell echo `uname -r | cut -d. -f-2 | tr "." "_"`)
|
||||
export KERNEL_MAIN_TYPE
|
||||
|
||||
SUBVERSION=$(shell echo `grep '^SUBLEVEL =' /usr/src/linux/Makefile | sed -e 's, ,,g' | sed -e 's/SUBLEVEL=//'`)
|
||||
IS_KERNEL_SUBVERSION_GREATER_THAN_20=$(shell if [ $(SUBVERSION) -ge 20 ] ; then echo true ; fi)
|
||||
|
||||
EXTRA_CFLAGS = -ggdb -D__KERNEL__ -DMODULE -D_LOOSE_KERNEL_NAMES -I/lib/modules/$(shell uname -r)/build/include -I/lib/modules/$(shell uname -r)/build/include/asm/mach-default -include /lib/modules/$(shell uname -r)/build/include/linux/autoconf.h
|
||||
|
||||
EXTRA_CFLAGS += -I$(PWD)/../../DEFS
|
||||
|
||||
obj-m += openair_rf.o
|
||||
|
||||
openair_rf-objs += module_main.o irq.o fileops.o exmimo_fw.o
|
||||
|
||||
all:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
rm -rf *.o
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
echo "Hint: this may not work if /usr/src/linux is not set to currently booted kernel."
|
||||
echo "Try 'make' instead."
|
||||
|
||||
make -C /usr/src/linux V=1 M=`pwd`
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
#ifndef __DEFS_H__
|
||||
#define __DEFS_H__
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/bitops.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/delay.h>
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mman.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
//#include <linux/config.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include <linux/errno.h>
|
||||
|
||||
#ifdef KERNEL2_6
|
||||
#include <linux/slab.h>
|
||||
#endif
|
||||
|
||||
#include "openair_device.h"
|
||||
|
||||
#include "linux/moduleparam.h"
|
||||
|
||||
|
||||
/*------------------------------------------------*/
|
||||
/* Prototypes */
|
||||
/*------------------------------------------------*/
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
|
||||
long openair_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
|
||||
#else
|
||||
int openair_device_ioctl(struct inode *inode,struct file *filp, unsigned int cmd, unsigned long arg);
|
||||
#endif
|
||||
int openair_device_open (struct inode *inode,struct file *filp);
|
||||
int openair_device_release (struct inode *inode,struct file *filp);
|
||||
int openair_device_mmap (struct file *filp, struct vm_area_struct *vma);
|
||||
|
||||
int exmimo_memory_alloc(int card);
|
||||
int exmimo_firmware_init(int card);
|
||||
int exmimo_firmware_cleanup(int card_id);
|
||||
|
||||
int exmimo_send_pccmd(int card_id, unsigned int cmd);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Re-Enumerate FPGA card
|
||||
|
||||
# After resetting or powering up the card or after reloading the FPGA bitstream,
|
||||
# run this script to re-enumerate the PCIe device in Linux.
|
||||
|
||||
# You may need to change the device path. Check lspci output for this.
|
||||
|
||||
# You need to run this as root:
|
||||
# sudo ./do_reenumerate_expressmimo.sh
|
||||
|
||||
# Matthias <ihmig@eurecom.fr>, 2013
|
||||
|
||||
rmmod openair_rf
|
||||
echo 1 > /sys/bus/pci/devices/0000\:01\:00.0/remove
|
||||
echo 1 > /sys/bus/pci/devices/0000\:05\:00.0/remove
|
||||
echo 1 > /sys/bus/pci/rescan
|
||||
|
||||
insmod openair_rf.ko
|
||||
@@ -0,0 +1 @@
|
||||
rmmod openair_rf && sleep 1 ; insmod openair_rf.ko
|
||||
@@ -0,0 +1,337 @@
|
||||
/** 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 <matthias.ihmig@mytum.de>, 2012, 2013
|
||||
* Riadh Ghaddab <riadh.ghaddab@eurecom.fr>
|
||||
* Raymond Knopp <raymond.knopp@eurecom.fr>
|
||||
*
|
||||
* Changelog:
|
||||
* 24.01.2013: added memory management functions for bigshm, lots of cleanups
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#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: %lu*%lu bytes)...\n", card, BIGSHM_SIZE_PAGES, PAGE_SIZE);
|
||||
|
||||
if ( sizeof(dma_addr_t) != 4)
|
||||
printk("!!! WARNING: sizeof (dma_addr_t) = %lu! 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<<PAGE_SHIFT, &bigshm_head_phys[card] );
|
||||
|
||||
if (bigshm_head[card] == NULL) {
|
||||
printk("[openair][MODULE][ERROR] Cannot Allocate Memory (%lu bytes) for shared data (bigshm)\n", BIGSHM_SIZE_PAGES<<PAGE_SHIFT);
|
||||
return -ENOMEM;
|
||||
}
|
||||
else {
|
||||
printk("[openair][MODULE][INFO] Bigshm at %p (phys %x)\n", bigshm_head[card], (unsigned int) bigshm_head_phys[card]);
|
||||
|
||||
bigshm_currentptr[card] = bigshm_head[card];
|
||||
|
||||
mem_SetPageReserved( bigshm_head[card], BIGSHM_SIZE_PAGES);
|
||||
memset(bigshm_head[card], 0, BIGSHM_SIZE_PAGES << PAGE_SHIFT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// use this instead of pci_alloc_consistent to assign memory from the bigshm block
|
||||
// return kernel virtual pointer and sets physical DMA address in dma_handle
|
||||
void *bigshm_assign( int card, size_t size_bytes, dma_addr_t *dma_handle_ptr )
|
||||
{
|
||||
void *ret;
|
||||
size_t size = size_bytes;
|
||||
|
||||
//size = (size-1) + 4 - ( (size-1) % 4); // round up to keep addresses aligned to DWs
|
||||
//size = (size-1) + 16 - ( (size-1) % 16); // round up to keep addresses aligned to 4 DWs
|
||||
|
||||
// round up to the next 64 DW (workaround for current bug in DMA on ExMIMO2)
|
||||
size = (size-1) + 256 - ( (size-1) % 256);
|
||||
|
||||
if ( (bigshm_currentptr[card] - bigshm_head[card]) > (BIGSHM_SIZE_PAGES<<PAGE_SHIFT) -size ) {
|
||||
printk("Not enough memory in bigshm! Make BIGSHM_SIZE_PAGES bigger!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*dma_handle_ptr = bigshm_head_phys[card] + ( (dma_addr_t)bigshm_currentptr[card] - (dma_addr_t)bigshm_head[card] );
|
||||
ret = bigshm_currentptr[card];
|
||||
bigshm_currentptr[card] = (char *)bigshm_currentptr[card] + size;
|
||||
|
||||
//printk("bigshm_assign: size %d, virt = %p, dma = %x, bigshm_phys=%x, _current=%p, _head=%p\n",
|
||||
// size, ret, *dma_handle_ptr, bigshm_head_phys[card], bigshm_currentptr[card], bigshm_head[card]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// assign shared memory between card an PC for data exchange: interface structure with pointers,
|
||||
// firmware- and printk buffers, configuration structure
|
||||
// returns -1 on error, 0 on success
|
||||
int exmimo_assign_shm_vars(int card_id)
|
||||
{
|
||||
int j;
|
||||
|
||||
if (p_exmimo_pci_phys[card_id] == NULL)
|
||||
{
|
||||
p_exmimo_pci_phys[card_id] = (exmimo_pci_interface_bot_t *) bigshm_assign( card_id,
|
||||
sizeof(exmimo_pci_interface_bot_t),
|
||||
&pphys_exmimo_pci_phys[card_id]);
|
||||
printk("Intializing EXMIMO interface support (exmimo_pci_bot at %p, phys %x, size %lu bytes)\n",p_exmimo_pci_phys[card_id],(unsigned int)pphys_exmimo_pci_phys[card_id], sizeof(exmimo_pci_interface_bot_t));
|
||||
|
||||
exmimo_pci_kvirt[card_id].firmware_block_ptr = (char *) bigshm_assign( card_id,
|
||||
MAX_FIRMWARE_BLOCK_SIZE_B,
|
||||
(dma_addr_t*)&(p_exmimo_pci_phys[card_id]->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; j<MAX_ANTENNAS; j++)
|
||||
{
|
||||
// size 4*1 should be sufficient, but just to make sure we can also use DMA of size 4DW as fallback
|
||||
exmimo_pci_kvirt[card_id].rxcnt_ptr[j] = (uint32_t *) bigshm_assign( card_id, 4*4,
|
||||
(dma_addr_t*)&(p_exmimo_pci_phys[card_id]->rxcnt_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,i;
|
||||
dma_addr_t dma_addr_dummy;
|
||||
// Round up to the next PAGE_SIZE (typ. 4096 bytes)
|
||||
size = (ADAC_BUFFERSZ_PERCHAN_B >> PAGE_SHIFT) + 1;
|
||||
size <<= PAGE_SHIFT;
|
||||
|
||||
for (j=0; j<MAX_ANTENNAS; j++)
|
||||
{
|
||||
|
||||
exmimo_pci_kvirt[card_id].adc_head[j] = (uint32_t *)pci_alloc_consistent( pdev[card_id], size, &dma_addr_dummy);
|
||||
p_exmimo_pci_phys[card_id]->adc_head[j]=((uint32_t*)&dma_addr_dummy)[0];
|
||||
|
||||
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;
|
||||
// printk("[MODULE MAIN0]Phys address TX[0] : (%8lx)\n",p_exmimo_pci_phys[0]->dac_head[ openair_mmap_getAntTX(2) ]);
|
||||
|
||||
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);
|
||||
|
||||
// printk("[MODULE MAIN1]Phys address TX[0] : (%8lx)\n",p_exmimo_pci_phys[0]->dac_head[ openair_mmap_getAntTX(2) ]);
|
||||
|
||||
exmimo_pci_kvirt[card_id].dac_head[j] = (uint32_t *)pci_alloc_consistent( pdev[card_id], size,&dma_addr_dummy);
|
||||
p_exmimo_pci_phys[card_id]->dac_head[j]=((uint32_t*)&dma_addr_dummy)[0];
|
||||
|
||||
// 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;
|
||||
// printk("[MODULE MAIN2]Phys address TX[0] : (%8lx)\n",p_exmimo_pci_phys[0]->dac_head[ openair_mmap_getAntTX(2) ]);
|
||||
|
||||
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);
|
||||
// printk("[MODULE MAIN3]Phys address TX[0] : (%8lx)\n",p_exmimo_pci_phys[0]->dac_head[ openair_mmap_getAntTX(2) ]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
* Public functions ExpressMIMO Interface
|
||||
*/
|
||||
|
||||
/* Allocates buffer and assigns pointers
|
||||
*
|
||||
* return 0 on success
|
||||
*/
|
||||
int exmimo_memory_alloc(int card)
|
||||
{
|
||||
int i;
|
||||
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)
|
||||
{
|
||||
|
||||
// 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
|
||||
|
||||
iowrite32(pphys_exmimo_pci_phys[card]-> p_exmimo_pci_phys[card_id]->adc_head[j]);
|
||||
|
||||
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<MAX_ANTENNAS; j++)
|
||||
{
|
||||
if ( exmimo_pci_kvirt[card].adc_head[j] ) {
|
||||
mem_ClearPageReserved( exmimo_pci_kvirt[card].adc_head[j], size >> 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 %lu, head %p, phys %x\n", card, pdev[card], BIGSHM_SIZE_PAGES<<PAGE_SHIFT, bigshm_head[card], (unsigned int)bigshm_head_phys[card]);
|
||||
mem_ClearPageReserved( bigshm_head[card], BIGSHM_SIZE_PAGES );
|
||||
|
||||
pci_free_consistent( pdev[card], BIGSHM_SIZE_PAGES<<PAGE_SHIFT, bigshm_head[card], bigshm_head_phys[card]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Send command to Leon and wait until command is completed
|
||||
*/
|
||||
int exmimo_send_pccmd(int card_id, unsigned int cmd)
|
||||
{
|
||||
unsigned int val;
|
||||
unsigned int cnt=0;
|
||||
|
||||
//printk("Sending command to ExpressMIMO (card %d) : %x\n",card_id, cmd);
|
||||
iowrite32(cmd,(bar[card_id]+PCIE_CONTROL1));
|
||||
// printk("Readback of control1 %x\n",ioread32(bar[0]+PCIE_CONTROL1));
|
||||
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case EXMIMO_CONFIG :
|
||||
|
||||
break;
|
||||
|
||||
case EXMIMO_PCIE_INIT :
|
||||
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// workaround for ExMIMO1&2: no command ack -> 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);
|
||||
}
|
||||
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#ifndef __EXTERN_H__
|
||||
#define __EXTERN_H__
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#ifdef KERNEL2_6
|
||||
#include <linux/slab.h>
|
||||
#endif
|
||||
|
||||
#include "defs.h"
|
||||
#include "pcie_interface.h"
|
||||
|
||||
extern char number_of_cards;
|
||||
|
||||
extern int major;
|
||||
|
||||
extern struct pci_dev *pdev[MAX_CARDS];
|
||||
extern void __iomem *bar[MAX_CARDS];
|
||||
|
||||
extern void *bigshm_head[MAX_CARDS];
|
||||
extern void *bigshm_currentptr[MAX_CARDS];
|
||||
extern dma_addr_t bigshm_head_phys[MAX_CARDS];
|
||||
|
||||
extern dma_addr_t pphys_exmimo_pci_phys[MAX_CARDS];
|
||||
extern exmimo_pci_interface_bot_t *p_exmimo_pci_phys[MAX_CARDS];
|
||||
extern exmimo_pci_interface_bot_virtual_t exmimo_pci_kvirt[MAX_CARDS];
|
||||
|
||||
#endif // __EXTERN_H__
|
||||
Executable
+435
@@ -0,0 +1,435 @@
|
||||
/** fileops.c
|
||||
*
|
||||
* Device IOCTL File Operations on character device /dev/openair0
|
||||
*
|
||||
* Authors: Matthias Ihmig <matthias.ihmig@mytum.de>, 2012, 2013
|
||||
* Riadh Ghaddab <riadh.ghaddab@eurecom.fr>
|
||||
* Raymond Knopp <raymond.knopp@eurecom.fr>
|
||||
*
|
||||
* Changelog:
|
||||
* 14.01.2013: removed remaining of BIGPHYS stuff and replaced with pci_alloc_consistent
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "openair_device.h"
|
||||
#include "defs.h"
|
||||
#include "extern.h"
|
||||
|
||||
#include "pcie_interface.h"
|
||||
|
||||
#define invert4(x) { \
|
||||
unsigned int ltmp; \
|
||||
ltmp=x; x=((ltmp & 0xff)<<24) | ((ltmp & 0xff00)<<8) | \
|
||||
((ltmp & 0xff0000)>>8) | ((ltmp & 0xff000000)>>24); \
|
||||
}
|
||||
|
||||
extern int get_frame_done;
|
||||
|
||||
|
||||
int is_card_num_invalid(int card)
|
||||
{
|
||||
if (card<0 || card>=number_of_cards)
|
||||
{
|
||||
printk("[openair][IOCTL]: ERROR: received invalid card number (%d)!\n", card);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int openair_device_open (struct inode *inode,struct file *filp)
|
||||
{
|
||||
//printk("[openair][MODULE] openair_open()\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int openair_device_release (struct inode *inode,struct file *filp)
|
||||
{
|
||||
// printk("[openair][MODULE] openair_release(), MODE = %d\n",openair_daq_vars.mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int openair_device_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
{
|
||||
unsigned long phys;
|
||||
unsigned long start = (unsigned long)vma->vm_start;
|
||||
unsigned long size = (unsigned long)(vma->vm_end-vma->vm_start);
|
||||
unsigned long maxsize;
|
||||
unsigned int memblock_ind;
|
||||
unsigned int card;
|
||||
|
||||
memblock_ind = openair_mmap_getMemBlock( vma->vm_pgoff );
|
||||
card = openair_mmap_getCard( vma->vm_pgoff );
|
||||
|
||||
/*printk("[openair][MMAP] called (start %lx, end %lx, pg_off %lx, size %lx)\n",
|
||||
vma->vm_start,
|
||||
vma->vm_end,
|
||||
vma->vm_pgoff,
|
||||
size);
|
||||
*/
|
||||
vma->vm_pgoff = 0;
|
||||
|
||||
// not supported by 64 bit kernels
|
||||
//vma->vm_flags |= VM_RESERVED;
|
||||
vma->vm_flags |= VM_IO;
|
||||
|
||||
if ( is_card_num_invalid(card) )
|
||||
return -EINVAL;
|
||||
|
||||
if (memblock_ind == openair_mmap_BIGSHM)
|
||||
{
|
||||
// map a buffer from bigshm
|
||||
maxsize = BIGSHM_SIZE_PAGES<<PAGE_SHIFT;
|
||||
if ( size > maxsize) {
|
||||
printk("[openair][MMAP][ERROR] Trying to map more than %d bytes (req size=%d)\n",
|
||||
(unsigned int)(BIGSHM_SIZE_PAGES<<PAGE_SHIFT), (unsigned int)size);
|
||||
return -EINVAL;
|
||||
}
|
||||
phys = bigshm_head_phys[card];
|
||||
}
|
||||
else if ( (memblock_ind & 1) == 1)
|
||||
{
|
||||
// mmap a RX buffer
|
||||
maxsize = ADAC_BUFFERSZ_PERCHAN_B;
|
||||
if ( size > maxsize) {
|
||||
printk("[openair][MMAP][ERROR] Trying to map more than %d bytes (req size=%d)\n",
|
||||
(unsigned int)(ADAC_BUFFERSZ_PERCHAN_B), (unsigned int)size);
|
||||
return -EINVAL;
|
||||
}
|
||||
phys = p_exmimo_pci_phys[card]->adc_head[ openair_mmap_getAntRX(memblock_ind) ];
|
||||
}
|
||||
else
|
||||
{
|
||||
// mmap a TX buffer
|
||||
maxsize = ADAC_BUFFERSZ_PERCHAN_B;
|
||||
if ( size > maxsize) {
|
||||
printk("[openair][MMAP][ERROR] Trying to map more than %d bytes (%d)\n",
|
||||
(unsigned int)(ADAC_BUFFERSZ_PERCHAN_B), (unsigned int)size);
|
||||
return -EINVAL;
|
||||
}
|
||||
phys = p_exmimo_pci_phys[card]->dac_head[ openair_mmap_getAntTX(memblock_ind) ];
|
||||
}
|
||||
|
||||
if (0)
|
||||
printk("[openair][MMAP] card%d: map phys (%08lx) at start %lx, end %lx, pg_off %lx, size %lx\n",
|
||||
card,
|
||||
phys,
|
||||
vma->vm_start,
|
||||
vma->vm_end,
|
||||
vma->vm_pgoff,
|
||||
size);
|
||||
|
||||
/* loop through all the physical pages in the buffer */
|
||||
/* Remember this won't work for vmalloc()d memory ! */
|
||||
if (remap_pfn_range(vma,
|
||||
start,
|
||||
phys>>PAGE_SHIFT,
|
||||
vma->vm_end-vma->vm_start,
|
||||
vma->vm_page_prot))
|
||||
{
|
||||
printk("[openair][MMAP] ERROR EAGAIN\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
|
||||
long openair_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
#else
|
||||
int openair_device_ioctl(struct inode *inode,struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
#endif
|
||||
{
|
||||
/* arg is not meaningful if no arg is passed in user space */
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int i, c;
|
||||
|
||||
int tmp;
|
||||
|
||||
static unsigned int update_firmware_command;
|
||||
static unsigned int update_firmware_address;
|
||||
static unsigned int update_firmware_length;
|
||||
static unsigned int* update_firmware_kbuffer;
|
||||
static unsigned int* __user update_firmware_ubuffer;
|
||||
static unsigned int update_firmware_start_address;
|
||||
static unsigned int update_firmware_stack_pointer;
|
||||
static unsigned int update_firmware_bss_address;
|
||||
static unsigned int update_firmware_bss_size;
|
||||
unsigned int *fw_block;
|
||||
unsigned int sparc_tmp_0;
|
||||
unsigned int sparc_tmp_1;
|
||||
static unsigned int lendian_length;
|
||||
|
||||
unsigned int get_frame_cnt=0;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case openair_STOP:
|
||||
|
||||
printk("[openair][IOCTL] openair_STOP(card%d)\n", (int)arg);
|
||||
if ( is_card_num_invalid((int)arg) )
|
||||
return -EINVAL;
|
||||
|
||||
exmimo_send_pccmd((int)arg, EXMIMO_STOP);
|
||||
|
||||
break;
|
||||
|
||||
case openair_STOP_WITHOUT_RESET:
|
||||
|
||||
printk("[openair][IOCTL] openair_STOP_WITHOUT_RESET(card%d)\n", (int)arg);
|
||||
if ( is_card_num_invalid((int)arg) )
|
||||
return -EINVAL;
|
||||
|
||||
exmimo_send_pccmd((int)arg, EXMIMO_STOP_WITHOUT_RESET);
|
||||
|
||||
break;
|
||||
|
||||
case openair_GET_FRAME:
|
||||
|
||||
get_frame_cnt=0;
|
||||
get_frame_done = 0;
|
||||
printk("[openair][IOCTL] : openair_GET_FRAME: calling exmimo_send_pccmd(%d, EXMIMO_GET_FRAME)\n", (int)arg);
|
||||
if ( is_card_num_invalid((int)arg) )
|
||||
return -EINVAL;
|
||||
|
||||
exmimo_send_pccmd((int)arg, EXMIMO_GET_FRAME);
|
||||
|
||||
while (get_frame_cnt<10 && !get_frame_done) {
|
||||
msleep(10);
|
||||
get_frame_cnt++;
|
||||
}
|
||||
if (get_frame_cnt==200)
|
||||
printk("[openair][IOCTL] : Get frame error: no IRQ received within 2000ms.\n");
|
||||
|
||||
get_frame_done = 0;
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case openair_GET_BIGSHMTOPS_KVIRT:
|
||||
|
||||
//printk("[openair][IOCTL] : openair_GET_BIGSHMTOPS_KVIRT (0x%p)[0] = %p[0] (bigshm_head) for 0..3 (sizeof %d) \n", (void *)arg, bigshm_head[0], sizeof(bigshm_head));
|
||||
copy_to_user((void *)arg, bigshm_head, sizeof(bigshm_head));
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case openair_GET_PCI_INTERFACE_BOTS_KVIRT:
|
||||
|
||||
//printk("[openair][IOCTL] : openair_GET_PCI_INTERFACE_BOTS_KVIRT: copying exmimo_pci_kvirt(@%8p) to %lx (sizeof %d)\n", &exmimo_pci_kvirt[0], arg, sizeof(exmimo_pci_kvirt));
|
||||
copy_to_user((void *)arg, exmimo_pci_kvirt, sizeof(exmimo_pci_kvirt));
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case openair_GET_NUM_DETECTED_CARDS:
|
||||
|
||||
//printk("[openair][IOCTL] : openair_GET_NUM_DETECTED_CARDS: *(0x%p) = %d\n", (void *)arg, number_of_cards);
|
||||
copy_to_user((void *)arg, &number_of_cards, sizeof(number_of_cards));
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case openair_DUMP_CONFIG:
|
||||
|
||||
//printk("[openair][IOCTL] openair_DUMP_CONFIG(%d)\n", (int)arg);
|
||||
if ( is_card_num_invalid((int)arg) ) {
|
||||
printk("[openair][IOCTL] openair_DUMP_CONFIG: Invalid card number %d.\n", (int)arg);
|
||||
return -EINVAL;
|
||||
}
|
||||
printk("[openair][IOCTL] : openair_DUMP_CONFIG(%d): exmimo_pci_kvirt[%d].exmimo_config_ptr = %p (phys %08x)\n",
|
||||
(int)arg, (int)arg, exmimo_pci_kvirt[(int)arg].exmimo_config_ptr, p_exmimo_pci_phys[(int)arg]->exmimo_config_ptr);
|
||||
|
||||
/*printk("EXMIMO_CONFIG: freq0 %d Hz, freq1 %d Hz, freqtx0 %d Hz, freqtx1 %d Hz, \nRX gain0 %d dB, RX Gain1 %d dB\n",
|
||||
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_rx[0],
|
||||
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_rx[1],
|
||||
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_tx[0],
|
||||
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_tx[1],
|
||||
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rx_gain[0][0],
|
||||
exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rx_gain[1][0]);
|
||||
*/
|
||||
|
||||
exmimo_send_pccmd((int)arg, EXMIMO_CONFIG);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case openair_START_RT_ACQUISITION:
|
||||
|
||||
printk("[openair][IOCTL] openair_START_TX_SIG(%d): send_pccmd(EXMIMO_START_RT_ACQUISITION).\n", (int) arg);
|
||||
if ( is_card_num_invalid((int)arg) )
|
||||
return -EINVAL;
|
||||
|
||||
exmimo_send_pccmd((int)arg, EXMIMO_START_RT_ACQUISITION);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case openair_UPDATE_FIRMWARE:
|
||||
|
||||
printk("[openair][IOCTL] openair_UPDATE_FIRMWARE\n");
|
||||
/***************************************************
|
||||
* Updating the firmware of Cardbus-MIMO-1 or ExpressMIMO SoC *
|
||||
***************************************************/
|
||||
/* 1st argument of this ioctl indicates the action to perform among these:
|
||||
- Transfer a block of data at a specified address (given as the 2nd argument)
|
||||
and for a specified length (given as the 3rd argument, in number of 32-bit words).
|
||||
The USER-SPACE address where to find the block of data is given as the 4th
|
||||
argument.
|
||||
- Ask the Leon processor to clear the .bss section. In this case, the base
|
||||
address of section .bss is given as the 2nd argument, and its size is
|
||||
given as the 3rd one.
|
||||
- Ask the Leon processor to jump at a specified address (given as the 2nd
|
||||
argument, most oftenly expected to be the top address of Ins, Scratch Pad
|
||||
Ram), after having set the stack pointer (given as the 3rd argument).
|
||||
For the openair_UPDATE_FIRMWARE ioctl, we perform a partial infinite loop
|
||||
while acknowledging the PCI irq from Leon software: the max number of loop
|
||||
is yielded by preprocessor constant MAX_IOCTL_ACK_CNT. This avoids handing
|
||||
the kernel with an infinite polling loop. An exception is the case of clearing
|
||||
the bss: it takes time to Leon3 to perform this operation, so we poll te
|
||||
acknowledge with no limit */
|
||||
|
||||
#define MAX_IOCTL_ACK_CNT 500
|
||||
update_firmware_command = *((unsigned int*)arg);
|
||||
|
||||
|
||||
switch (update_firmware_command)
|
||||
{
|
||||
case UPDATE_FIRMWARE_TRANSFER_BLOCK:
|
||||
update_firmware_address = ((unsigned int*)arg)[1];
|
||||
update_firmware_length = ((unsigned int*)arg)[2];
|
||||
|
||||
update_firmware_ubuffer = (unsigned int*)((unsigned int*)arg)[3];
|
||||
update_firmware_kbuffer = (unsigned int*)kmalloc(update_firmware_length * 4 /* 4 because kmalloc expects bytes */,
|
||||
GFP_KERNEL);
|
||||
if (!update_firmware_kbuffer) {
|
||||
printk("[openair][IOCTL] Could NOT allocate %u bytes from kernel memory (kmalloc failed).\n", lendian_length * 4);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// update all cards at the same time
|
||||
for (c=0; c<number_of_cards; c++)
|
||||
{
|
||||
fw_block = (unsigned int *)exmimo_pci_kvirt[c].firmware_block_ptr;
|
||||
/* Copy the data block from user space */
|
||||
fw_block[0] = update_firmware_address;
|
||||
fw_block[1] = update_firmware_length;
|
||||
//printk("copy_from_user %p => %p (pci) => fw[0]=fw_addr=%08x (ahb), fw[1]=fw_length=%d DW\n",update_firmware_ubuffer,&fw_block[16],update_firmware_address,update_firmware_length);
|
||||
tmp = copy_from_user(update_firmware_kbuffer,
|
||||
update_firmware_ubuffer, /* from */
|
||||
update_firmware_length * 4 /* in bytes */
|
||||
);
|
||||
if (tmp) {
|
||||
printk("[openair][IOCTL] Could NOT copy all data from user-space to kernel-space (%d bytes remained uncopied).\n", tmp);
|
||||
return -1;
|
||||
}
|
||||
// pci_map_single(pdev[0],(void*)fw_block, update_firmware_length*4,PCI_DMA_BIDIRECTIONAL);
|
||||
for (i=0;i<update_firmware_length;i++)
|
||||
{
|
||||
fw_block[32+i] = ((unsigned int *)update_firmware_kbuffer)[i];
|
||||
// Endian flipping is done in user-space so undo it
|
||||
invert4(fw_block[32+i]);
|
||||
}
|
||||
|
||||
exmimo_send_pccmd(c, EXMIMO_FW_INIT);
|
||||
printk("[openair][IOCTL] card%d: ok %u DW copied to address 0x%08x (fw_block_ptr %p)\n",
|
||||
c, fw_block[1], fw_block[0],fw_block);
|
||||
}
|
||||
|
||||
kfree(update_firmware_kbuffer);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
for (i=0; i<update_firmware_length;i++) {
|
||||
printk("%08x ", fw_block[32+i]);
|
||||
if ((i % 8) == 7)
|
||||
printk("\n");
|
||||
}*/
|
||||
|
||||
break;
|
||||
|
||||
case UPDATE_FIRMWARE_CLEAR_BSS:
|
||||
|
||||
update_firmware_bss_address = ((unsigned int*)arg)[1];
|
||||
update_firmware_bss_size = ((unsigned int*)arg)[2];
|
||||
sparc_tmp_0 = update_firmware_bss_address;
|
||||
sparc_tmp_1 = update_firmware_bss_size;
|
||||
|
||||
printk("[openair][IOCTL] ok asked Leon to clear .bss (addr 0x%08x, size %d bytes)\n", sparc_tmp_0, sparc_tmp_1);
|
||||
|
||||
// update all cards at the same time
|
||||
for (c=0; c<number_of_cards; c++)
|
||||
{
|
||||
fw_block = (unsigned int *)exmimo_pci_kvirt[c].firmware_block_ptr;
|
||||
fw_block[0] = update_firmware_bss_address;
|
||||
fw_block[1] = update_firmware_bss_size;
|
||||
|
||||
exmimo_send_pccmd(c, EXMIMO_FW_CLEAR_BSS);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case UPDATE_FIRMWARE_START_EXECUTION:
|
||||
|
||||
update_firmware_start_address = ((unsigned int*)arg)[1];
|
||||
update_firmware_stack_pointer = ((unsigned int*)arg)[2];
|
||||
sparc_tmp_0 = update_firmware_start_address;
|
||||
sparc_tmp_1 = update_firmware_stack_pointer;
|
||||
|
||||
printk("[openair][IOCTL] ok asked Leon to set stack and start execution (addr 0x%08x, stackptr %08x)\n", sparc_tmp_0, sparc_tmp_1);
|
||||
|
||||
for (c=0; c<number_of_cards; c++)
|
||||
{
|
||||
fw_block = (unsigned int *)exmimo_pci_kvirt[c].firmware_block_ptr;
|
||||
fw_block[0] = update_firmware_start_address;
|
||||
fw_block[1] = update_firmware_stack_pointer;
|
||||
|
||||
exmimo_send_pccmd(c, EXMIMO_FW_START_EXEC);
|
||||
msleep(10);
|
||||
exmimo_firmware_init(c);
|
||||
}
|
||||
break;
|
||||
|
||||
case UPDATE_FIRMWARE_FORCE_REBOOT:
|
||||
|
||||
printk("[openair][IOCTL] ok asked Leon to reboot.\n");
|
||||
|
||||
for (c=0; c<number_of_cards; c++)
|
||||
{
|
||||
exmimo_send_pccmd(c, EXMIMO_REBOOT);
|
||||
|
||||
exmimo_firmware_init(c);
|
||||
}
|
||||
break;
|
||||
|
||||
case UPDATE_FIRMWARE_TEST_GOK:
|
||||
printk("[openair][IOCTL] TEST_GOK command doesn't work with ExpressMIMO. Ignored.\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
//----------------------
|
||||
printk("[IOCTL] openair_IOCTL unknown: basecmd = %i (cmd=%X)\n", _IOC_NR(cmd), cmd );
|
||||
return -EPERM;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
/** irq.c
|
||||
- IRQ Handler: IRQ from Leon to PCIe/Kernel: exmimo_irq_handler
|
||||
- sends received packets to userspace
|
||||
|
||||
- send command from PC to Leon and trigger IRQ on Leon using CONTROL1 register
|
||||
- commands are defined in $OPENAIR0/express-mimo/software/pcie_interface.h
|
||||
|
||||
- added: pass card_id as parameter to tasklet and irq handler
|
||||
|
||||
Authors:
|
||||
Raymond Knopp <raymond.knopp@eurecom.fr>
|
||||
Matthias Ihmig <matthias.ihmig@mytum.de>, 2011, 2013
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/swab.h>
|
||||
|
||||
#include "openair_device.h"
|
||||
#include "extern.h"
|
||||
|
||||
unsigned int openair_bh_cnt;
|
||||
|
||||
int get_frame_done = 0;
|
||||
|
||||
void pcie_printk(int card_id);
|
||||
|
||||
void openair_do_tasklet (unsigned long card_id);
|
||||
DECLARE_TASKLET (openair_tasklet, openair_do_tasklet, 0);
|
||||
|
||||
irqreturn_t openair_irq_handler(int irq, void *cookie)
|
||||
{
|
||||
unsigned int irqval;
|
||||
unsigned int irqcmd = EXMIMO_NOP;
|
||||
unsigned long card_id; // = (unsigned long) cookie;
|
||||
unsigned int pcie_control = PCIE_CONTROL2;
|
||||
|
||||
// check interrupt status register
|
||||
//pci_read_config_word(pdev[0],6 , &irqval);
|
||||
|
||||
// find card_id. cookie is set by request_irq and static, so we will always find it
|
||||
for (card_id=0; card_id<MAX_CARDS; card_id++)
|
||||
if ( pdev[card_id] == cookie )
|
||||
break;
|
||||
|
||||
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY)
|
||||
pcie_control = PCIE_CONTROL1;
|
||||
else
|
||||
pcie_control = PCIE_CONTROL2;
|
||||
|
||||
//printk("irq hndl called: card_id=%i, irqval=%i\n", card_id, irqval);
|
||||
|
||||
// get AHBPCIE interrupt line (bit 7) to determine if IRQ was for us from ExMIMO card, or from a different device
|
||||
// reading CONTROL0 will also clear this bit and the LEON-to-PC IRQ line
|
||||
irqval = ioread32(bar[card_id]+PCIE_CONTROL0);
|
||||
|
||||
irqcmd = ioread32(bar[card_id]+pcie_control);
|
||||
//printk("IRQ handler: ctrl0: %08x, ctrl1: %08x, ctrl2: %08x, status: %08x\n", irqval, ioread32(bar[card_id]+PCIE_CONTROL1), ioread32(bar[card_id]+PCIE_CONTROL2), ioread32(bar[card_id]+PCIE_STATUS));
|
||||
|
||||
if ( (irqval & 0x80) == 0 ) { // CTRL0.bit7 is no set -> IRQ is not from ExMIMO i.e. not for us
|
||||
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_CMDREGISTERS){
|
||||
if (irqcmd != EXMIMO_NOP && irqcmd != EXMIMO_CONTROL2_COOKIE) {
|
||||
if (irqcmd == GET_FRAME_DONE)
|
||||
{
|
||||
get_frame_done = 1;
|
||||
}
|
||||
openair_tasklet.data = card_id;
|
||||
tasklet_schedule(&openair_tasklet);
|
||||
openair_bh_cnt++;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return IRQ_NONE;
|
||||
}
|
||||
}
|
||||
else
|
||||
return IRQ_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY){
|
||||
// clear PCIE interrupt (bit 7 of register 0x0)
|
||||
iowrite32(irqval&0xffffff7f,bar[card_id]+PCIE_CONTROL0);
|
||||
}
|
||||
if (irqcmd == GET_FRAME_DONE)
|
||||
{
|
||||
get_frame_done = 1;
|
||||
}
|
||||
|
||||
openair_tasklet.data = card_id;
|
||||
tasklet_schedule(&openair_tasklet);
|
||||
openair_bh_cnt++;
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
void openair_do_tasklet (unsigned long card_id)
|
||||
{
|
||||
int save_irq_cnt = openair_bh_cnt;
|
||||
unsigned int irqcmd;
|
||||
unsigned int pcie_control = PCIE_CONTROL2;
|
||||
openair_bh_cnt = 0;
|
||||
|
||||
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY)
|
||||
pcie_control = PCIE_CONTROL1;
|
||||
else
|
||||
pcie_control = PCIE_CONTROL2;
|
||||
|
||||
irqcmd = ioread32(bar[card_id]+pcie_control);
|
||||
|
||||
if (save_irq_cnt > 1)
|
||||
printk("[openair][IRQ tasklet(%ld)]: Warning: received more than 1 PCIE IRQ (openair_bh_cnt=%i), only the last one is acted upon(irqcmd= %i (0x%X)\n", card_id, openair_bh_cnt, irqcmd, irqcmd);
|
||||
|
||||
switch( irqcmd )
|
||||
{
|
||||
case PCI_PRINTK:
|
||||
// printk("Got PCIe interrupt for printk ...\n");
|
||||
pcie_printk((int) card_id);
|
||||
break;
|
||||
|
||||
case GET_FRAME_DONE:
|
||||
printk("[openair][IRQ tasklet] : Got PCIe interrupt for GET_FRAME_DONE ...\n");
|
||||
break;
|
||||
|
||||
case EXMIMO_NOP:
|
||||
printk("[openair][IRQ tasklet] : Received IRQ, with CONTROL0.bit7(IRQ Leon2PC) set, but irqcmd = EXMIMO_NOP. This should not happen with bitstreams built after June 3rd 2013.\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
printk("[openair][IRQ tasklet] : Got unknown PCIe cmd: card_id = %li, irqcmd(CONTROL1) = %i (0x%X)\n", card_id, irqcmd, irqcmd);
|
||||
}
|
||||
|
||||
iowrite32(EXMIMO_NOP, bar[card_id]+pcie_control);
|
||||
}
|
||||
|
||||
void pcie_printk(int card_id)
|
||||
{
|
||||
char *buffer = exmimo_pci_kvirt[card_id].printk_buffer_ptr;
|
||||
unsigned int len = ((unsigned int *)buffer)[0];
|
||||
unsigned int off=0,i;
|
||||
unsigned char *dword;
|
||||
unsigned char tmp;
|
||||
|
||||
//printk("In pci_fifo_printk : buffer %p, len %d: \n",buffer,len);
|
||||
printk("[LEON card%d]: ", card_id);
|
||||
|
||||
if (len<1024)
|
||||
{
|
||||
if ( (len&3) >0 )
|
||||
off=1;
|
||||
|
||||
for (i=0; i<(off+(len>>2)); i++)
|
||||
{
|
||||
dword = &((unsigned char *)buffer)[(1+i)<<2];
|
||||
tmp = dword[3];
|
||||
dword[3] = dword[0];
|
||||
dword[0] = tmp;
|
||||
tmp = dword[2];
|
||||
dword[2] = dword[1];
|
||||
dword[1] = tmp;
|
||||
}
|
||||
for (i=0; i<len; i++)
|
||||
printk("%c",((char*)&buffer[4])[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+333
@@ -0,0 +1,333 @@
|
||||
/** module_main.c (was: device.c)
|
||||
*
|
||||
* Main Kernel module functions for load/init and cleanup of the kernel driver
|
||||
*
|
||||
* Supports multiple ExpressMIMO cards
|
||||
*
|
||||
* Authors: Matthias Ihmig <matthias.ihmig@mytum.de>, 2012, 2013
|
||||
* Riadh Ghaddab <riadh.ghaddab@eurecom.fr>
|
||||
* Raymond Knopp <raymond.knopp@eurecom.fr>
|
||||
*
|
||||
* Changelog:
|
||||
* 14.01.2013: removed remaining of BIGPHYS stuff and replaced with pci_alloc_consistent
|
||||
* 20.01.2013: added support for multiple cards
|
||||
* 24.01.2013: restructured interfaces & structures of how physical and virtual pointers are handled
|
||||
*/
|
||||
|
||||
#include "openair_device.h"
|
||||
#include "defs.h"
|
||||
#include "vars.h"
|
||||
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/aer.h>
|
||||
#include <linux/pci_regs.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
static void openair_cleanup(void);
|
||||
|
||||
extern irqreturn_t openair_irq_handler(int irq, void *cookie);
|
||||
|
||||
static int irq = 0;
|
||||
module_param(irq,int,S_IRUSR|S_IWUSR);
|
||||
|
||||
|
||||
static struct file_operations openair_fops = {
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
|
||||
unlocked_ioctl:openair_device_ioctl,
|
||||
#else
|
||||
ioctl: openair_device_ioctl,
|
||||
#endif
|
||||
open: openair_device_open,
|
||||
release:openair_device_release,
|
||||
mmap: openair_device_mmap
|
||||
};
|
||||
|
||||
static int __init openair_init_module( void )
|
||||
{
|
||||
int res = 0;
|
||||
unsigned int readback;
|
||||
unsigned int card, j;
|
||||
unsigned int vid,did;
|
||||
unsigned short vendor, subid;
|
||||
exmimo_id_t exmimo_id_tmp[MAX_CARDS];
|
||||
|
||||
//------------------------------------------------
|
||||
// Find and enable ExpressMIMO PCI cards
|
||||
//------------------------------------------------
|
||||
//
|
||||
card = 0;
|
||||
|
||||
pdev[card] = pci_get_device(XILINX_VENDOR, XILINX_ID, NULL);
|
||||
|
||||
if( pdev[card] )
|
||||
{
|
||||
// This print does not work for 64 bit kernels
|
||||
// printk("[openair][INIT_MODULE][INFO]: openair card (ExpressMIMO) %d found, bus 0x%x, primary 0x%x, secondary 0x%x\n",card,
|
||||
// pdev[card]->bus->number, pdev[card]->bus->primary,pdev[card]->bus->secondary);
|
||||
|
||||
pci_read_config_word(pdev[card], PCI_SUBSYSTEM_ID, &subid);
|
||||
pci_read_config_word(pdev[card], PCI_SUBSYSTEM_VENDOR_ID, &vendor);
|
||||
exmimo_id_tmp[card].board_vendor = vendor;
|
||||
|
||||
if ( exmimo_id_tmp[card].board_vendor == XILINX_VENDOR )
|
||||
exmimo_id_tmp[card].board_vendor = EURECOM_VENDOR; // set default to EURECOM
|
||||
|
||||
exmimo_id_tmp[card].board_exmimoversion = (subid >> 12) & 0x0F;
|
||||
if (exmimo_id_tmp[card].board_exmimoversion == 0)
|
||||
exmimo_id_tmp[card].board_exmimoversion = 1; // default (for old bitstreams) is ExpressMIMO-1
|
||||
|
||||
exmimo_id_tmp[card].board_hwrev = (subid >> 8) & 0x0F;
|
||||
exmimo_id_tmp[card].board_swrev = (subid ) & 0xFF;
|
||||
|
||||
printk("[openair][INIT_MODULE][INFO]: card %d: ExpressMIMO-%i (HW Rev %i), Bitstream: %s, SW/Protocol Revision: 0x%02X\n", card,
|
||||
exmimo_id_tmp[card].board_exmimoversion, exmimo_id_tmp[card].board_hwrev, ( (exmimo_id_tmp[card].board_vendor == EURECOM_VENDOR) ? "Eurecom" : "Telecom Paristech"), exmimo_id_tmp[card].board_swrev );
|
||||
|
||||
card++;
|
||||
vid = XILINX_VENDOR;
|
||||
did = XILINX_ID;
|
||||
}
|
||||
else {
|
||||
printk("[openair][INIT_MODULE][INFO]: no card found, stopping.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
// Now look for more cards on the same bus
|
||||
while (card<MAX_CARDS)
|
||||
{
|
||||
pdev[card] = pci_get_device(vid,did, pdev[card-1]);
|
||||
if(pdev[card])
|
||||
{
|
||||
// This print does not work for 64 bit kernels
|
||||
// printk("[openair][INIT_MODULE][INFO]: openair card %d found, bus 0x%x, primary 0x%x, secondary 0x%x\n",card,
|
||||
// pdev[card]->bus->number,pdev[card]->bus->primary,pdev[card]->bus->secondary);
|
||||
|
||||
pci_read_config_word(pdev[card], PCI_SUBSYSTEM_ID, &subid);
|
||||
pci_read_config_word(pdev[card], PCI_SUBSYSTEM_VENDOR_ID, &vendor);
|
||||
exmimo_id_tmp[card].board_vendor = vendor;
|
||||
|
||||
if ( exmimo_id_tmp[card].board_vendor == XILINX_VENDOR )
|
||||
exmimo_id_tmp[card].board_vendor = EURECOM_VENDOR; // default (for old bitstreams) is EURECOM_VENDOR
|
||||
|
||||
exmimo_id_tmp[card].board_exmimoversion = (subid >> 12) & 0x0F;
|
||||
if (exmimo_id_tmp[card].board_exmimoversion == 0)
|
||||
exmimo_id_tmp[card].board_exmimoversion = 1; // default (for old bitstreams) is ExpressMIMO-1
|
||||
|
||||
exmimo_id_tmp[card].board_hwrev = (subid >> 8) & 0x0F;
|
||||
exmimo_id_tmp[card].board_swrev = (subid ) & 0xFF;
|
||||
printk("[openair][INIT_MODULE][INFO]: card %d: ExpressMIMO-%i (HW Rev %i), Bitstream: %s, SW/Protocol Revision: 0x%02X\n", card,
|
||||
exmimo_id_tmp[card].board_exmimoversion, exmimo_id_tmp[card].board_hwrev, ( (exmimo_id_tmp[card].board_vendor == EURECOM_VENDOR) ? "Eurecom" : "Telecom Paristech"), exmimo_id_tmp[card].board_swrev );
|
||||
|
||||
card++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// at least one device found, enable it
|
||||
number_of_cards = card;
|
||||
|
||||
for (card=0; card<number_of_cards; card++)
|
||||
{
|
||||
if( pci_enable_device(pdev[card]) )
|
||||
{
|
||||
printk("[openair][INIT_MODULE][INFO]: Could not enable PCI card device %d\n",card);
|
||||
openair_cleanup();
|
||||
return -ENODEV;
|
||||
}
|
||||
else {
|
||||
printk("[openair][INIT_MODULE][INFO]: *** CARD DEVICE %d (pdev=%p) ENABLED, irq %d\n",card,pdev[card],irq);
|
||||
printk("[openair][INIT_MODULE][INFO]: *** CARD DEVICE %d (pdev=%p) ENABLED, irq %d\n",card,pdev[card],pdev[card]->irq);
|
||||
openair_pci_device_enabled[card] = 1;
|
||||
}
|
||||
// Make the FPGA to a PCI master
|
||||
pci_set_master(pdev[card]);
|
||||
|
||||
// set DMA mask
|
||||
if (!pci_set_dma_mask(pdev[card], DMA_BIT_MASK(32))) {
|
||||
if (pci_set_consistent_dma_mask(pdev[card], DMA_BIT_MASK(32))) {
|
||||
printk(KERN_INFO "[openair][INIT_MODULE]: Unable to obtain 32bit DMA for consistent allocations\n");
|
||||
openair_cleanup();
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
//if (pci_enable_pcie_error_reporting(pdev[card]) > 0)
|
||||
// printk("[openair][INIT_MODULE][INFO]: Enabled PCIe error reporting\n");
|
||||
//else
|
||||
// printk("[openair][INIT_MODULE][INFO]: Failed to enable PCIe error reporting\n");
|
||||
|
||||
//pci_cleanup_aer_uncorrect_error_status(pdev[card]);
|
||||
|
||||
mmio_start[card] = pci_resource_start(pdev[card], 0); // get start of BAR0
|
||||
mmio_length[card] = pci_resource_len (pdev[card], 0);
|
||||
mmio_flags[card] = pci_resource_flags(pdev[card], 0);
|
||||
|
||||
if (check_mem_region(mmio_start[card],256) < 0)
|
||||
{
|
||||
printk("[openair][INIT_MODULE][FATAL] : Cannot get memory region 0, aborting\n");
|
||||
mmio_start[card] = 0;
|
||||
openair_cleanup();
|
||||
return -EBUSY;
|
||||
}
|
||||
else
|
||||
printk("[openair][INIT_MODULE][INFO] : Reserving memory region 0 : mmio_start = 0x%x\n",(unsigned int)mmio_start[card]);
|
||||
|
||||
request_mem_region(mmio_start[card], 256, "openair_rf");
|
||||
|
||||
bar[card] = pci_iomap( pdev[card], 0, mmio_length[card] ); // get virtual kernel address for BAR0
|
||||
|
||||
printk("[openair][INIT_MODULE][INFO]: BAR0 card %d = 0x%p\n", card, bar[card]);
|
||||
|
||||
printk("[openair][INIT_MODULE][INFO]: Writing 0x%x to BAR0+0x1c (PCIBASEL)\n", 0x12345678);
|
||||
|
||||
iowrite32( 0x12345678, (bar[card]+PCIE_PCIBASEL) );
|
||||
udelay(100);
|
||||
readback = ioread32( bar[card]+PCIE_PCIBASEL );
|
||||
if (readback != 0x12345678)
|
||||
{
|
||||
printk("[openair][INIT_MODULE][INFO]: Readback of FPGA register failed (%x)\n",readback);
|
||||
openair_cleanup();
|
||||
return -EIO;
|
||||
}
|
||||
iowrite32((1<<8), bar[card] +PCIE_CONTROL0 ); // bit8=AHBPCIE_CTL0_SOFTRESET, but what is bit9 and bit10?
|
||||
udelay(1000);
|
||||
readback = ioread32( bar[card] +PCIE_CONTROL0);
|
||||
printk("CONTROL0 readback %x\n",readback);
|
||||
|
||||
// allocating buffers
|
||||
if ( exmimo_memory_alloc( card ) ) {
|
||||
printk("[openair][MODULE][ERROR] exmimo_memory_alloc() failed!\n");
|
||||
openair_cleanup();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
exmimo_pci_kvirt[card].exmimo_id_ptr->board_vendor = exmimo_id_tmp[card].board_vendor;
|
||||
exmimo_pci_kvirt[card].exmimo_id_ptr->board_exmimoversion = exmimo_id_tmp[card].board_exmimoversion;
|
||||
exmimo_pci_kvirt[card].exmimo_id_ptr->board_hwrev = exmimo_id_tmp[card].board_hwrev;
|
||||
exmimo_pci_kvirt[card].exmimo_id_ptr->board_swrev = exmimo_id_tmp[card].board_swrev;
|
||||
|
||||
if (irq!=0)
|
||||
printk("[OPENAIR][SCHED][INIT] card %d: Trying to get IRQ %d\n", card,irq);
|
||||
else
|
||||
printk("[OPENAIR][SCHED][INIT] card %d: Trying to get IRQ %d\n", card, pdev[card]->irq);
|
||||
|
||||
openair_irq_enabled[card] = 0;
|
||||
|
||||
// #ifdef CONFIG_PREEMPT_RT doesn't work -> fix misconfigured header files?
|
||||
#if 1
|
||||
if (irq!=0){
|
||||
if ( (res = request_irq(irq, openair_irq_handler,
|
||||
IRQF_SHARED , "openair_rf", pdev[card] )) == 0) {
|
||||
openair_irq_enabled[card] = 1;
|
||||
}
|
||||
else {
|
||||
printk("[EXMIMO][SCHED][INIT] Cannot get IRQ %d for HW, error: %d\n", irq, res);
|
||||
openair_cleanup();
|
||||
return -EBUSY;
|
||||
}}
|
||||
else
|
||||
{
|
||||
if ( (res = request_irq(pdev[card]->irq, openair_irq_handler,
|
||||
IRQF_SHARED , "openair_rf", pdev[card] )) == 0) {
|
||||
openair_irq_enabled[card] = 1;
|
||||
}
|
||||
else {
|
||||
printk("[EXMIMO][SCHED][INIT] Cannot get IRQ %d for HW, error: %d\n", pdev[card]->irq, res);
|
||||
openair_cleanup();
|
||||
return -EBUSY;
|
||||
}}
|
||||
|
||||
|
||||
#else
|
||||
printk("Warning: didn't request IRQ for PREEMPT_REALTIME\n");
|
||||
#endif
|
||||
|
||||
} // for (i=0; i<number_of_cards; i++)
|
||||
|
||||
//------------------------------------------------
|
||||
// Register the device in /dev
|
||||
//------------------------------------------------
|
||||
//
|
||||
major = openair_MAJOR;
|
||||
|
||||
if( (res = register_chrdev(major, "openair", &openair_fops )) < 0)
|
||||
{
|
||||
printk("[openair][INIT_MODULE][ERROR]: can't register char device driver, major : %d, error: %d\n", major, res);
|
||||
for (j=0; j<=number_of_cards; j++)
|
||||
release_mem_region(mmio_start[j],256);
|
||||
return -EBUSY;
|
||||
} else {
|
||||
printk("[openair][INIT_MODULE][INFO]: char device driver registered major : %d\n", major);
|
||||
openair_chrdev_registered = 1;
|
||||
}
|
||||
|
||||
printk("[openair][MODULE][INFO] Initializing Leon (EXMIMO_PCIE_INIT) on all cards...\n");
|
||||
|
||||
for (card=0; card<number_of_cards; card++)
|
||||
exmimo_firmware_init( card );
|
||||
|
||||
printk("[openair][MODULE][INFO] Done module init\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void __exit openair_cleanup_module(void)
|
||||
{
|
||||
//int card;
|
||||
printk("[openair][CLEANUP MODULE]\n");
|
||||
|
||||
// stop any ongoing acquisition
|
||||
//for (card = 0; card < number_of_cards; card++)
|
||||
// exmimo_send_pccmd(card, EXMIMO_STOP);
|
||||
|
||||
openair_cleanup();
|
||||
}
|
||||
|
||||
static void openair_cleanup(void)
|
||||
{
|
||||
int card;
|
||||
|
||||
if ( openair_chrdev_registered )
|
||||
unregister_chrdev(major,"openair");
|
||||
openair_chrdev_registered = 0;
|
||||
|
||||
for (card=0; card<number_of_cards; card++)
|
||||
{
|
||||
// unregister interrupt
|
||||
if ( openair_irq_enabled[card] ) {
|
||||
printk("[openair][CLEANUP] disabling interrupt card %d\n", card);
|
||||
if (irq!=0)
|
||||
free_irq(irq, pdev[card] );
|
||||
else
|
||||
free_irq( pdev[card]->irq, pdev[card] );
|
||||
|
||||
openair_irq_enabled[card] = 0;
|
||||
}
|
||||
|
||||
exmimo_firmware_cleanup( card );
|
||||
|
||||
if ( bar[card] ) {
|
||||
printk("unmap bar[%d] %p\n", card, bar[card]);
|
||||
iounmap((void *)bar[card]);
|
||||
}
|
||||
|
||||
if ( mmio_start[card] ) {
|
||||
printk("release mem[%d] %x\n", card, (unsigned int)mmio_start[card]);
|
||||
release_mem_region(mmio_start[card],256);
|
||||
}
|
||||
|
||||
if ( openair_pci_device_enabled[card] ) {
|
||||
printk("pci_disable_device %i\n", card);
|
||||
pci_disable_device( pdev[card] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MODULE_AUTHOR ("Raymond KNOPP <raymond.knopp@eurecom.fr>, Matthias IHMIG <matthias.ihmig@eurecom.fr>, Florian KALTENBERGER <florian.kaltenberger@eurecom.fr>, Riadh GHADDAB <riadh.ghaddab@eurecom.fr>");
|
||||
MODULE_DESCRIPTION ("openair ExpressMIMO/ExpressMIMO3 driver");
|
||||
MODULE_LICENSE ("GPL");
|
||||
module_init (openair_init_module);
|
||||
module_exit (openair_cleanup_module);
|
||||
@@ -0,0 +1 @@
|
||||
kernel//homes/ghaddab/riadh/openair4G/trunk/targets/ARCH/EXMIMO/DRIVER/eurecom/openair_rf.ko
|
||||
Binary file not shown.
@@ -0,0 +1,68 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/vermagic.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
MODULE_INFO(vermagic, VERMAGIC_STRING);
|
||||
|
||||
struct module __this_module
|
||||
__attribute__((section(".gnu.linkonce.this_module"))) = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.init = init_module,
|
||||
#ifdef CONFIG_MODULE_UNLOAD
|
||||
.exit = cleanup_module,
|
||||
#endif
|
||||
.arch = MODULE_ARCH_INIT,
|
||||
};
|
||||
|
||||
static const struct modversion_info ____versions[]
|
||||
__used
|
||||
__attribute__((section("__versions"))) = {
|
||||
{ 0x4d6582e4, "module_layout" },
|
||||
{ 0x6bc3fbc0, "__unregister_chrdev" },
|
||||
{ 0x1fedf0f4, "__request_region" },
|
||||
{ 0x12da5bb2, "__kmalloc" },
|
||||
{ 0xf9a482f9, "msleep" },
|
||||
{ 0xb8957094, "mem_map" },
|
||||
{ 0x15692c87, "param_ops_int" },
|
||||
{ 0x69a358a6, "iomem_resource" },
|
||||
{ 0x763c5db, "dma_set_mask" },
|
||||
{ 0x184a8a78, "pci_disable_device" },
|
||||
{ 0x38620fb, "__register_chrdev" },
|
||||
{ 0x3573f04f, "x86_dma_fallback_dev" },
|
||||
{ 0xeae3dfd6, "__const_udelay" },
|
||||
{ 0xb74d03f5, "pci_set_master" },
|
||||
{ 0x2bc95bd4, "memset" },
|
||||
{ 0x50eedeb8, "printk" },
|
||||
{ 0xae88b44d, "ipipe_percpu" },
|
||||
{ 0xfaef0ed, "__tasklet_schedule" },
|
||||
{ 0x2f287f0d, "copy_to_user" },
|
||||
{ 0xb4390f9a, "mcount" },
|
||||
{ 0x16305289, "warn_slowpath_null" },
|
||||
{ 0x7e61808f, "dma_release_from_coherent" },
|
||||
{ 0x2072ee9b, "request_threaded_irq" },
|
||||
{ 0x98fb1f75, "dma_alloc_from_coherent" },
|
||||
{ 0xa8a6f639, "__check_region" },
|
||||
{ 0x19c39034, "pci_bus_read_config_word" },
|
||||
{ 0x7c61340c, "__release_region" },
|
||||
{ 0x37a0cba, "kfree" },
|
||||
{ 0xf85828f1, "remap_pfn_range" },
|
||||
{ 0xec591975, "dma_supported" },
|
||||
{ 0xedc03953, "iounmap" },
|
||||
{ 0x7628f3c7, "this_cpu_off" },
|
||||
{ 0x94828082, "pci_get_device" },
|
||||
{ 0x471d2cd9, "pci_iomap" },
|
||||
{ 0x436c2179, "iowrite32" },
|
||||
{ 0xc1a6619, "pci_enable_device" },
|
||||
{ 0x362ef408, "_copy_from_user" },
|
||||
{ 0xf358d5ac, "dma_ops" },
|
||||
{ 0xe484e35f, "ioread32" },
|
||||
{ 0xf20dabd8, "free_irq" },
|
||||
};
|
||||
|
||||
static const char __module_depends[]
|
||||
__used
|
||||
__attribute__((section(".modinfo"))) =
|
||||
"depends=";
|
||||
|
||||
|
||||
MODULE_INFO(srcversion, "BAA63F2436D299D87A90400");
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
PCI=`lspci -m | grep Xilinx`
|
||||
if [ -z "$PCI" ]; then
|
||||
echo "No card found. Stopping!"
|
||||
return
|
||||
fi
|
||||
|
||||
SLOT_NUMBER=`echo $PCI | awk -F\" '{print $1}'`
|
||||
|
||||
setpci -s $SLOT_NUMBER 60.b=10
|
||||
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#ifndef __VARS_H__
|
||||
#define __VARS_H__
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#ifdef KERNEL2_6
|
||||
#include <linux/slab.h>
|
||||
#endif
|
||||
|
||||
#include "defs.h"
|
||||
#include "pcie_interface.h"
|
||||
|
||||
unsigned int openair_irq_enabled[MAX_CARDS] = INIT_ZEROS;
|
||||
unsigned int openair_chrdev_registered = 0;
|
||||
unsigned int openair_pci_device_enabled[MAX_CARDS] = INIT_ZEROS;
|
||||
|
||||
struct pci_dev *pdev[MAX_CARDS] = INIT_ZEROS;
|
||||
void __iomem *bar[MAX_CARDS] = INIT_ZEROS;
|
||||
|
||||
resource_size_t mmio_start[MAX_CARDS] = INIT_ZEROS;
|
||||
resource_size_t mmio_length[MAX_CARDS];
|
||||
unsigned int mmio_flags[MAX_CARDS];
|
||||
|
||||
int major;
|
||||
|
||||
char number_of_cards;
|
||||
|
||||
// bigshm allocs a single larger block, used for shared structures and pointers
|
||||
dma_addr_t bigshm_head_phys[MAX_CARDS] = INIT_ZEROS;
|
||||
void *bigshm_head[MAX_CARDS] = INIT_ZEROS;
|
||||
void *bigshm_currentptr[MAX_CARDS];
|
||||
|
||||
dma_addr_t pphys_exmimo_pci_phys[MAX_CARDS]; // phys pointer to pci_bot structure in shared mem
|
||||
|
||||
exmimo_pci_interface_bot_t *p_exmimo_pci_phys[MAX_CARDS] = INIT_ZEROS; // inside struct has physical (DMA) pointers to pci_bot memory blocks
|
||||
|
||||
exmimo_pci_interface_bot_virtual_t exmimo_pci_kvirt[MAX_CARDS]; // has virtual pointers to pci_bot memory blocks
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user