astyle --recursive --indent=spaces=2 --style=kr --indent-col1-comments --break-blocks --convert-tabs --max-code-length=200

This is done for better merging branch/LG_PRE_RELEASE_0.3 into trunk (same process is applied on this branch)

git-svn-id: http://svn.eurecom.fr/openair4G/trunk@7073 818b1a75-f10b-46b9-bf7c-635c3b92a50f
This commit is contained in:
Lionel Gauthier
2015-04-09 09:29:12 +00:00
parent f0a8a0b3b5
commit 059a0a3fdc
2044 changed files with 1182666 additions and 1145123 deletions
+12 -12
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,23 +14,23 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/** common_lib.h
*
* Author: HongliangXU : hong-liang-xu@agilent.com
*/
/** common_lib.h
*
* Author: HongliangXU : hong-liang-xu@agilent.com
*/
#ifndef COMMON_LIB_H
#define COMMON_LIB_H
#include <stdint.h>
@@ -40,7 +40,7 @@ typedef struct openair0_device_t openair0_device;
/* structrue holds the parameters to configure USRP devices
*/
#ifndef EXMIMO
#ifndef EXMIMO
#define MAX_CARDS 1
#endif
@@ -100,7 +100,7 @@ struct openair0_device_t {
/* RF frontend parameters set by application */
openair0_config_t openair0_cfg;
/* Can be used by driver to hold internal structure*/
void *priv;
@@ -151,4 +151,4 @@ int openair0_set_gains(openair0_device* device, openair0_config_t *openair0_cfg)
#endif
#endif // COMMON_LIB_H
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,28 +14,28 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/** ethernet_lib : API to stream I/Q samples over standard ethernet
*
* Authors: Pedro Dinis <pedrodinis20@gmail.com>
* Lucio Ferreira <lucio.ferreira@inov.pt>
* Raymond Knopp <raymond.knopp@eurecom.fr>
*
* Changelog:
* 06.10.2014: Initial version
*/
/** ethernet_lib : API to stream I/Q samples over standard ethernet
*
* Authors: Pedro Dinis <pedrodinis20@gmail.com>
* Lucio Ferreira <lucio.ferreira@inov.pt>
* Raymond Knopp <raymond.knopp@eurecom.fr>
*
* Changelog:
* 06.10.2014: Initial version
*/
#include <arpa/inet.h>
#include <linux/if_packet.h>
@@ -51,8 +51,8 @@
#include "common_lib.h"
#define DEFAULT_IF "eth0"
#define BUF_SIZ 8960 /*Jumbo frame size*/
#define DEFAULT_IF "eth0"
#define BUF_SIZ 8960 /*Jumbo frame size*/
#define MAX_INST 4
int sockfd[MAX_INST];
@@ -62,12 +62,12 @@ int dest_addr_len[MAX_INST];
int i;
int tx_len = 0;
char sendbuf[MAX_INST][BUF_SIZ]; /*TODO*/
/**PDF: Initialization of UDP Socket to communicate with one DEST */
int ethernet_socket_init(int Mod_id, char *dest_ip,int dest_port)
{
{
/**PDF: To be passed by input argument*/
// DEST_port = 32000;
struct sockaddr_in *dest = &dest_addr[Mod_id];
@@ -86,50 +86,53 @@ int ethernet_socket_init(int Mod_id, char *dest_ip,int dest_port)
dest->sin_port=htons(dest_port);
dest_addr_len[Mod_id] = sizeof(struct sockaddr);
inet_ntop(AF_INET, &(dest->sin_addr), str, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &(dest->sin_addr), str, INET_ADDRSTRLEN);
printf("Connecting to %s:%d\n",str,ntohs(dest->sin_port));
}
int ethernet_write_data(int Mod_id, openair0_timestamp timestamp, const void **buff, int antenna_id, int nsamps) {
int ethernet_write_data(int Mod_id, openair0_timestamp timestamp, const void **buff, int antenna_id, int nsamps)
{
void *buff2 = (void*)buff[antenna_id]-sizeof(openair0_timestamp)-(sizeof(int16_t)*2);
int32_t temp0 = *(int32_t *)buff2;
openair0_timestamp temp1 = *(openair0_timestamp *)(buff2+(sizeof(int16_t)*2));
int n_written;
n_written = 0;
((int16_t *)buff2)[0] = 1+(antenna_id<<1);
((int16_t *)buff2)[1] = nsamps;
*((openair0_timestamp *)(buff2+(sizeof(int16_t)*2))) = timestamp;
// printf("Timestamp TX sent : %d\n",timestamp);
// printf("Timestamp TX sent : %d\n",timestamp);
// printf("buffer head : %d %d %d %d \n",((int16_t *)buff2)[0],((int16_t *)buff2)[1],((int16_t *)buff2)[2],((int16_t *)buff2)[3]);
// printf("buffer head : %d %d %d %d \n",((int16_t *)buff2)[0],((int16_t *)buff2)[1],((int16_t *)buff2)[2],((int16_t *)buff2)[3]);
while(n_written < nsamps) {
/* Send packet */
if ((n_written += sendto(sockfd[Mod_id],
buff2,
(nsamps<<2)+sizeof(openair0_timestamp)+(2*sizeof(int16_t)),
0,
(struct sockaddr*)&dest_addr[Mod_id],
dest_addr_len[Mod_id])) < 0) {
if ((n_written += sendto(sockfd[Mod_id],
buff2,
(nsamps<<2)+sizeof(openair0_timestamp)+(2*sizeof(int16_t)),
0,
(struct sockaddr*)&dest_addr[Mod_id],
dest_addr_len[Mod_id])) < 0) {
printf("Send failed for Mod_id %d\n",Mod_id);
perror("ETHERNET:");
exit(-1);
}
}
}
*(int32_t *)buff2 = temp0;
*(openair0_timestamp *)(buff2+2*sizeof(int16_t)) = temp1;
return n_written;
}
int ethernet_read_data(int Mod_id,openair0_timestamp *timestamp,void **buff, int antenna_id, int nsamps) {
int ethernet_read_data(int Mod_id,openair0_timestamp *timestamp,void **buff, int antenna_id, int nsamps)
{
void *buff2 = (void*)buff[antenna_id]-sizeof(openair0_timestamp);
int bytes_received;
@@ -150,27 +153,28 @@ int ethernet_read_data(int Mod_id,openair0_timestamp *timestamp,void **buff, int
bytes_received=0;
block_cnt=0;
while(bytes_received < (int)((nsamps<<2))) {
//printf("requesting %d bytes\n",(nsamps<<2));
ret=recvfrom(sockfd[Mod_id],
buff2+bytes_received,
(nsamps<<2)+sizeof(openair0_timestamp)-bytes_received,
0,//MSG_DONTWAIT,
(struct sockaddr *)&dest_addr[Mod_id],
&dest_addr_len[Mod_id]);
buff2+bytes_received,
(nsamps<<2)+sizeof(openair0_timestamp)-bytes_received,
0,//MSG_DONTWAIT,
(struct sockaddr *)&dest_addr[Mod_id],
&dest_addr_len[Mod_id]);
//printf("bytes_received %d (ret %d)\n",bytes_received+ret,ret);
if (ret==-1) {
if (errno == EAGAIN) {
perror("ETHERNET: ");
return((nsamps<<2)+sizeof(openair0_timestamp));
perror("ETHERNET: ");
return((nsamps<<2)+sizeof(openair0_timestamp));
} else if (errno == EWOULDBLOCK) {
block_cnt++;
usleep(10);
if (block_cnt == 100) return(-1);
}
else if (errno == EWOULDBLOCK) {
block_cnt++;
usleep(10);
if (block_cnt == 100) return(-1);
}
}
else {
} else {
bytes_received+=ret;
}
}
@@ -178,18 +182,19 @@ int ethernet_read_data(int Mod_id,openair0_timestamp *timestamp,void **buff, int
//printf("buffer head : %x %x %x %x \n",((int32_t *)buff2)[0],((int32_t *)buff2)[1],((int32_t *)buff2)[2],((int32_t *)buff2)[3]);
*timestamp = *(openair0_timestamp *)(buff2);
// printf("Received %d samples, timestamp = %d\n",bytes_received>>2,*(int32_t*)timestamp);
// printf("Received %d samples, timestamp = %d\n",bytes_received>>2,*(int32_t*)timestamp);
*(openair0_timestamp *)(buff2) = temp;
return nsamps;
}
int trx_eth_start(openair0_device *openair0) {
int trx_eth_start(openair0_device *openair0)
{
int16_t mesg[2];
int Mod_id;
Mod_id = openair0->openair0_cfg.Mod_id;
ethernet_socket_init(openair0->openair0_cfg.Mod_id, openair0->openair0_cfg.rrh_ip,openair0->openair0_cfg.rrh_port);
@@ -205,18 +210,22 @@ int trx_eth_start(openair0_device *openair0) {
void trx_eth_write(openair0_device *device, openair0_timestamp timestamp, const void **buff, int nsamps, int cc, int flags)
{
int i;
for (i=0;i<cc;i++)
for (i=0; i<cc; i++)
ethernet_write_data(device->Mod_id,timestamp,buff,i,nsamps);
}
int trx_eth_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int cc) {
int trx_eth_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int cc)
{
int i;
for (i=0;i<cc;i++)
for (i=0; i<cc; i++)
return(ethernet_read_data(device->Mod_id,ptimestamp,buff,i,nsamps));
}
void trx_eth_end(openair0_device *device) {
void trx_eth_end(openair0_device *device)
{
+11 -11
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,20 +14,20 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#ifndef OPENAIR_DEVICE_H
#ifndef OPENAIR_DEVICE_H
#define OPENAIR_DEVICE_H
@@ -49,23 +49,23 @@
#define TELECOM_PARISTECH_VENDOR 0x0002
/*
PCIe Subsystem ID = exmimo_id.board_exmimoversion(1,2) (4 bits) | exmimo_id.board_hwrev (4 bits) | exmimo_id.board_swrev (Protocol Revision, 8 bits)
Board IDs (exmimo_id.board_exmimoversion(1,2) (4 bits) + exmimo_id.board_hwrev (4 bits))
0x11 => ExpressMIMO-1, first run/HW revision
0x12 => ExpressMIMO-1, second run
0x21 => ExpressMIMO-2, first run
0x22 => ExpressMIMO-2, second run
SW/Protocol revisions: (exmimo_id.board_swrev (Protocol Revision, 8 bits)
BOARD_SWREV_LEGACY:
- IRQ Leon->PC Bit 7 (AHBPCIE_INTERRUPT_ASSERT_BIT) must be cleared in PC kernel driver
- PC->Leon and Leon->PC commands share a single register CONTROL1
BOARD_SWREV_CMDREGISTERS:
- IRQ Leon->PC Bit 7 (AHBPCIE_INTERRUPT_ASSERT_BIT) is automatically cleared on PCIe read
- PC->Leon and Leon->PC commands have separete command registers CONTROL1 (PC->Leon) and CONTROL2 (Leon->PC)
BOARD_SWREV_CMDFIFOS:
- uses two command FIFOs (for PC->Leon and Leon->PC), by Telecom Paristech
*/
+84 -91
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,43 +14,43 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/** pcie_interface.h
Interface definitions to handle communication between PC (kernel driver & SDR application) and Leon3
/** pcie_interface.h
- commands from PC->Leon and Leon->PC passed through CONTROL1 register (or new: FIFOs)
- structure for passing initial (shared PC memory) buffer pointers
- #defines for buffer sizes
This is now the CENTRAL header file for all structs and defines that are
requires on both LEON and Kernel and PC Application
Changelog:
01.12.2012: Fix: RXEN and TXEN were swapped
New rf_mode flag: use DMAMODE_RX and DMAMODE_TX to selectively enable DMA transfers (only used on ExpressMIMO2)
use RXOUTSW to close Lime baseband RXout switch between RFFE and ADC
09.01.2013: Renamed exmimo_rf_t.mbox --> .p_mbox to indicate this is a pointer to the mbox and not the mbox itself
15.01.2013: added command (EXMIMO_GET_SYSTEMID) and structure (exmimo_system_id_t)
to get system ID and bitstream and software versions on PC
22.01.2013: Moved structures into pcie/pcie_interface.h to have all these spread-out definitions in a single place
Interface definitions to handle communication between PC (kernel driver & SDR application) and Leon3
Author: Matthias Ihmig <matthias.ihmig@mytum.de>, 2012
Raymond Knopp <raymond.knopp@eurecom.fr>
Riadh Ghaddab <riadh.ghaddab@eurecom.fr>
*/
- commands from PC->Leon and Leon->PC passed through CONTROL1 register (or new: FIFOs)
- structure for passing initial (shared PC memory) buffer pointers
- #defines for buffer sizes
This is now the CENTRAL header file for all structs and defines that are
requires on both LEON and Kernel and PC Application
Changelog:
01.12.2012: Fix: RXEN and TXEN were swapped
New rf_mode flag: use DMAMODE_RX and DMAMODE_TX to selectively enable DMA transfers (only used on ExpressMIMO2)
use RXOUTSW to close Lime baseband RXout switch between RFFE and ADC
09.01.2013: Renamed exmimo_rf_t.mbox --> .p_mbox to indicate this is a pointer to the mbox and not the mbox itself
15.01.2013: added command (EXMIMO_GET_SYSTEMID) and structure (exmimo_system_id_t)
to get system ID and bitstream and software versions on PC
22.01.2013: Moved structures into pcie/pcie_interface.h to have all these spread-out definitions in a single place
Author: Matthias Ihmig <matthias.ihmig@mytum.de>, 2012
Raymond Knopp <raymond.knopp@eurecom.fr>
Riadh Ghaddab <riadh.ghaddab@eurecom.fr>
*/
#ifndef PCIE_INTERFACE_H
#define PCIE_INTERFACE_H
@@ -80,7 +80,7 @@
/*
* Commands exchanged between PC <--> LEON
*
*
* Idle/Ready: EXMIMO_NOP
*/
#define EXMIMO_NOP 0x9999
@@ -134,32 +134,30 @@
// structures for communication between ExMIMO and kernel
// -----------------------------------------------------------
/*
/*
* struct exmimo_system_id_t:
* Contains information on the bitstream, filled by Leon,
* based on data stored in an APB block on FPGA (TODO)
*
*
* struct exmimo_id_t:
* Compound structure, also includes information
* from PCI configuration space (board_)
*/
typedef struct
{
uint32_t bitstream_id;
uint32_t bitstream_build_date;
uint32_t software_id;
uint32_t software_build_date;
uint32_t dsp_bitstream_id;
uint32_t dsp_bitstream_build_date;
typedef struct {
uint32_t bitstream_id;
uint32_t bitstream_build_date;
uint32_t software_id;
uint32_t software_build_date;
uint32_t dsp_bitstream_id;
uint32_t dsp_bitstream_build_date;
} exmimo_system_id_t;
typedef struct
{
exmimo_system_id_t system_id;
uint32_t board_vendor;
uint32_t board_exmimoversion;
uint32_t board_hwrev;
uint32_t board_swrev;
typedef struct {
exmimo_system_id_t system_id;
uint32_t board_vendor;
uint32_t board_exmimoversion;
uint32_t board_hwrev;
uint32_t board_swrev;
} exmimo_id_t;
@@ -219,7 +217,7 @@ typedef struct
#define LNAMASK (3<<12)
#define LNADIS 0
#define LNA1ON (1<<12)
#define LNA2ON (2<<12)
#define LNA2ON (2<<12)
#define LNA3ON (3<<12)
#define LNAGAINMASK (3<<14)
@@ -259,45 +257,44 @@ typedef struct
#define RXLOIMASK (63<<12)
#define RXLOQMASK (63<<18)
typedef struct
{
typedef struct {
uint32_t do_autocal[MAX_ANTENNAS];
uint32_t rf_freq_rx[MAX_ANTENNAS];
uint32_t rf_freq_tx[MAX_ANTENNAS];
// TX Gain [Chain0..3][0=LIME Gain, 1=currently ignored]
uint32_t tx_gain[MAX_ANTENNAS][2];
// RX Gain [Chain0..3][0=LIME Gain, 1=currently ignored]
uint32_t rx_gain[MAX_ANTENNAS][2];
//LIME RF modes
// 21 | 20:19 | 18:16 |15:14 | 13:12|11:8 | 7 |6:3 |2 |1 |0 |
// TXBYP | RXBYP | RF/BB |LNAMode| LNA |RXLPF|RXLPFen|TXLPF|TXLPFen|TXen|RXen|
uint32_t rf_mode[MAX_ANTENNAS];
// LIME LO Calibration Constants
// | RXLOQ | RXLOI | TXLOQ | TXLOI |
// | 23:18 | 17:12 | 11:6 | 5:0 |
uint32_t rf_local[MAX_ANTENNAS];
// LIME RX DC OFFSET
// | RXDCQ | RXDCI |
// | 15:8 | 7:0 |
uint32_t rf_rxdc[MAX_ANTENNAS];
// LIME VCO Calibration Constants
// | RXVCOCAP | TXVCOCAP |
// | 11:6 | 5:0 |
uint32_t rf_vcocal[MAX_ANTENNAS];
// External RF Frontend, as used on ExpressMIMO-2
uint32_t rffe_gain_txlow[MAX_ANTENNAS];
uint32_t rffe_gain_txhigh[MAX_ANTENNAS];
uint32_t rffe_gain_rxfinal[MAX_ANTENNAS];
uint32_t rffe_gain_rxlow[MAX_ANTENNAS];
uint32_t rffe_band_mode[MAX_ANTENNAS];
} exmimo_rf_t;
@@ -340,28 +337,26 @@ typedef enum {
BW20
} exmimo_bw_t;
typedef struct
{
typedef struct {
uint32_t multicard_syncmode;
uint32_t eNB_flag;
uint32_t tdd_config;
uint32_t frame_length; // e.g. 76800
uint32_t frame_start; // e.g. 18
uint32_t adac_buffer_period; // e.g. 2048
uint32_t adac_intr_period; // e.g. 1024
uint32_t switch_offset[4]; // sample offsets (relative to start of frame) used to control the RX/TX switch in TDD mode
uint32_t resampling_factor[4]; // 0=>1, 1=>2, 2=>4, applied equally to each chain and TX/RX
} exmimo_framing_t;
typedef struct
{
exmimo_rf_t rf;
exmimo_framing_t framing;
typedef struct {
exmimo_rf_t rf;
exmimo_framing_t framing;
} exmimo_config_t;
@@ -371,44 +366,42 @@ typedef struct
* between Leon, Kernel and Userspace
*/
/*
/*
* struct exmimo_pci_interface_bot_t:
* Main structure to exchange physical(DMA) pointers between kernel and Leon
*/
typedef struct
{
uint32_t firmware_block_ptr;
uint32_t printk_buffer_ptr;
typedef struct {
uint32_t firmware_block_ptr;
uint32_t printk_buffer_ptr;
uint32_t exmimo_config_ptr;
uint32_t exmimo_id_ptr;
uint32_t exmimo_config_ptr;
uint32_t exmimo_id_ptr;
// rxcnt / txcnt: stores the current ring buffer position indicators (formerly mbox)
// - increment by one for every 512 samples (512 DW)
// - currently wraps at 150 (0..149) to cover 1 LTE frame in the buffer
// - in current sdr LEON code: only rxcnt_ptr[0] is used
uint32_t rxcnt_ptr[MAX_ANTENNAS]; // points to uint32_t RX ring buffer position for each antenna
uint32_t txcnt_ptr[MAX_ANTENNAS]; // points to uint32_t TX ring buffer position for each antenna
uint32_t adc_head[MAX_ANTENNAS]; // address of start of ADC (RX) buffer in PC memory
uint32_t dac_head[MAX_ANTENNAS]; // address of start of DAC (TX) buffer in PC memory
// rxcnt / txcnt: stores the current ring buffer position indicators (formerly mbox)
// - increment by one for every 512 samples (512 DW)
// - currently wraps at 150 (0..149) to cover 1 LTE frame in the buffer
// - in current sdr LEON code: only rxcnt_ptr[0] is used
uint32_t rxcnt_ptr[MAX_ANTENNAS]; // points to uint32_t RX ring buffer position for each antenna
uint32_t txcnt_ptr[MAX_ANTENNAS]; // points to uint32_t TX ring buffer position for each antenna
uint32_t adc_head[MAX_ANTENNAS]; // address of start of ADC (RX) buffer in PC memory
uint32_t dac_head[MAX_ANTENNAS]; // address of start of DAC (TX) buffer in PC memory
#ifdef NOINIT
uint32_t dummy[13]; // used only in simulation for Modelsim memcopy tests
uint32_t dummy[13]; // used only in simulation for Modelsim memcopy tests
#endif
} exmimo_pci_interface_bot_t;
/*
* Equivalent structure to exmimo_pci_interface_bot, which keeps type-specific virtual pointers
*/
typedef struct
{
char *firmware_block_ptr;
char *printk_buffer_ptr;
exmimo_config_t *exmimo_config_ptr;
exmimo_id_t *exmimo_id_ptr;
uint32_t *rxcnt_ptr[MAX_ANTENNAS]; // points to uint32_t RX ring buffer position for each antenna
uint32_t *txcnt_ptr[MAX_ANTENNAS]; // points to uint32_t TX ring buffer position for each antenna
uint32_t *adc_head[MAX_ANTENNAS]; // address of start of ADC (RX) buffer in PC memory
uint32_t *dac_head[MAX_ANTENNAS]; // address of start of DAC (TX) buffer in PC memory
typedef struct {
char *firmware_block_ptr;
char *printk_buffer_ptr;
exmimo_config_t *exmimo_config_ptr;
exmimo_id_t *exmimo_id_ptr;
uint32_t *rxcnt_ptr[MAX_ANTENNAS]; // points to uint32_t RX ring buffer position for each antenna
uint32_t *txcnt_ptr[MAX_ANTENNAS]; // points to uint32_t TX ring buffer position for each antenna
uint32_t *adc_head[MAX_ANTENNAS]; // address of start of ADC (RX) buffer in PC memory
uint32_t *dac_head[MAX_ANTENNAS]; // address of start of DAC (TX) buffer in PC memory
} exmimo_pci_interface_bot_virtual_t;
#endif
+8 -8
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,20 +14,20 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#ifndef __DEFS_H__
#ifndef __DEFS_H__
#define __DEFS_H__
#include <asm/io.h>
@@ -64,9 +64,9 @@
/* Prototypes */
/*------------------------------------------------*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
long openair_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
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);
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);
+224 -220
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,37 +14,37 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/** 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>
/** 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"
@@ -55,27 +55,26 @@
void mem_SetPageReserved(void *kvirt_addr, unsigned int size_pages)
{
size_t temp_size = size_pages << PAGE_SHIFT;
void *adr = kvirt_addr;
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;
}
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;
}
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.
@@ -83,27 +82,27 @@ void mem_ClearPageReserved(void *kvirt_addr, unsigned int size_pages)
// 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);
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 ( 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) {
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]);
if ( bigshm_head[card] == NULL )
bigshm_head[card] = pci_alloc_consistent( pdev[card], BIGSHM_SIZE_PAGES<<PAGE_SHIFT, &bigshm_head_phys[card] );
bigshm_currentptr[card] = bigshm_head[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]);
mem_SetPageReserved( bigshm_head[card], BIGSHM_SIZE_PAGES);
memset(bigshm_head[card], 0, BIGSHM_SIZE_PAGES << PAGE_SHIFT);
}
return 0;
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;
}
@@ -111,28 +110,28 @@ int bigshm_init(int card)
// 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;
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
//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);
// 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;
}
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;
*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]);
//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;
return ret;
}
@@ -141,131 +140,135 @@ void *bigshm_assign( int card, size_t size_bytes, dma_addr_t *dma_handle_ptr )
// 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));
int j;
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);
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].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_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);
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;
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;
}
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;
}
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++)
{
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);
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];
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) ]);
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);
// printk("[MODULE MAIN3]Phys address TX[0] : (%8lx)\n",p_exmimo_pci_phys[0]->dac_head[ openair_mmap_getAntTX(2) ]);
}
return 0;
// 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
* 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;
}
int i;
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;
}
if ( bigshm_init( card ) ) {
printk("exmimo_memory_alloc(): bigshm_init failed for card %d.\n", card);
return -ENOMEM;
}
return 0;
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;
}
/*
@@ -273,22 +276,22 @@ int i;
*/
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); */
/* 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
// 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;
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;
}
/*
@@ -296,34 +299,34 @@ int exmimo_firmware_init(int card)
*/
int exmimo_firmware_cleanup(int card)
{
size_t size;
int j;
size_t size;
int j;
// free exmimo_allocate_rx_tx_buffers
// 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] );
}
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 ( 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]);
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] );
}
}
return 0;
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;
}
@@ -332,28 +335,29 @@ int exmimo_firmware_cleanup(int card)
*/
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));
val = ioread32(bar[card_id]+PCIE_CONTROL0); // this is only necessary for ExMIMO1. ExMIMO2 will not overwrite any bits in CONTROL0 whenever bit0 is set.
// set interrupt bit to trigger LEON interrupt
iowrite32(val|0x1,bar[card_id]+PCIE_CONTROL0);
// printk("Readback of control0 %x\n",ioread32(bar[0]+PCIE_CONTROL0));
// workaround for ExMIMO1: 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);
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));
val = ioread32(bar[card_id]+PCIE_CONTROL0); // this is only necessary for ExMIMO1. ExMIMO2 will not overwrite any bits in CONTROL0 whenever bit0 is set.
// set interrupt bit to trigger LEON interrupt
iowrite32(val|0x1,bar[card_id]+PCIE_CONTROL0);
// printk("Readback of control0 %x\n",ioread32(bar[0]+PCIE_CONTROL0));
// workaround for ExMIMO1: 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);
}
+7 -7
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,20 +14,20 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#ifndef __EXTERN_H__
#ifndef __EXTERN_H__
#define __EXTERN_H__
#include <linux/init.h>
@@ -52,7 +52,7 @@ 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 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];
+363 -360
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,31 +14,31 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/** 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
*/
/** 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"
@@ -58,20 +58,18 @@ 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;
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;
//printk("[openair][MODULE] openair_open()\n");
return 0;
}
//-----------------------------------------------------------------------------
@@ -84,381 +82,386 @@ int openair_device_release (struct inode *inode,struct file *filp)
//-----------------------------------------------------------------------------
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;
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 );
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;
/*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;
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;
// 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;
}
return 0;
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)
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)
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 */
//-----------------------------------------------------------------------------
/* 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;
int i, c;
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);
int tmp;
break;
case openair_STOP_WITHOUT_RESET:
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;
printk("[openair][IOCTL] openair_STOP_WITHOUT_RESET(card%d)\n", (int)arg);
if ( is_card_num_invalid((int)arg) )
return -EINVAL;
unsigned int get_frame_cnt=0;
exmimo_send_pccmd((int)arg, EXMIMO_STOP_WITHOUT_RESET);
switch(cmd) {
case openair_STOP:
break;
case openair_GET_FRAME:
printk("[openair][IOCTL] openair_STOP(card%d)\n", (int)arg);
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;
if ( is_card_num_invalid((int)arg) )
return -EINVAL;
break;
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));
case openair_GET_BIGSHMTOPS_KVIRT:
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_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));
//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;
break;
case openair_DUMP_CONFIG:
case openair_GET_PCI_INTERFACE_BOTS_KVIRT:
//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;
//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_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;
case openair_GET_NUM_DETECTED_CARDS:
exmimo_send_pccmd((int)arg, EXMIMO_START_RT_ACQUISITION);
//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;
break;
case openair_UPDATE_FIRMWARE:
case openair_DUMP_CONFIG:
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 */
//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 */
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;
if (tmp) {
printk("[openair][IOCTL] Could NOT copy all data from user-space to kernel-space (%d bytes remained uncopied).\n", tmp);
return -1;
}
break;
// 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:
//----------------------
printk("[IOCTL] openair_IOCTL unknown: basecmd = %i (cmd=%X)\n", _IOC_NR(cmd), cmd );
return -EPERM;
break;
return -1;
break;
}
return 0;
break;
default:
//----------------------
printk("[IOCTL] openair_IOCTL unknown: basecmd = %i (cmd=%X)\n", _IOC_NR(cmd), cmd );
return -EPERM;
break;
}
return 0;
}
+118 -125
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,32 +14,32 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/** 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
/** irq.c
- IRQ Handler: IRQ from Leon to PCIe/Kernel: exmimo_irq_handler
- sends received packets to userspace
- added: pass card_id as parameter to tasklet and irq handler
- 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
Authors:
Raymond Knopp <raymond.knopp@eurecom.fr>
Matthias Ihmig <matthias.ihmig@mytum.de>, 2011, 2013
*/
- 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>
@@ -61,140 +61,133 @@ 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;
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;
// check interrupt status register
//pci_read_config_word(pdev[0],6 , &irqval);
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY)
pcie_control = PCIE_CONTROL1;
else
pcie_control = PCIE_CONTROL2;
// 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;
//printk("irq hndl called: card_id=%i, irqval=%i\n", card_id, irqval);
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY)
pcie_control = PCIE_CONTROL1;
else
pcie_control = PCIE_CONTROL2;
// 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);
//printk("irq hndl called: card_id=%i, irqval=%i\n", card_id, irqval);
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;
}
// 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;
}
else
return IRQ_NONE;
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);
}
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;
}
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;
int save_irq_cnt = openair_bh_cnt;
unsigned int irqcmd;
unsigned int pcie_control = PCIE_CONTROL2;
openair_bh_cnt = 0;
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);
}
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;
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);
//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]);
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]);
}
}
+264 -263
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,34 +14,34 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/** 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
*/
/** 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"
@@ -63,303 +63,304 @@ 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,
unlocked_ioctl:
openair_device_ioctl,
#else
ioctl: openair_device_ioctl,
ioctl:
openair_device_ioctl,
#endif
open: openair_device_open,
release:openair_device_release,
mmap: openair_device_mmap
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 int val;
unsigned short vendor, subid;
exmimo_id_t exmimo_id_tmp[MAX_CARDS];
int res = 0;
unsigned int readback;
unsigned int card, j;
unsigned int vid,did;
unsigned int val;
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);
//------------------------------------------------
// Find and enable ExpressMIMO PCI cards
//------------------------------------------------
//
card = 0;
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);
pdev[card] = pci_get_device(XILINX_VENDOR, XILINX_ID, NULL);
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
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);
exmimo_id_tmp[card].board_hwrev = (subid >> 8) & 0x0F;
exmimo_id_tmp[card].board_swrev = (subid ) & 0xFF;
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;
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;
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;
}
// 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 );
// Make the FPGA to a PCI master
pci_set_master(pdev[card]);
card++;
}
else
break;
// 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;
}
}
// at least one device found, enable it
number_of_cards = card;
//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");
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]);
//pci_cleanup_aer_uncorrect_error_status(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;
}
}
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 (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");
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]);
//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);
request_mem_region(mmio_start[card], 256, "openair_rf");
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]);
bar[card] = pci_iomap( pdev[card], 0, mmio_length[card] ); // get virtual kernel address for BAR0
request_mem_region(mmio_start[card], 256, "openair_rf");
printk("[openair][INIT_MODULE][INFO]: BAR0 card %d = 0x%p\n", card, bar[card]);
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);
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 );
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);
// This is for displaying the card number in the leds of the exmimo card
val = ioread32(bar[card]+PCIE_CONTROL0);
iowrite32(val| ((card & 0x1F) << 9),bar[card]+PCIE_CONTROL0);
//val = ioread32(bar[card]+PCIE_CONTROL0);
//printk("[openair][INIT_MODULE][INFO]: writing leds for card %d control0 %x\n",card,val);
// 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);
if (readback != 0x12345678) {
printk("[openair][INIT_MODULE][INFO]: Readback of FPGA register failed (%x)\n",readback);
openair_cleanup();
return -EIO;
}
openair_irq_enabled[card] = 0;
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);
// #ifdef CONFIG_PREEMPT_RT doesn't work -> fix misconfigured header files?
// This is for displaying the card number in the leds of the exmimo card
val = ioread32(bar[card]+PCIE_CONTROL0);
iowrite32(val| ((card & 0x1F) << 9),bar[card]+PCIE_CONTROL0);
//val = ioread32(bar[card]+PCIE_CONTROL0);
//printk("[openair][INIT_MODULE][INFO]: writing leds for card %d control0 %x\n",card,val);
// 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;
}}
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");
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;
} // for (i=0; i<number_of_cards; i++)
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;
}
//------------------------------------------------
// Register the device in /dev
//------------------------------------------------
//
major = openair_MAJOR;
printk("[openair][MODULE][INFO] Initializing Leon (EXMIMO_PCIE_INIT) on all cards...\n");
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 (card=0; card<number_of_cards; card++)
exmimo_firmware_init( card );
for (j=0; j<=number_of_cards; j++)
release_mem_region(mmio_start[j],256);
printk("[openair][MODULE][INFO] Done module init\n");
return -EBUSY;
} else {
printk("[openair][INIT_MODULE][INFO]: char device driver registered major : %d\n", major);
openair_chrdev_registered = 1;
}
return 0;
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");
//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();
// 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;
int card;
if ( openair_chrdev_registered )
unregister_chrdev(major,"openair");
openair_chrdev_registered = 0;
if ( openair_chrdev_registered )
unregister_chrdev(major,"openair");
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_chrdev_registered = 0;
openair_irq_enabled[card] = 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);
exmimo_firmware_cleanup( card );
if (irq!=0)
free_irq(irq, pdev[card] );
else
free_irq( pdev[card]->irq, pdev[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] );
}
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] );
}
}
}
+6 -6
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,20 +14,20 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#ifndef __VARS_H__
#ifndef __VARS_H__
#define __VARS_H__
#include <linux/init.h>
+8 -8
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,20 +14,20 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#ifndef __DEFS_H__
#ifndef __DEFS_H__
#define __DEFS_H__
#include <asm/io.h>
@@ -64,9 +64,9 @@
/* Prototypes */
/*------------------------------------------------*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
long openair_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
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);
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);
+225 -223
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,37 +14,37 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/** 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>
/** 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"
@@ -55,27 +55,26 @@
void mem_SetPageReserved(void *kvirt_addr, unsigned int size_pages)
{
size_t temp_size = size_pages << PAGE_SHIFT;
void *adr = kvirt_addr;
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;
}
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;
}
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.
@@ -83,27 +82,27 @@ void mem_ClearPageReserved(void *kvirt_addr, unsigned int size_pages)
// 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);
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 ( 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) {
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]);
if ( bigshm_head[card] == NULL )
bigshm_head[card] = pci_alloc_consistent( pdev[card], BIGSHM_SIZE_PAGES<<PAGE_SHIFT, &bigshm_head_phys[card] );
bigshm_currentptr[card] = bigshm_head[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]);
mem_SetPageReserved( bigshm_head[card], BIGSHM_SIZE_PAGES);
memset(bigshm_head[card], 0, BIGSHM_SIZE_PAGES << PAGE_SHIFT);
}
return 0;
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;
}
@@ -111,28 +110,28 @@ int bigshm_init(int card)
// 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;
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
//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);
// 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;
}
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;
*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]);
//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;
return ret;
}
@@ -141,131 +140,135 @@ void *bigshm_assign( int card, size_t size_bytes, dma_addr_t *dma_handle_ptr )
// 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));
int j;
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);
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].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_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);
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;
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;
}
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;
}
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++)
{
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);
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];
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) ]);
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);
// printk("[MODULE MAIN3]Phys address TX[0] : (%8lx)\n",p_exmimo_pci_phys[0]->dac_head[ openair_mmap_getAntTX(2) ]);
}
return 0;
// 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
* 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;
}
int i;
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;
}
if ( bigshm_init( card ) ) {
printk("exmimo_memory_alloc(): bigshm_init failed for card %d.\n", card);
return -ENOMEM;
}
return 0;
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;
}
/*
@@ -274,19 +277,18 @@ int i;
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
// 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
for (j=0;j<MAX_ANTENNAS;j++)
{
iowrite32(p_exmimo_pci_phys[card]->adc_head[j], (bar[card]+));
iowrite32(p_exmimo_pci_phys[card]->dac_head[j], (bar[card]+));
}
for (j=0; j<MAX_ANTENNAS; j++) {
iowrite32(p_exmimo_pci_phys[card]->adc_head[j], (bar[card]+));
iowrite32(p_exmimo_pci_phys[card]->dac_head[j], (bar[card]+));
}
exmimo_send_pccmd(card, EXMIMO_PCIE_INIT);
return 0;
exmimo_send_pccmd(card, EXMIMO_PCIE_INIT);
return 0;
}
/*
@@ -294,34 +296,34 @@ int exmimo_firmware_init(int card)
*/
int exmimo_firmware_cleanup(int card)
{
size_t size;
int j;
size_t size;
int j;
// free exmimo_allocate_rx_tx_buffers
// 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] );
}
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 ( 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]);
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] );
}
}
return 0;
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;
}
@@ -330,37 +332,37 @@ int exmimo_firmware_cleanup(int card)
*/
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));
unsigned int val;
unsigned int cnt=0;
switch(cmd)
{
case EXMIMO_CONFIG :
break;
case EXMIMO_PCIE_INIT :
break;
//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));
}
// 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);
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);
}
+7 -7
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,20 +14,20 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#ifndef __EXTERN_H__
#ifndef __EXTERN_H__
#define __EXTERN_H__
#include <linux/init.h>
@@ -52,7 +52,7 @@ 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 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];
+363 -360
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,31 +14,31 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/** 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
*/
/** 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"
@@ -58,20 +58,18 @@ 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;
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;
//printk("[openair][MODULE] openair_open()\n");
return 0;
}
//-----------------------------------------------------------------------------
@@ -84,381 +82,386 @@ int openair_device_release (struct inode *inode,struct file *filp)
//-----------------------------------------------------------------------------
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;
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 );
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;
/*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;
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;
// 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;
}
return 0;
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)
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)
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 */
//-----------------------------------------------------------------------------
/* 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;
int i, c;
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);
int tmp;
break;
case openair_STOP_WITHOUT_RESET:
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;
printk("[openair][IOCTL] openair_STOP_WITHOUT_RESET(card%d)\n", (int)arg);
if ( is_card_num_invalid((int)arg) )
return -EINVAL;
unsigned int get_frame_cnt=0;
exmimo_send_pccmd((int)arg, EXMIMO_STOP_WITHOUT_RESET);
switch(cmd) {
case openair_STOP:
break;
case openair_GET_FRAME:
printk("[openair][IOCTL] openair_STOP(card%d)\n", (int)arg);
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;
if ( is_card_num_invalid((int)arg) )
return -EINVAL;
break;
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));
case openair_GET_BIGSHMTOPS_KVIRT:
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_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));
//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;
break;
case openair_DUMP_CONFIG:
case openair_GET_PCI_INTERFACE_BOTS_KVIRT:
//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;
//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_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;
case openair_GET_NUM_DETECTED_CARDS:
exmimo_send_pccmd((int)arg, EXMIMO_START_RT_ACQUISITION);
//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;
break;
case openair_UPDATE_FIRMWARE:
case openair_DUMP_CONFIG:
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 */
//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 */
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;
if (tmp) {
printk("[openair][IOCTL] Could NOT copy all data from user-space to kernel-space (%d bytes remained uncopied).\n", tmp);
return -1;
}
break;
// 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:
//----------------------
printk("[IOCTL] openair_IOCTL unknown: basecmd = %i (cmd=%X)\n", _IOC_NR(cmd), cmd );
return -EPERM;
break;
return -1;
break;
}
return 0;
break;
default:
//----------------------
printk("[IOCTL] openair_IOCTL unknown: basecmd = %i (cmd=%X)\n", _IOC_NR(cmd), cmd );
return -EPERM;
break;
}
return 0;
}
+118 -125
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,32 +14,32 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/** 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
/** irq.c
- IRQ Handler: IRQ from Leon to PCIe/Kernel: exmimo_irq_handler
- sends received packets to userspace
- added: pass card_id as parameter to tasklet and irq handler
- 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
Authors:
Raymond Knopp <raymond.knopp@eurecom.fr>
Matthias Ihmig <matthias.ihmig@mytum.de>, 2011, 2013
*/
- 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>
@@ -61,140 +61,133 @@ 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;
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;
// check interrupt status register
//pci_read_config_word(pdev[0],6 , &irqval);
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY)
pcie_control = PCIE_CONTROL1;
else
pcie_control = PCIE_CONTROL2;
// 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;
//printk("irq hndl called: card_id=%i, irqval=%i\n", card_id, irqval);
if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY)
pcie_control = PCIE_CONTROL1;
else
pcie_control = PCIE_CONTROL2;
// 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);
//printk("irq hndl called: card_id=%i, irqval=%i\n", card_id, irqval);
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;
}
// 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;
}
else
return IRQ_NONE;
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);
}
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;
}
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;
int save_irq_cnt = openair_bh_cnt;
unsigned int irqcmd;
unsigned int pcie_control = PCIE_CONTROL2;
openair_bh_cnt = 0;
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);
}
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;
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);
//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]);
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]);
}
}
+256 -255
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,34 +14,34 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/** 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
*/
/** 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"
@@ -63,295 +63,296 @@ 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,
unlocked_ioctl:
openair_device_ioctl,
#else
ioctl: openair_device_ioctl,
ioctl:
openair_device_ioctl,
#endif
open: openair_device_open,
release:openair_device_release,
mmap: openair_device_mmap
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];
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);
//------------------------------------------------
// Find and enable ExpressMIMO PCI cards
//------------------------------------------------
//
card = 0;
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);
pdev[card] = pci_get_device(XILINX_VENDOR, XILINX_ID, NULL);
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
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);
exmimo_id_tmp[card].board_hwrev = (subid >> 8) & 0x0F;
exmimo_id_tmp[card].board_swrev = (subid ) & 0xFF;
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;
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;
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;
}
// 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);
// Make the FPGA to a PCI master
pci_set_master(pdev[card]);
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;
// 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;
}
}
// at least one device found, enable it
number_of_cards = card;
//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");
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]);
//pci_cleanup_aer_uncorrect_error_status(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;
}
}
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 (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");
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]);
//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);
request_mem_region(mmio_start[card], 256, "openair_rf");
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]);
bar[card] = pci_iomap( pdev[card], 0, mmio_length[card] ); // get virtual kernel address for BAR0
request_mem_region(mmio_start[card], 256, "openair_rf");
printk("[openair][INIT_MODULE][INFO]: BAR0 card %d = 0x%p\n", card, bar[card]);
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);
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 );
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);
if (readback != 0x12345678) {
printk("[openair][INIT_MODULE][INFO]: Readback of FPGA register failed (%x)\n",readback);
openair_cleanup();
return -EIO;
}
openair_irq_enabled[card] = 0;
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);
// #ifdef CONFIG_PREEMPT_RT doesn't work -> fix misconfigured header files?
// 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;
}}
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");
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;
} // for (i=0; i<number_of_cards; i++)
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;
}
//------------------------------------------------
// Register the device in /dev
//------------------------------------------------
//
major = openair_MAJOR;
printk("[openair][MODULE][INFO] Initializing Leon (EXMIMO_PCIE_INIT) on all cards...\n");
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 (card=0; card<number_of_cards; card++)
exmimo_firmware_init( card );
for (j=0; j<=number_of_cards; j++)
release_mem_region(mmio_start[j],256);
printk("[openair][MODULE][INFO] Done module init\n");
return -EBUSY;
} else {
printk("[openair][INIT_MODULE][INFO]: char device driver registered major : %d\n", major);
openair_chrdev_registered = 1;
}
return 0;
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");
//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();
// 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;
int card;
if ( openair_chrdev_registered )
unregister_chrdev(major,"openair");
openair_chrdev_registered = 0;
if ( openair_chrdev_registered )
unregister_chrdev(major,"openair");
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_chrdev_registered = 0;
openair_irq_enabled[card] = 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);
exmimo_firmware_cleanup( card );
if (irq!=0)
free_irq(irq, pdev[card] );
else
free_irq( pdev[card]->irq, pdev[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] );
}
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] );
}
}
}
+6 -6
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,20 +14,20 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#ifndef __VARS_H__
#ifndef __VARS_H__
#define __VARS_H__
#include <linux/init.h>
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,178 +14,173 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#include "em1_drv.h"
#include "em1_drv.h"
static irqreturn_t irq_handler(int irq, void *dev_id)
{
uint32_t irqval;
irqreturn_t res = IRQ_NONE;
struct em1_private_s *pv = dev_id;
uint32_t irqval;
irqreturn_t res = IRQ_NONE;
struct em1_private_s *pv = dev_id;
spin_lock(&pv->lock);
irqval = ioread32(pv->base + REG_ISTATUS);
spin_lock(&pv->lock);
irqval = ioread32(pv->base + REG_ISTATUS);
if (irqval & IRQ_MSK)
{
// printk(KERN_DEBUG "em1 irqval 0x%x", irqval);
if (irqval & IRQ_MSK) {
// printk(KERN_DEBUG "em1 irqval 0x%x", irqval);
if ((irqval & EM1_NOTFULL_IRQ) && (pv->busy & EM1_BUSY_FIFO_W))
{
wake_up_all(&pv->rq_wait_fifo_w);
res = IRQ_HANDLED;
}
if ((irqval & EM1_NOTFULL_IRQ) && (pv->busy & EM1_BUSY_FIFO_W)) {
wake_up_all(&pv->rq_wait_fifo_w);
res = IRQ_HANDLED;
}
if ((irqval & EM1_NOTEMPTY_IRQ) && (pv->busy & EM1_BUSY_FIFO_R))
{
wake_up_all(&pv->rq_wait_fifo_r);
res = IRQ_HANDLED;
}
if ((irqval & EM1_NOTEMPTY_IRQ) && (pv->busy & EM1_BUSY_FIFO_R)) {
wake_up_all(&pv->rq_wait_fifo_r);
res = IRQ_HANDLED;
}
if (irqval & EM1_DMA_IRQ)
{
pv->dma_done = irqval >> 16;
wake_up_all(&pv->rq_wait_dma);
res = IRQ_HANDLED;
}
}
if (irqval & EM1_DMA_IRQ) {
pv->dma_done = irqval >> 16;
wake_up_all(&pv->rq_wait_dma);
res = IRQ_HANDLED;
}
}
spin_unlock(&pv->lock);
return res;
spin_unlock(&pv->lock);
return res;
}
int __devinit em1_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int ret, i;
resource_size_t len, start;
struct em1_private_s *pv;
int ret, i;
resource_size_t len, start;
struct em1_private_s *pv;
for (i = 0; i < MAX_EM1_DEVICES; i++)
if (em1_devices[i] == NULL)
goto found;
for (i = 0; i < MAX_EM1_DEVICES; i++)
if (em1_devices[i] == NULL)
goto found;
printk("exmimo1 : Too many devices");
return -ENOENT;
printk("exmimo1 : Too many devices");
return -ENOENT;
found:
pv = kmalloc(sizeof(struct em1_private_s), GFP_KERNEL);
em1_devices[i] = pv;
pv = kmalloc(sizeof(struct em1_private_s), GFP_KERNEL);
em1_devices[i] = pv;
if (pv == NULL)
{
printk(KERN_ERR "exmimo1 : Out of memory\n");
return -ENOMEM;
}
pci_set_drvdata(dev, pv);
if (pv == NULL) {
printk(KERN_ERR "exmimo1 : Out of memory\n");
return -ENOMEM;
}
ret = pci_enable_device(dev);
if (ret <0)
{
printk(KERN_WARNING "exmimo1 : Problem when enabling PCI device\n");
goto err_kfree;
}
pci_set_drvdata(dev, pv);
/* Set interrupt handler function */
ret = request_irq(dev->irq, &irq_handler, IRQF_SHARED, "exmimo1", pv);
ret = pci_enable_device(dev);
if (ret <0)
{
printk(KERN_WARNING "exmimo1 : Problem when requesting interrupt for PCI device\n");
goto err_disable;
}
if (ret <0) {
printk(KERN_WARNING "exmimo1 : Problem when enabling PCI device\n");
goto err_kfree;
}
/* Address of first PCI BAR region */
len = pci_resource_len(dev, 0);
start = pci_resource_start(dev, 0);
printk("exmimo1 : len : %d\n", len);
printk("exmimo1 : start : %x\n", start);
/* Set interrupt handler function */
ret = request_irq(dev->irq, &irq_handler, IRQF_SHARED, "exmimo1", pv);
if (check_mem_region(start, len) < 0)
{
printk(KERN_ERR "exmimo1 : Cannot check memory region 0, already in use\n");
ret = -ENOMEM;
goto err_req_irq;
}
if (request_mem_region(start, len, "exmimo") == NULL)
{
printk(KERN_ERR "exmimo1 : Cannot get memory region 0, already in use\n");
ret = -ENOMEM;
goto err_req_irq;
}
pv->base = pci_iomap(dev, 0, len);
printk(KERN_DEBUG "exmimo1 : base address := 0x%x\n", (unsigned int)pv->base);
if (ret <0) {
printk(KERN_WARNING "exmimo1 : Problem when requesting interrupt for PCI device\n");
goto err_disable;
}
pci_set_master(dev);
/* Address of first PCI BAR region */
len = pci_resource_len(dev, 0);
start = pci_resource_start(dev, 0);
printk("exmimo1 : len : %d\n", len);
printk("exmimo1 : start : %x\n", start);
init_waitqueue_head(&pv->rq_wait_fifo_r);
init_waitqueue_head(&pv->rq_wait_fifo_w);
init_waitqueue_head(&pv->rq_wait_dma);
if (check_mem_region(start, len) < 0) {
printk(KERN_ERR "exmimo1 : Cannot check memory region 0, already in use\n");
ret = -ENOMEM;
goto err_req_irq;
}
pv->ie = 0;
pv->busy = 0;
pv->fifo_read_left = 0;
pv->fifo_write_left = 0;
spin_lock_init(&pv->lock);
pv->dev = &dev->dev;
pv->pdev = dev;
if (request_mem_region(start, len, "exmimo") == NULL) {
printk(KERN_ERR "exmimo1 : Cannot get memory region 0, already in use\n");
ret = -ENOMEM;
goto err_req_irq;
}
/* Get DMA done counter */
pv->dma_started = pv->dma_done = ioread32(pv->base + REG_ISTATUS) >> 16;
pv->base = pci_iomap(dev, 0, len);
printk(KERN_DEBUG "exmimo1 : base address := 0x%x\n", (unsigned int)pv->base);
/* Disable interrupt */
iowrite32(pv->ie, pv->base + REG_FSTATUS);
pci_set_master(dev);
return 0;
init_waitqueue_head(&pv->rq_wait_fifo_r);
init_waitqueue_head(&pv->rq_wait_fifo_w);
init_waitqueue_head(&pv->rq_wait_dma);
err_req_irq:
free_irq(dev->irq, pv);
err_disable:
pci_disable_device(dev);
err_kfree:
kfree(pv);
em1_devices[i] = NULL;
return ret;
pv->ie = 0;
pv->busy = 0;
pv->fifo_read_left = 0;
pv->fifo_write_left = 0;
spin_lock_init(&pv->lock);
pv->dev = &dev->dev;
pv->pdev = dev;
/* Get DMA done counter */
pv->dma_started = pv->dma_done = ioread32(pv->base + REG_ISTATUS) >> 16;
/* Disable interrupt */
iowrite32(pv->ie, pv->base + REG_FSTATUS);
return 0;
err_req_irq:
free_irq(dev->irq, pv);
err_disable:
pci_disable_device(dev);
err_kfree:
kfree(pv);
em1_devices[i] = NULL;
return ret;
}
void __devexit em1_remove(struct pci_dev *dev)
{
int i;
int i;
struct em1_private_s *pv = pci_get_drvdata(dev);
resource_size_t len, start;
struct em1_private_s *pv = pci_get_drvdata(dev);
resource_size_t len, start;
printk(KERN_DEBUG "exmimo1 : remove()\n");
iounmap((void*)pv->base);
/* Address of first PCI BAR region */
printk(KERN_DEBUG "exmimo1 : remove()\n");
len = pci_resource_len(dev, 0);
start = pci_resource_start(dev, 0);
release_mem_region(start, len);
iounmap((void*)pv->base);
/* Address of first PCI BAR region */
// Unregister interrupt
free_irq(dev->irq, pv);
len = pci_resource_len(dev, 0);
start = pci_resource_start(dev, 0);
release_mem_region(start, len);
pci_disable_device(dev);
//Free private data
kfree(pv);
// Unregister interrupt
free_irq(dev->irq, pv);
for (i = 0; i < MAX_EM1_DEVICES; i++)
if (em1_devices[i] == pv)
em1_devices[i] = NULL;
pci_disable_device(dev);
//Free private data
kfree(pv);
for (i = 0; i < MAX_EM1_DEVICES; i++)
if (em1_devices[i] == pv)
em1_devices[i] = NULL;
}
/*
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,20 +14,20 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#include "em1_drv.h"
#include "em1_drv.h"
MODULE_AUTHOR("Alexandre Becoulet, Cerdan Sebastien");
MODULE_DESCRIPTION("Driver for Express-Mimo 1 board");
@@ -39,139 +39,141 @@ static int major = 256;
struct em1_private_s *em1_devices[MAX_EM1_DEVICES] = {};
int em1_user_op_enter(struct em1_private_s *pv, wait_queue_t *wait,
wait_queue_head_t *wh, int busy_flag, int new_state)
wait_queue_head_t *wh, int busy_flag, int new_state)
{
add_wait_queue(wh, wait);
add_wait_queue(wh, wait);
spin_lock_irq(&pv->lock);
spin_lock_irq(&pv->lock);
/* wait for other tasks to leave */
while (pv->busy & busy_flag)
{
if (new_state == TASK_INTERRUPTIBLE &&
signal_pending(current))
return 1;
set_current_state(new_state);
spin_unlock_irq(&pv->lock);
schedule();
spin_lock_irq(&pv->lock);
}
/* wait for other tasks to leave */
while (pv->busy & busy_flag) {
if (new_state == TASK_INTERRUPTIBLE &&
signal_pending(current))
return 1;
pv->busy |= busy_flag;
return 0;
set_current_state(new_state);
spin_unlock_irq(&pv->lock);
schedule();
spin_lock_irq(&pv->lock);
}
pv->busy |= busy_flag;
return 0;
}
void em1_user_op_leave(struct em1_private_s *pv, wait_queue_t *wait,
wait_queue_head_t *wh)
wait_queue_head_t *wh)
{
set_current_state(TASK_RUNNING);
spin_unlock_irq(&pv->lock);
set_current_state(TASK_RUNNING);
spin_unlock_irq(&pv->lock);
remove_wait_queue(wh, wait);
remove_wait_queue(wh, wait);
// wake other waiting tasks
wake_up_all(wh);
// wake other waiting tasks
wake_up_all(wh);
}
static int em1_open(struct inode *inode, struct file *file)
{
int i;
//FIXME Lock list access
int i;
//FIXME Lock list access
for (i = 0; i < MAX_EM1_DEVICES; i++)
{
struct em1_private_s *pv = em1_devices[i];
for (i = 0; i < MAX_EM1_DEVICES; i++) {
struct em1_private_s *pv = em1_devices[i];
if (pv != NULL && i == iminor(inode))
{
struct em1_file_s *fpv = kmalloc(sizeof(struct em1_file_s), GFP_KERNEL);
if (!fpv)
return -ENOMEM;
printk(KERN_DEBUG "exmimo1 : open()\n");
if (pv != NULL && i == iminor(inode)) {
struct em1_file_s *fpv = kmalloc(sizeof(struct em1_file_s), GFP_KERNEL);
fpv->pv = pv;
file->private_data = fpv;
fpv->read.addr = 0;
fpv->write.addr = 0;
memset(fpv->mmap_list, 0, sizeof(fpv->mmap_list));
return 0;
}
}
if (!fpv)
return -ENOMEM;
return -ENODEV;
printk(KERN_DEBUG "exmimo1 : open()\n");
fpv->pv = pv;
file->private_data = fpv;
fpv->read.addr = 0;
fpv->write.addr = 0;
memset(fpv->mmap_list, 0, sizeof(fpv->mmap_list));
return 0;
}
}
return -ENODEV;
}
static int em1_release(struct inode *inode, struct file *file)
{
int i;
struct em1_file_s *fpv = file->private_data;
int i;
struct em1_file_s *fpv = file->private_data;
em1_unlock_user_page(&fpv->read);
em1_unlock_user_page(&fpv->write);
for (i = 0; i < MAX_EM1_MMAP; i++)
if (fpv->mmap_list[i].virt)
{
struct em1_mmap_ctx * mctx = fpv->mmap_list + i;
pci_free_consistent(fpv->pv->pdev, mctx->size, mctx->virt, mctx->phys);
}
kfree(fpv);
em1_unlock_user_page(&fpv->read);
em1_unlock_user_page(&fpv->write);
printk(KERN_DEBUG "exmimo1 : release()\n");
return 0;
for (i = 0; i < MAX_EM1_MMAP; i++)
if (fpv->mmap_list[i].virt) {
struct em1_mmap_ctx * mctx = fpv->mmap_list + i;
pci_free_consistent(fpv->pv->pdev, mctx->size, mctx->virt, mctx->phys);
}
kfree(fpv);
printk(KERN_DEBUG "exmimo1 : release()\n");
return 0;
}
static const struct file_operations em1_fops = {
.read = em1_read,
.write = em1_write,
.open = em1_open,
.release = em1_release,
.ioctl = em1_ioctl,
.mmap = em1_mmap,
.read = em1_read,
.write = em1_write,
.open = em1_open,
.release = em1_release,
.ioctl = em1_ioctl,
.mmap = em1_mmap,
};
/* Supported devices */
static struct pci_device_id em1_pci_tbl[] = {
{ XILINX_VENDOR, XILINX_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,}
{ XILINX_VENDOR, XILINX_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,}
};
MODULE_DEVICE_TABLE(pci, em1_pci_tbl);
static struct pci_driver em1_driver = {
.name = "exmimo1",
.id_table = em1_pci_tbl,
.probe = em1_probe,
.remove = em1_remove,
.name = "exmimo1",
.id_table = em1_pci_tbl,
.probe = em1_probe,
.remove = em1_remove,
};
static int __init em1_init(void)
{
int ret;
printk(KERN_DEBUG "exmimo1 : Hello world!\n");
int ret;
printk(KERN_DEBUG "exmimo1 : Hello world!\n");
ret = pci_register_driver(&em1_driver);
if (ret < 0)
{
printk(KERN_ERR "exmimo1 : Error when registering PCI driver\n");
goto err;
}
ret = pci_register_driver(&em1_driver);
if (ret < 0) {
printk(KERN_ERR "exmimo1 : Error when registering PCI driver\n");
goto err;
}
ret = register_chrdev(major, "exmimo1", &em1_fops);
if (ret < 0) {
printk(KERN_ERR "exmimo1 : Error when registering char device\n");
goto err;
}
ret = register_chrdev(major, "exmimo1", &em1_fops);
if (ret < 0)
{
printk(KERN_ERR "exmimo1 : Error when registering char device\n");
goto err;
}
err:
return ret;
return ret;
}
static void __exit em1_cleanup(void)
{
printk(KERN_DEBUG "exmimo1 : Goodbye world!\n");
unregister_chrdev(major, "exmimo1");
pci_unregister_driver(&em1_driver);
printk(KERN_DEBUG "exmimo1 : Goodbye world!\n");
unregister_chrdev(major, "exmimo1");
pci_unregister_driver(&em1_driver);
}
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,20 +14,20 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#ifndef USER_APP
#ifndef USER_APP
#include <linux/uaccess.h>
#include <linux/module.h>
@@ -94,53 +94,50 @@
#define EM1_BUSY_FIFO_W 2
#define EM1_BUSY_DMA 4
struct em1_private_s;
struct em1_private_s;
struct em1_page_s
{
uintptr_t addr;
struct page *page;
struct em1_page_s {
uintptr_t addr;
struct page *page;
};
struct em1_mmap_ctx {
void* virt;
dma_addr_t phys;
size_t size;
void* virt;
dma_addr_t phys;
size_t size;
};
struct em1_file_s
{
struct em1_private_s *pv;
struct em1_page_s read;
struct em1_page_s write;
struct em1_mmap_ctx mmap_list[MAX_EM1_MMAP];
struct em1_file_s {
struct em1_private_s *pv;
struct em1_page_s read;
struct em1_page_s write;
struct em1_mmap_ctx mmap_list[MAX_EM1_MMAP];
};
struct em1_private_s
{
struct pci_dev *pdev;
struct device *dev;
spinlock_t lock;
struct em1_private_s {
struct pci_dev *pdev;
struct device *dev;
spinlock_t lock;
/* memeory mapped device base address */
void * base;
/* memeory mapped device base address */
void * base;
/* wait queues */
wait_queue_head_t rq_wait_fifo_r;
wait_queue_head_t rq_wait_fifo_w;
wait_queue_head_t rq_wait_dma;
/* wait queues */
wait_queue_head_t rq_wait_fifo_r;
wait_queue_head_t rq_wait_fifo_w;
wait_queue_head_t rq_wait_dma;
/* Number of fifo words left to read or write */
size_t fifo_read_left;
size_t fifo_write_left;
/* Number of fifo words left to read or write */
size_t fifo_read_left;
size_t fifo_write_left;
/* Cached interrupt enabled value */
uint32_t ie;
/* Driver busy operations flags */
int busy;
/* Cached interrupt enabled value */
uint32_t ie;
/* Driver busy operations flags */
int busy;
/* Completed DMA transfer counters */
uint16_t dma_started, dma_done;
/* Completed DMA transfer counters */
uint16_t dma_started, dma_done;
};
extern struct em1_private_s *em1_devices[MAX_EM1_DEVICES];
@@ -153,9 +150,9 @@ static int __init em1_init(void);
static void __exit em1_cleanup(void);
#endif
int em1_user_op_enter(struct em1_private_s *pv, wait_queue_t *wait,
wait_queue_head_t *wh, int busy_flag, int new_state);
wait_queue_head_t *wh, int busy_flag, int new_state);
void em1_user_op_leave(struct em1_private_s *pv, wait_queue_t *wait,
wait_queue_head_t *wh);
wait_queue_head_t *wh);
/* em1_rw.c: read and write syscalls */
int em1_lock_user_page(struct em1_page_s *ep, uintptr_t addr, int direction);
@@ -176,32 +173,30 @@ int em1_fifo_read(struct em1_private_s *pv, uint32_t *buf, size_t count);
/* em1_ioctl.c */
int em1_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
unsigned int cmd, unsigned long arg);
/* em1_mmap.c */
int em1_mmap(struct file *filp, struct vm_area_struct *vma);
#endif
enum em1_ioctl_cmd
{
EM1_IOCTL_FIFO_WRITE,
EM1_IOCTL_FIFO_READ,
enum em1_ioctl_cmd {
EM1_IOCTL_FIFO_WRITE,
EM1_IOCTL_FIFO_READ,
};
#define EM1_MAX_FIFO_PAYLOAD 128
struct em1_ioctl_fifo_params
{
uint32_t *words;
size_t count;
struct em1_ioctl_fifo_params {
uint32_t *words;
size_t count;
};
#if 0
static int em1_ioctl_fifo_write(struct em1_private_s *pv,
struct em1_ioctl_fifo_params *p);
struct em1_ioctl_fifo_params *p);
static int em1_ioctl_fifo_read(struct em1_private_s *pv,
struct em1_ioctl_fifo_params *p);
struct em1_ioctl_fifo_params *p);
static int em1_ioctl_alloc(struct em1_private_s *pv, void **buf);
#endif
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,112 +14,105 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#include "em1_drv.h"
#include "em1_drv.h"
int em1_fifo_write(struct em1_private_s *pv, const uint32_t *buf, size_t count)
{
int retval = 0;
size_t cnt = count;
int retval = 0;
size_t cnt = count;
while (cnt > 0)
{
//read fifo state register
uint32_t data = ioread32(pv->base + REG_FSTATUS);
if (data & PUSH_FULL_STATUS_MSK)
{
/* Enable push fifo no full interrupt */
pv->ie |= PUSH_NO_FULL_IRQ_MSK;
iowrite32(pv->ie, pv->base + REG_FSTATUS);
while (cnt > 0) {
//read fifo state register
uint32_t data = ioread32(pv->base + REG_FSTATUS);
set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&pv->lock);
// printk(KERN_DEBUG "sleep %08x %i", data, current->state);
schedule();
// printk(KERN_DEBUG "wake");
if (data & PUSH_FULL_STATUS_MSK) {
/* Enable push fifo no full interrupt */
pv->ie |= PUSH_NO_FULL_IRQ_MSK;
iowrite32(pv->ie, pv->base + REG_FSTATUS);
spin_lock_irq(&pv->lock);
continue;
}
data = *buf++;
cnt--;
iowrite32(data, pv->base + REG_FCMD);
set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&pv->lock);
// printk(KERN_DEBUG "sleep %08x %i", data, current->state);
schedule();
// printk(KERN_DEBUG "wake");
if (!pv->fifo_write_left)
{
/* Size must be retrieved from POP fifo entry */
pv->fifo_write_left = data & 0xFF;
}
else
{
pv->fifo_write_left--;
}
spin_lock_irq(&pv->lock);
continue;
}
if (!pv->fifo_write_left)
break;
}
data = *buf++;
cnt--;
iowrite32(data, pv->base + REG_FCMD);
pv->ie &= ~PUSH_NO_FULL_IRQ_MSK;
iowrite32(pv->ie, pv->base + REG_FSTATUS);
if (!pv->fifo_write_left) {
/* Size must be retrieved from POP fifo entry */
pv->fifo_write_left = data & 0xFF;
} else {
pv->fifo_write_left--;
}
return retval;
if (!pv->fifo_write_left)
break;
}
pv->ie &= ~PUSH_NO_FULL_IRQ_MSK;
iowrite32(pv->ie, pv->base + REG_FSTATUS);
return retval;
}
int em1_fifo_read(struct em1_private_s *pv, uint32_t *buf, size_t count)
{
int retval = 0;
size_t cnt = count;
int retval = 0;
size_t cnt = count;
while (cnt > 0)
{
//read fifo state register
uint32_t data = ioread32(pv->base + REG_FSTATUS);
while (cnt > 0) {
//read fifo state register
uint32_t data = ioread32(pv->base + REG_FSTATUS);
if (data & POP_EMPTY_STATUS_MSK)
{
/* Enable pop fifo no empty interrupt */
pv->ie |= POP_NO_EMPTY_IRQ_MSK;
iowrite32(pv->ie, pv->base + REG_FSTATUS);
if (data & POP_EMPTY_STATUS_MSK) {
/* Enable pop fifo no empty interrupt */
pv->ie |= POP_NO_EMPTY_IRQ_MSK;
iowrite32(pv->ie, pv->base + REG_FSTATUS);
set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&pv->lock);
schedule();
spin_lock_irq(&pv->lock);
continue;
}
data = ioread32(pv->base + REG_FCMD);
*buf++ = data;
cnt--;
set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&pv->lock);
schedule();
spin_lock_irq(&pv->lock);
continue;
}
if (!pv->fifo_read_left)
{
/* Size must be retrieved from POP fifo entry */
pv->fifo_read_left = data & 0xFF;
}
else
{
pv->fifo_read_left--;
}
data = ioread32(pv->base + REG_FCMD);
*buf++ = data;
cnt--;
if (!pv->fifo_read_left)
break;
}
if (!pv->fifo_read_left) {
/* Size must be retrieved from POP fifo entry */
pv->fifo_read_left = data & 0xFF;
} else {
pv->fifo_read_left--;
}
pv->ie &= ~POP_NO_EMPTY_IRQ_MSK;
iowrite32(pv->ie, pv->base + REG_FSTATUS);
if (!pv->fifo_read_left)
break;
}
return retval;
pv->ie &= ~POP_NO_EMPTY_IRQ_MSK;
iowrite32(pv->ie, pv->base + REG_FSTATUS);
return retval;
}
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,93 +14,98 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#include "em1_drv.h"
#include "em1_drv.h"
static int em1_ioctl_fifo_write(struct em1_private_s *pv, size_t size, uint32_t *words)
{
DECLARE_WAITQUEUE(wait, current);
int res = -ERESTARTSYS;
DECLARE_WAITQUEUE(wait, current);
int res = -ERESTARTSYS;
if (!em1_user_op_enter(pv, &wait, &pv->rq_wait_fifo_w,
EM1_BUSY_FIFO_W, TASK_INTERRUPTIBLE))
{
res = em1_fifo_write(pv, words, size);
res = 0;
pv->busy &= ~EM1_BUSY_FIFO_W;
}
if (!em1_user_op_enter(pv, &wait, &pv->rq_wait_fifo_w,
EM1_BUSY_FIFO_W, TASK_INTERRUPTIBLE)) {
res = em1_fifo_write(pv, words, size);
res = 0;
pv->busy &= ~EM1_BUSY_FIFO_W;
}
em1_user_op_leave(pv, &wait, &pv->rq_wait_fifo_w);
em1_user_op_leave(pv, &wait, &pv->rq_wait_fifo_w);
return res;
return res;
}
static int em1_ioctl_fifo_read(struct em1_private_s *pv, size_t size, uint32_t *words)
{
DECLARE_WAITQUEUE(wait, current);
int res = -ERESTARTSYS;
DECLARE_WAITQUEUE(wait, current);
int res = -ERESTARTSYS;
if (!em1_user_op_enter(pv, &wait, &pv->rq_wait_fifo_r,
EM1_BUSY_FIFO_R, TASK_INTERRUPTIBLE))
{
res = em1_fifo_read(pv, words, size);
pv->busy &= ~EM1_BUSY_FIFO_R;
}
if (!em1_user_op_enter(pv, &wait, &pv->rq_wait_fifo_r,
EM1_BUSY_FIFO_R, TASK_INTERRUPTIBLE)) {
res = em1_fifo_read(pv, words, size);
pv->busy &= ~EM1_BUSY_FIFO_R;
}
em1_user_op_leave(pv, &wait, &pv->rq_wait_fifo_r);
em1_user_op_leave(pv, &wait, &pv->rq_wait_fifo_r);
return res;
return res;
}
int em1_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
unsigned int cmd, unsigned long arg)
{
struct em1_file_s *fpv = file->private_data;
struct em1_private_s *pv = fpv->pv;
struct em1_file_s *fpv = file->private_data;
struct em1_private_s *pv = fpv->pv;
switch ((enum em1_ioctl_cmd)cmd)
{
case EM1_IOCTL_FIFO_WRITE: {
struct em1_ioctl_fifo_params p;
uint32_t w[EM1_MAX_FIFO_PAYLOAD];
switch ((enum em1_ioctl_cmd)cmd) {
case EM1_IOCTL_FIFO_WRITE: {
struct em1_ioctl_fifo_params p;
uint32_t w[EM1_MAX_FIFO_PAYLOAD];
if (copy_from_user(&p, (void*)arg, sizeof(p)))
return -EFAULT;
if (p.count > EM1_MAX_FIFO_PAYLOAD)
return -EINVAL;
if (copy_from_user(w, p.words, p.count * sizeof(uint32_t)))
return -EFAULT;
return em1_ioctl_fifo_write(pv, p.count, w);
}
if (copy_from_user(&p, (void*)arg, sizeof(p)))
return -EFAULT;
case EM1_IOCTL_FIFO_READ: {
struct em1_ioctl_fifo_params p;
uint32_t w[EM1_MAX_FIFO_PAYLOAD];
int res;
if (p.count > EM1_MAX_FIFO_PAYLOAD)
return -EINVAL;
if (copy_from_user(&p, (void*)arg, sizeof(p)))
return -EFAULT;
if (p.count > EM1_MAX_FIFO_PAYLOAD)
return -EINVAL;
res = em1_ioctl_fifo_read(pv, p.count, w);
if (!res && copy_to_user(p.words, w, p.count * sizeof(uint32_t)))
return -EFAULT;
return res;
}
}
return 0;
if (copy_from_user(w, p.words, p.count * sizeof(uint32_t)))
return -EFAULT;
return em1_ioctl_fifo_write(pv, p.count, w);
}
case EM1_IOCTL_FIFO_READ: {
struct em1_ioctl_fifo_params p;
uint32_t w[EM1_MAX_FIFO_PAYLOAD];
int res;
if (copy_from_user(&p, (void*)arg, sizeof(p)))
return -EFAULT;
if (p.count > EM1_MAX_FIFO_PAYLOAD)
return -EINVAL;
res = em1_ioctl_fifo_read(pv, p.count, w);
if (!res && copy_to_user(p.words, w, p.count * sizeof(uint32_t)))
return -EFAULT;
return res;
}
}
return 0;
}
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,60 +14,60 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#include "em1_drv.h"
#include "em1_drv.h"
int em1_mmap(struct file *filp, struct vm_area_struct *vma)
{
int i;
struct em1_file_s *fpv = filp->private_data;
struct em1_mmap_ctx * mctx;
size_t size = vma->vm_end - vma->vm_start;
void * virt;
dma_addr_t phys;
int i;
struct em1_file_s *fpv = filp->private_data;
struct em1_mmap_ctx * mctx;
size_t size = vma->vm_end - vma->vm_start;
void * virt;
dma_addr_t phys;
printk(KERN_DEBUG "exmimo1 : mmap()\n");
printk(KERN_DEBUG "exmimo1 : mmap()\n");
if (vma->vm_end <= vma->vm_start)
return -EINVAL;
if (vma->vm_end <= vma->vm_start)
return -EINVAL;
for (i = 0; i < MAX_EM1_MMAP; i++)
{
mctx = fpv->mmap_list + i;
if (mctx->virt == 0)
break;
}
for (i = 0; i < MAX_EM1_MMAP; i++) {
mctx = fpv->mmap_list + i;
if (i == MAX_EM1_MMAP)
return -ENOMEM;
if (mctx->virt == 0)
break;
}
virt = pci_alloc_consistent(fpv->pv->pdev, size, &phys);
if (virt < 0)
return -EINVAL;
if (i == MAX_EM1_MMAP)
return -ENOMEM;
if (remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT, size, vma->vm_page_prot))
return -EAGAIN;
virt = pci_alloc_consistent(fpv->pv->pdev, size, &phys);
mctx->virt = virt;
mctx->phys = phys;
mctx->size = size;
if (virt < 0)
return -EINVAL;
return 0;
if (remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT, size, vma->vm_page_prot))
return -EAGAIN;
mctx->virt = virt;
mctx->phys = phys;
mctx->size = size;
return 0;
}
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,144 +14,139 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#include "em1_drv.h"
#include "em1_drv.h"
void em1_unlock_user_page(struct em1_page_s *ep)
{
if (ep->addr != 0)
{
// printk(KERN_DEBUG "unlocking user read page");
page_cache_release(ep->page);
ep->addr = 0;
}
if (ep->addr != 0) {
// printk(KERN_DEBUG "unlocking user read page");
page_cache_release(ep->page);
ep->addr = 0;
}
}
int em1_lock_user_page(struct em1_page_s *ep, uintptr_t addr, int direction)
{
int res;
int res;
if (ep->addr == addr)
return 0;
if (ep->addr == addr)
return 0;
em1_unlock_user_page(ep);
em1_unlock_user_page(ep);
// printk(KERN_DEBUG "locking user page for addr %p", addr);
// printk(KERN_DEBUG "locking user page for addr %p", addr);
down_read(&current->mm->mmap_sem);
res = get_user_pages(current, current->mm, addr & ~(PAGE_SIZE-1),
1, direction == DMA_FROM_DEVICE,
0, /* don't force */ &ep->page, NULL);
up_read(&current->mm->mmap_sem);
down_read(&current->mm->mmap_sem);
res = get_user_pages(current, current->mm, addr & ~(PAGE_SIZE-1),
1, direction == DMA_FROM_DEVICE,
0, /* don't force */ &ep->page, NULL);
up_read(&current->mm->mmap_sem);
if (res != 1) {
printk(KERN_ERR "exmimo1: get_user_pages error");
return -EFAULT;
}
if (res != 1) {
printk(KERN_ERR "exmimo1: get_user_pages error");
return -EFAULT;
}
ep->addr = addr;
ep->addr = addr;
return 0;
return 0;
}
static ssize_t em1_dma_access(struct em1_file_s *fpv, char __user *buf,
size_t size, int direction, int opcode)
size_t size, int direction, int opcode)
{
DECLARE_WAITQUEUE(wait, current);
struct em1_private_s *pv = fpv->pv;
uint32_t cmd[4];
uintptr_t addr = (uintptr_t)buf;
uintptr_t end = (uintptr_t)buf + size - 1;
struct em1_page_s *page;
int fres = -ERESTARTSYS;
uint16_t dma_this;
DECLARE_WAITQUEUE(wait, current);
struct em1_private_s *pv = fpv->pv;
uint32_t cmd[4];
uintptr_t addr = (uintptr_t)buf;
uintptr_t end = (uintptr_t)buf + size - 1;
struct em1_page_s *page;
int fres = -ERESTARTSYS;
uint16_t dma_this;
/* check single page span */
if ((addr & ~(PAGE_SIZE-1)) != (end & ~(PAGE_SIZE-1)))
return -EINVAL;
/* check single page span */
if ((addr & ~(PAGE_SIZE-1)) != (end & ~(PAGE_SIZE-1)))
return -EINVAL;
if (!access_ok(direction == DMA_FROM_DEVICE ? VERIFY_WRITE : VERIFY_READ, buf, size))
return -EFAULT;
if (!access_ok(direction == DMA_FROM_DEVICE ? VERIFY_WRITE : VERIFY_READ, buf, size))
return -EFAULT;
page = direction == DMA_FROM_DEVICE ? &fpv->read : &fpv->write;
page = direction == DMA_FROM_DEVICE ? &fpv->read : &fpv->write;
if (em1_lock_user_page(page, addr, direction))
return -EFAULT;
if (em1_lock_user_page(page, addr, direction))
return -EFAULT;
addr = dma_map_page(pv->dev, page->page, 0, PAGE_SIZE, direction);
addr = dma_map_page(pv->dev, page->page, 0, PAGE_SIZE, direction);
/* prepare command for em1 */
cmd[0] = opcode | 3;
cmd[1] = sizeof(addr) > 4 ? (uint32_t)(addr >> 32) : 0;
cmd[2] = (uint32_t)addr;
cmd[3] = size;
/* prepare command for em1 */
cmd[0] = opcode | 3;
cmd[1] = sizeof(addr) > 4 ? (uint32_t)(addr >> 32) : 0;
cmd[2] = (uint32_t)addr;
cmd[3] = size;
if (!em1_user_op_enter(pv, &wait, &pv->rq_wait_fifo_w,
EM1_BUSY_FIFO_W, TASK_INTERRUPTIBLE))
{
/* send command */
fres = em1_fifo_write(pv, cmd, 4);
pv->busy &= ~EM1_BUSY_FIFO_W;
dma_this = ++pv->dma_started;
}
if (!em1_user_op_enter(pv, &wait, &pv->rq_wait_fifo_w,
EM1_BUSY_FIFO_W, TASK_INTERRUPTIBLE)) {
/* send command */
fres = em1_fifo_write(pv, cmd, 4);
pv->busy &= ~EM1_BUSY_FIFO_W;
dma_this = ++pv->dma_started;
}
em1_user_op_leave(pv, &wait, &pv->rq_wait_fifo_w);
em1_user_op_leave(pv, &wait, &pv->rq_wait_fifo_w);
// printk(KERN_DEBUG "exmimo1: dma fifo write %i, addr %x", fres, addr);
// printk(KERN_DEBUG "exmimo1: dma fifo write %i, addr %x", fres, addr);
if (!fres)
{
if (!em1_user_op_enter(pv, &wait, &pv->rq_wait_dma,
EM1_BUSY_DMA, TASK_UNINTERRUPTIBLE))
{
// printk(KERN_DEBUG "wait dma");
if (!fres) {
if (!em1_user_op_enter(pv, &wait, &pv->rq_wait_dma,
EM1_BUSY_DMA, TASK_UNINTERRUPTIBLE)) {
// printk(KERN_DEBUG "wait dma");
/* wait for DMA end irq */
while ((int16_t)(dma_this - pv->dma_done) > 0)
{
set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&pv->lock);
schedule();
spin_lock_irq(&pv->lock);
}
/* wait for DMA end irq */
while ((int16_t)(dma_this - pv->dma_done) > 0) {
set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&pv->lock);
schedule();
spin_lock_irq(&pv->lock);
}
pv->busy &= ~EM1_BUSY_DMA;
fres = size;
}
pv->busy &= ~EM1_BUSY_DMA;
fres = size;
}
em1_user_op_leave(pv, &wait, &pv->rq_wait_dma);
}
em1_user_op_leave(pv, &wait, &pv->rq_wait_dma);
}
dma_unmap_page(pv->dev, addr, PAGE_SIZE, direction);
dma_unmap_page(pv->dev, addr, PAGE_SIZE, direction);
if (direction == DMA_FROM_DEVICE)
SetPageDirty(page->page);
if (direction == DMA_FROM_DEVICE)
SetPageDirty(page->page);
return fres;
return fres;
}
ssize_t em1_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
{
return em1_dma_access(file->private_data, (char*)buf, size,
DMA_TO_DEVICE, EM1_CMD_OP_DMA_PC2EM1);
return em1_dma_access(file->private_data, (char*)buf, size,
DMA_TO_DEVICE, EM1_CMD_OP_DMA_PC2EM1);
}
ssize_t em1_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
return em1_dma_access(file->private_data, buf, size,
DMA_FROM_DEVICE, EM1_CMD_OP_DMA_EM12PC);
return em1_dma_access(file->private_data, buf, size,
DMA_FROM_DEVICE, EM1_CMD_OP_DMA_EM12PC);
}
/*
+74 -72
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,20 +14,20 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#include <stdio.h>
#include <stdio.h>
#include "openair0_lib.h"
exmimo_config_t *p_exmimo_config;
@@ -35,91 +35,93 @@ exmimo_id_t *p_exmimo_id;
unsigned int build_rflocal(txi, txq, rxi, rxq)
{
return (txi + txq<<6 + rxi<<12 + rxq<<18);
return (txi + txq<<6 + rxi<<12 + rxq<<18);
}
unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe)
{
return (dcoff_i_rxfe + dcoff_q_rxfe<<8);
return (dcoff_i_rxfe + dcoff_q_rxfe<<8);
}
void test_config(int card, int ant, unsigned int rf_mode)
{
p_exmimo_config->framing.eNB_flag = 0;
p_exmimo_config->framing.tdd_config = 0;
p_exmimo_config->rf.rf_freq_rx[ant] = 1907600000;
p_exmimo_config->rf.rf_freq_tx[ant] = 1907600000;;
p_exmimo_config->rf.rx_gain[ant][0] = 20;
p_exmimo_config->rf.tx_gain[ant][0] = 10;
p_exmimo_config->rf.rf_mode[ant] = rf_mode;
p_exmimo_config->rf.rf_local[ant] = build_rflocal(20,25,26,04);
p_exmimo_config->rf.rf_rxdc[ant] = build_rfdc(128, 128);
p_exmimo_config->rf.rf_vcocal[ant] = 0xE<<6 + 0xE;
p_exmimo_config->framing.eNB_flag = 0;
p_exmimo_config->framing.tdd_config = 0;
openair0_dump_config( card );
p_exmimo_config->rf.rf_freq_rx[ant] = 1907600000;
p_exmimo_config->rf.rf_freq_tx[ant] = 1907600000;;
p_exmimo_config->rf.rx_gain[ant][0] = 20;
p_exmimo_config->rf.tx_gain[ant][0] = 10;
p_exmimo_config->rf.rf_mode[ant] = rf_mode;
p_exmimo_config->rf.rf_local[ant] = build_rflocal(20,25,26,04);
p_exmimo_config->rf.rf_rxdc[ant] = build_rfdc(128, 128);
p_exmimo_config->rf.rf_vcocal[ant] = 0xE<<6 + 0xE;
openair0_dump_config( card );
}
void read_firmware_buffer(int card)
{
int i;
unsigned int *p= (unsigned int *) (openair0_exmimo_pci[card].firmware_block_ptr);
printf("firmware_buffer: \n");
for (i=0; i<0x30; i++)
printf("u32 fwbuf[%d]: value=%08X\n", i, p[i]);
int i;
unsigned int *p= (unsigned int *) (openair0_exmimo_pci[card].firmware_block_ptr);
printf("firmware_buffer: \n");
for (i=0; i<0x30; i++)
printf("u32 fwbuf[%d]: value=%08X\n", i, p[i]);
}
void main(void)
{
int ret, card, ant;
unsigned int my_rf_mode;
unsigned int *p_rx_ant0, *p_tx_ant0;
ret = openair0_open();
if ( ret != 0 )
{
if (ret == -1)
printf("Error opening /dev/openair0");
if (ret == -2)
printf("Error mapping bigshm");
if (ret == -3)
printf("Error mapping RX or TX buffer");
return;
}
my_rf_mode = RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM;
my_rf_mode += DMAMODE_RX + DMAMODE_TX;
printf ("Detected %d number of cards.\n", openair0_num_detected_cards);
card =0;
ant =0;
printf ("Will configure card %d, antenna %d\n", card, ant);
int ret, card, ant;
unsigned int my_rf_mode;
p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
p_exmimo_id = openair0_exmimo_pci[card].exmimo_id_ptr;
printf("Card %d: ExpressMIMO %d, HW Rev %d, SW Rev 0x%d\n", card, p_exmimo_id->board_exmimoversion, p_exmimo_id->board_hwrev, p_exmimo_id->board_swrev);
unsigned int *p_rx_ant0, *p_tx_ant0;
//read_firmware_buffer(card);
ret = openair0_open();
if ( ret != 0 ) {
if (ret == -1)
printf("Error opening /dev/openair0");
if (ret == -2)
printf("Error mapping bigshm");
if (ret == -3)
printf("Error mapping RX or TX buffer");
return;
}
my_rf_mode = RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM;
my_rf_mode += DMAMODE_RX + DMAMODE_TX;
printf ("Detected %d number of cards.\n", openair0_num_detected_cards);
card =0;
ant =0;
printf ("Will configure card %d, antenna %d\n", card, ant);
p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
p_exmimo_id = openair0_exmimo_pci[card].exmimo_id_ptr;
printf("Card %d: ExpressMIMO %d, HW Rev %d, SW Rev 0x%d\n", card, p_exmimo_id->board_exmimoversion, p_exmimo_id->board_hwrev, p_exmimo_id->board_swrev);
test_config( card, ant, my_rf_mode);
// pointer to data
p_rx_ant0 = openair0_exmimo_pci[ card ].adc_head[ ant ];
p_tx_ant0 = openair0_exmimo_pci[ card ].dac_head[ ant ];
// do something with the data here
openair0_close();
//read_firmware_buffer(card);
test_config( card, ant, my_rf_mode);
// pointer to data
p_rx_ant0 = openair0_exmimo_pci[ card ].adc_head[ ant ];
p_tx_ant0 = openair0_exmimo_pci[ card ].dac_head[ ant ];
// do something with the data here
openair0_close();
}
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,80 +14,87 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#include "openair0_lib.h"
#include "openair0_lib.h"
#include "gain_control.h"
//#define DEBUG_PHY
#ifdef DEBUG_PHY
#include "UTIL/LOG/log_extern.h"
#endif
void gain_control_all (unsigned int rx_power_fil_dB, unsigned int card) {
void gain_control_all (unsigned int rx_power_fil_dB, unsigned int card)
{
unsigned int ant;
for (ant=0;ant<4;ant++)
for (ant=0; ant<4; ant++)
gain_control (rx_power_fil_dB,ant,card);
}
void gain_control (unsigned int rx_power_fil_dB, unsigned int ant, unsigned int card) {
void gain_control (unsigned int rx_power_fil_dB, unsigned int ant, unsigned int card)
{
exmimo_config_t *p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
unsigned int rf_mode, rx_gain, LNA;
rx_gain = p_exmimo_config->rf.rx_gain[ant][0];
rf_mode = p_exmimo_config->rf.rf_mode[ant];
LNA = rf_mode & LNAGAINMASK;
rx_gain = p_exmimo_config->rf.rx_gain[ant][0];
rf_mode = p_exmimo_config->rf.rf_mode[ant];
LNA = rf_mode & LNAGAINMASK;
// Gain control with hysterisis
// Gain control with hysterisis
if (rx_power_fil_dB < TARGET_RX_POWER_MIN) { //increase gain
if (rx_power_fil_dB < TARGET_RX_POWER_MIN) { //increase gain
switch (LNA) {
case LNAByp:
p_exmimo_config->rf.rf_mode[ant] = (rf_mode & (~LNAGAINMASK)) | LNAMed;
break;
case LNAMed:
p_exmimo_config->rf.rf_mode[ant] = (rf_mode & (~LNAGAINMASK)) | LNAMax;
break;
case LNAMax:
p_exmimo_config->rf.rx_gain[ant][0] = min(30,rx_gain+5);
break;
default:
break;
}
} else if (rx_power_fil_dB > TARGET_RX_POWER_MAX) { //decrease gain
if (rx_gain==0) {
switch (LNA) {
case LNAByp:
p_exmimo_config->rf.rf_mode[ant] = (rf_mode & (~LNAGAINMASK)) | LNAMed;
break;
case LNAMed:
p_exmimo_config->rf.rf_mode[ant] = (rf_mode & (~LNAGAINMASK)) | LNAMax;
break;
case LNAMax:
p_exmimo_config->rf.rx_gain[ant][0] = min(30,rx_gain+5);
break;
p_exmimo_config->rf.rf_mode[ant] = (rf_mode & (~LNAGAINMASK)) | LNAMed;
break;
case LNAMed:
p_exmimo_config->rf.rf_mode[ant] = (rf_mode & (~LNAGAINMASK)) | LNAByp;
break;
case LNAByp:
break;
default:
break;
}
}
else if (rx_power_fil_dB > TARGET_RX_POWER_MAX) { //decrease gain
if (rx_gain==0) {
switch (LNA) {
case LNAMax:
p_exmimo_config->rf.rf_mode[ant] = (rf_mode & (~LNAGAINMASK)) | LNAMed;
break;
case LNAMed:
p_exmimo_config->rf.rf_mode[ant] = (rf_mode & (~LNAGAINMASK)) | LNAByp;
break;
case LNAByp:
break;
default:
break;
}
}
else {
p_exmimo_config->rf.rx_gain[ant][0] = max(0,(int)rx_gain-5);
break;
}
} else {
p_exmimo_config->rf.rx_gain[ant][0] = max(0,(int)rx_gain-5);
}
}
#ifdef DEBUG_PHY
LOG_D(PHY,"AGC for chain %d: rx_power_fil_dB=%d, rx_gain=%d, LNA=%d (1=Byp,2=Med,3=Max)\n",ant,rx_power_fil_dB,p_exmimo_config->rf.rx_gain[ant][0],(p_exmimo_config->rf.rf_mode[ant]&LNAGAINMASK)>>14);
LOG_D(PHY,"AGC for chain %d: rx_power_fil_dB=%d, rx_gain=%d, LNA=%d (1=Byp,2=Med,3=Max)\n",ant,rx_power_fil_dB,p_exmimo_config->rf.rx_gain[ant][0],(p_exmimo_config->rf.rf_mode[ant]&LNAGAINMASK)>>14);
#endif //DEBUG_PHY
}
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,22 +14,22 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#define TARGET_RX_POWER 50 // Target digital power for the AGC
#define TARGET_RX_POWER_MAX 53 // Maximum digital power for AGC
#define TARGET_RX_POWER_MIN 48 // Minimum digital power for AGC
#define TARGET_RX_POWER 50 // Target digital power for the AGC
#define TARGET_RX_POWER_MAX 53 // Maximum digital power for AGC
#define TARGET_RX_POWER_MIN 48 // Minimum digital power for AGC
#define min(a,b) (((a)<(b))?(a):(b))
#define max(a,b) (((a)>(b))?(a):(b))
+229 -224
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,29 +14,29 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/** openair0_lib : API to interface with ExpressMIMO-1&2 kernel driver
*
* Authors: Matthias Ihmig <matthias.ihmig@mytum.de>, 2013
* Raymond Knopp <raymond.knopp@eurecom.fr>
*
* Changelog:
* 28.01.2013: Initial version
*/
#include <fcntl.h>
/** openair0_lib : API to interface with ExpressMIMO-1&2 kernel driver
*
* Authors: Matthias Ihmig <matthias.ihmig@mytum.de>, 2013
* Raymond Knopp <raymond.knopp@eurecom.fr>
*
* Changelog:
* 28.01.2013: Initial version
*/
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <string.h>
@@ -59,8 +59,8 @@ int openair0_num_detected_cards = 0;
unsigned int PAGE_SHIFT;
static uint32_t rf_local[4] = {8255000,8255000,8255000,8255000}; // UE zepto
//{8254617, 8254617, 8254617, 8254617}; //eNB khalifa
//{8255067,8254810,8257340,8257340}; // eNB PETRONAS
//{8254617, 8254617, 8254617, 8254617}; //eNB khalifa
//{8255067,8254810,8257340,8257340}; // eNB PETRONAS
static uint32_t rf_vcocal[4] = {910,910,910,910};
static uint32_t rf_vcocal_850[4] = {2015, 2015, 2015, 2015};
@@ -69,188 +69,186 @@ static uint32_t rf_rxdc[4] = {32896,32896,32896,3289
unsigned int log2_int( unsigned int x )
{
unsigned int ans = 0 ;
while( x>>=1 ) ans++;
return ans ;
}
int openair0_open(void)
{
exmimo_pci_interface_bot_virtual_t exmimo_pci_kvirt[MAX_CARDS];
void *bigshm_top_kvirtptr[MAX_CARDS];
int card;
int ant;
exmimo_pci_interface_bot_virtual_t exmimo_pci_kvirt[MAX_CARDS];
void *bigshm_top_kvirtptr[MAX_CARDS];
PAGE_SHIFT = log2_int( sysconf( _SC_PAGESIZE ) );
int card;
int ant;
PAGE_SHIFT = log2_int( sysconf( _SC_PAGESIZE ) );
if ((openair0_fd = open("/dev/openair0", O_RDWR,0)) <0)
{
return -1;
if ((openair0_fd = open("/dev/openair0", O_RDWR,0)) <0) {
return -1;
}
ioctl(openair0_fd, openair_GET_NUM_DETECTED_CARDS, &openair0_num_detected_cards);
if ( openair0_num_detected_cards == 0 ) {
fprintf(stderr, "No cards detected!\n");
return -4;
}
ioctl(openair0_fd, openair_GET_BIGSHMTOPS_KVIRT, &bigshm_top_kvirtptr[0]);
ioctl(openair0_fd, openair_GET_PCI_INTERFACE_BOTS_KVIRT, &exmimo_pci_kvirt[0]);
//printf("bigshm_top_kvirtptr (MAX_CARDS %d): %p %p %p %p\n", MAX_CARDS,bigshm_top_kvirtptr[0], bigshm_top_kvirtptr[1], bigshm_top_kvirtptr[2], bigshm_top_kvirtptr[3]);
for( card=0; card < openair0_num_detected_cards; card++) {
bigshm_top[card] = (char *)mmap( NULL,
BIGSHM_SIZE_PAGES<<PAGE_SHIFT,
PROT_READ|PROT_WRITE,
MAP_SHARED, //|MAP_FIXED,//MAP_SHARED,
openair0_fd,
( openair_mmap_BIGSHM | openair_mmap_Card(card) )<<PAGE_SHIFT);
if (bigshm_top[card] == MAP_FAILED) {
openair0_close();
return -2;
}
ioctl(openair0_fd, openair_GET_NUM_DETECTED_CARDS, &openair0_num_detected_cards);
if ( openair0_num_detected_cards == 0 )
{
fprintf(stderr, "No cards detected!\n");
return -4;
}
ioctl(openair0_fd, openair_GET_BIGSHMTOPS_KVIRT, &bigshm_top_kvirtptr[0]);
ioctl(openair0_fd, openair_GET_PCI_INTERFACE_BOTS_KVIRT, &exmimo_pci_kvirt[0]);
//printf("bigshm_top_kvirtptr (MAX_CARDS %d): %p %p %p %p\n", MAX_CARDS,bigshm_top_kvirtptr[0], bigshm_top_kvirtptr[1], bigshm_top_kvirtptr[2], bigshm_top_kvirtptr[3]);
for( card=0; card < openair0_num_detected_cards; card++)
{
bigshm_top[card] = (char *)mmap( NULL,
BIGSHM_SIZE_PAGES<<PAGE_SHIFT,
PROT_READ|PROT_WRITE,
MAP_SHARED, //|MAP_FIXED,//MAP_SHARED,
openair0_fd,
( openair_mmap_BIGSHM | openair_mmap_Card(card) )<<PAGE_SHIFT);
if (bigshm_top[card] == MAP_FAILED) {
openair0_close();
return -2;
}
// calculate userspace addresses
// calculate userspace addresses
#if __x86_64
openair0_exmimo_pci[card].firmware_block_ptr = (bigshm_top[card] + (int64_t)exmimo_pci_kvirt[0].firmware_block_ptr - (int64_t)bigshm_top_kvirtptr[0]);
openair0_exmimo_pci[card].printk_buffer_ptr = (bigshm_top[card] + (int64_t)exmimo_pci_kvirt[0].printk_buffer_ptr - (int64_t)bigshm_top_kvirtptr[0]);
openair0_exmimo_pci[card].exmimo_config_ptr = (exmimo_config_t*) (bigshm_top[card] + (int64_t)exmimo_pci_kvirt[0].exmimo_config_ptr - (int64_t)bigshm_top_kvirtptr[0]);
openair0_exmimo_pci[card].exmimo_id_ptr = (exmimo_id_t*) (bigshm_top[card] + (int64_t)exmimo_pci_kvirt[0].exmimo_id_ptr - (int64_t)bigshm_top_kvirtptr[0]);
openair0_exmimo_pci[card].firmware_block_ptr = (bigshm_top[card] + (int64_t)exmimo_pci_kvirt[0].firmware_block_ptr - (int64_t)bigshm_top_kvirtptr[0]);
openair0_exmimo_pci[card].printk_buffer_ptr = (bigshm_top[card] + (int64_t)exmimo_pci_kvirt[0].printk_buffer_ptr - (int64_t)bigshm_top_kvirtptr[0]);
openair0_exmimo_pci[card].exmimo_config_ptr = (exmimo_config_t*) (bigshm_top[card] + (int64_t)exmimo_pci_kvirt[0].exmimo_config_ptr - (int64_t)bigshm_top_kvirtptr[0]);
openair0_exmimo_pci[card].exmimo_id_ptr = (exmimo_id_t*) (bigshm_top[card] + (int64_t)exmimo_pci_kvirt[0].exmimo_id_ptr - (int64_t)bigshm_top_kvirtptr[0]);
#else
openair0_exmimo_pci[card].firmware_block_ptr = (bigshm_top[card] + (int32_t)exmimo_pci_kvirt[0].firmware_block_ptr - (int32_t)bigshm_top_kvirtptr[0]);
openair0_exmimo_pci[card].printk_buffer_ptr = (bigshm_top[card] + (int32_t)exmimo_pci_kvirt[0].printk_buffer_ptr - (int32_t)bigshm_top_kvirtptr[0]);
openair0_exmimo_pci[card].exmimo_config_ptr = (exmimo_config_t*) (bigshm_top[card] + (int32_t)exmimo_pci_kvirt[0].exmimo_config_ptr - (int32_t)bigshm_top_kvirtptr[0]);
openair0_exmimo_pci[card].exmimo_id_ptr = (exmimo_id_t*) (bigshm_top[card] + (int32_t)exmimo_pci_kvirt[0].exmimo_id_ptr - (int32_t)bigshm_top_kvirtptr[0]);
openair0_exmimo_pci[card].firmware_block_ptr = (bigshm_top[card] + (int32_t)exmimo_pci_kvirt[0].firmware_block_ptr - (int32_t)bigshm_top_kvirtptr[0]);
openair0_exmimo_pci[card].printk_buffer_ptr = (bigshm_top[card] + (int32_t)exmimo_pci_kvirt[0].printk_buffer_ptr - (int32_t)bigshm_top_kvirtptr[0]);
openair0_exmimo_pci[card].exmimo_config_ptr = (exmimo_config_t*) (bigshm_top[card] + (int32_t)exmimo_pci_kvirt[0].exmimo_config_ptr - (int32_t)bigshm_top_kvirtptr[0]);
openair0_exmimo_pci[card].exmimo_id_ptr = (exmimo_id_t*) (bigshm_top[card] + (int32_t)exmimo_pci_kvirt[0].exmimo_id_ptr - (int32_t)bigshm_top_kvirtptr[0]);
#endif
/*
printf("openair0_exmimo_pci.firmware_block_ptr (%p) = bigshm_top(%p) + exmimo_pci_kvirt.firmware_block_ptr(%p) - bigshm_top_kvirtptr(%p)\n",
openair0_exmimo_pci[card].firmware_block_ptr, bigshm_top, exmimo_pci_kvirt[card].firmware_block_ptr, bigshm_top_kvirtptr[card]);
printf("card%d, openair0_exmimo_pci.exmimo_id_ptr (%p) = bigshm_top(%p) + exmimo_pci_kvirt.exmimo_id_ptr (%p) - bigshm_top_kvirtptr(%p)\n",
card, openair0_exmimo_pci[card].exmimo_id_ptr, bigshm_top[card], exmimo_pci_kvirt[card].exmimo_id_ptr, bigshm_top_kvirtptr[card]);
*/
/*
printf("openair0_exmimo_pci.firmware_block_ptr (%p) = bigshm_top(%p) + exmimo_pci_kvirt.firmware_block_ptr(%p) - bigshm_top_kvirtptr(%p)\n",
openair0_exmimo_pci[card].firmware_block_ptr, bigshm_top, exmimo_pci_kvirt[card].firmware_block_ptr, bigshm_top_kvirtptr[card]);
printf("card%d, openair0_exmimo_pci.exmimo_id_ptr (%p) = bigshm_top(%p) + exmimo_pci_kvirt.exmimo_id_ptr (%p) - bigshm_top_kvirtptr(%p)\n",
card, openair0_exmimo_pci[card].exmimo_id_ptr, bigshm_top[card], exmimo_pci_kvirt[card].exmimo_id_ptr, bigshm_top_kvirtptr[card]);
*/
/*
if (openair0_exmimo_pci[card].exmimo_id_ptr->board_swrev != BOARD_SWREV_CNTL2)
{
error("Software revision %d and firmware revision %d do not match, Please update either Software or Firmware",BOARD_SWREV_CNTL2,openair0_exmimo_pci[card].exmimo_id_ptr->board_swrev);
return -5;
}
*/
/*
if (openair0_exmimo_pci[card].exmimo_id_ptr->board_swrev != BOARD_SWREV_CNTL2)
{
error("Software revision %d and firmware revision %d do not match, Please update either Software or Firmware",BOARD_SWREV_CNTL2,openair0_exmimo_pci[card].exmimo_id_ptr->board_swrev);
return -5;
}
*/
if ( openair0_exmimo_pci[card].exmimo_id_ptr->board_exmimoversion == 1)
openair0_num_antennas[card] = 2;
if ( openair0_exmimo_pci[card].exmimo_id_ptr->board_exmimoversion == 1)
openair0_num_antennas[card] = 2;
if ( openair0_exmimo_pci[card].exmimo_id_ptr->board_exmimoversion == 2)
openair0_num_antennas[card] = 4;
if ( openair0_exmimo_pci[card].exmimo_id_ptr->board_exmimoversion == 2)
openair0_num_antennas[card] = 4;
for (ant=0; ant<openair0_num_antennas[card]; ant++)
{
for (ant=0; ant<openair0_num_antennas[card]; ant++) {
#if __x86_64__
openair0_exmimo_pci[card].rxcnt_ptr[ant] = (unsigned int *) (bigshm_top[card] + (int64_t)exmimo_pci_kvirt[card].rxcnt_ptr[ant] - (int64_t)bigshm_top_kvirtptr[card]);
openair0_exmimo_pci[card].txcnt_ptr[ant] = (unsigned int *) (bigshm_top[card] + (int64_t)exmimo_pci_kvirt[card].txcnt_ptr[ant] - (int64_t)bigshm_top_kvirtptr[card]);
openair0_exmimo_pci[card].rxcnt_ptr[ant] = (unsigned int *) (bigshm_top[card] + (int64_t)exmimo_pci_kvirt[card].rxcnt_ptr[ant] - (int64_t)bigshm_top_kvirtptr[card]);
openair0_exmimo_pci[card].txcnt_ptr[ant] = (unsigned int *) (bigshm_top[card] + (int64_t)exmimo_pci_kvirt[card].txcnt_ptr[ant] - (int64_t)bigshm_top_kvirtptr[card]);
#else
openair0_exmimo_pci[card].rxcnt_ptr[ant] = (unsigned int *) (bigshm_top[card] + (int32_t)exmimo_pci_kvirt[card].rxcnt_ptr[ant] - (int32_t)bigshm_top_kvirtptr[card]);
openair0_exmimo_pci[card].txcnt_ptr[ant] = (unsigned int *) (bigshm_top[card] + (int32_t)exmimo_pci_kvirt[card].txcnt_ptr[ant] - (int32_t)bigshm_top_kvirtptr[card]);
openair0_exmimo_pci[card].rxcnt_ptr[ant] = (unsigned int *) (bigshm_top[card] + (int32_t)exmimo_pci_kvirt[card].rxcnt_ptr[ant] - (int32_t)bigshm_top_kvirtptr[card]);
openair0_exmimo_pci[card].txcnt_ptr[ant] = (unsigned int *) (bigshm_top[card] + (int32_t)exmimo_pci_kvirt[card].txcnt_ptr[ant] - (int32_t)bigshm_top_kvirtptr[card]);
#endif
}
}
for (ant=0; ant<openair0_num_antennas[card]; ant++)
{
openair0_exmimo_pci[card].adc_head[ant] = mmap( NULL,
ADAC_BUFFERSZ_PERCHAN_B,
PROT_READ|PROT_WRITE,
MAP_SHARED, //|MAP_FIXED,//MAP_SHARED,
openair0_fd,
( openair_mmap_RX(ant) | openair_mmap_Card(card) )<<PAGE_SHIFT );
for (ant=0; ant<openair0_num_antennas[card]; ant++) {
openair0_exmimo_pci[card].adc_head[ant] = mmap( NULL,
ADAC_BUFFERSZ_PERCHAN_B,
PROT_READ|PROT_WRITE,
MAP_SHARED, //|MAP_FIXED,//MAP_SHARED,
openair0_fd,
( openair_mmap_RX(ant) | openair_mmap_Card(card) )<<PAGE_SHIFT );
openair0_exmimo_pci[card].dac_head[ant] = mmap( NULL,
ADAC_BUFFERSZ_PERCHAN_B,
PROT_READ|PROT_WRITE,
MAP_SHARED, //|MAP_FIXED,//MAP_SHARED,
openair0_fd,
( openair_mmap_TX(ant) | openair_mmap_Card(card) )<<PAGE_SHIFT );
if (openair0_exmimo_pci[card].adc_head[ant] == MAP_FAILED || openair0_exmimo_pci[card].dac_head[ant] == MAP_FAILED) {
openair0_close();
return -3;
}
}
openair0_exmimo_pci[card].dac_head[ant] = mmap( NULL,
ADAC_BUFFERSZ_PERCHAN_B,
PROT_READ|PROT_WRITE,
MAP_SHARED, //|MAP_FIXED,//MAP_SHARED,
openair0_fd,
( openair_mmap_TX(ant) | openair_mmap_Card(card) )<<PAGE_SHIFT );
//printf("p_exmimo_config = %p, p_exmimo_id = %p\n", openair0_exmimo_pci.exmimo_config_ptr, openair0_exmimo_pci.exmimo_id_ptr);
printf("card %d: ExpressMIMO %d, HW Rev %d, SW Rev 0x%d, %d antennas\n", card, openair0_exmimo_pci[card].exmimo_id_ptr->board_exmimoversion,
openair0_exmimo_pci[card].exmimo_id_ptr->board_hwrev, openair0_exmimo_pci[card].exmimo_id_ptr->board_swrev, openair0_num_antennas[card]);
} // end for(card)
return 0;
if (openair0_exmimo_pci[card].adc_head[ant] == MAP_FAILED || openair0_exmimo_pci[card].dac_head[ant] == MAP_FAILED) {
openair0_close();
return -3;
}
}
//printf("p_exmimo_config = %p, p_exmimo_id = %p\n", openair0_exmimo_pci.exmimo_config_ptr, openair0_exmimo_pci.exmimo_id_ptr);
printf("card %d: ExpressMIMO %d, HW Rev %d, SW Rev 0x%d, %d antennas\n", card, openair0_exmimo_pci[card].exmimo_id_ptr->board_exmimoversion,
openair0_exmimo_pci[card].exmimo_id_ptr->board_hwrev, openair0_exmimo_pci[card].exmimo_id_ptr->board_swrev, openair0_num_antennas[card]);
} // end for(card)
return 0;
}
int openair0_close(void)
{
int ant;
int card;
close(openair0_fd);
for (card=0; card<openair0_num_detected_cards; card++)
{
if (bigshm_top[card] != NULL && bigshm_top[card] != MAP_FAILED)
munmap(bigshm_top[card], BIGSHM_SIZE_PAGES<<PAGE_SHIFT);
int ant;
int card;
for (ant=0; ant<openair0_num_antennas[card]; ant++)
{
if (openair0_exmimo_pci[card].adc_head[ant] != NULL && openair0_exmimo_pci[card].adc_head[ant] != MAP_FAILED)
munmap(openair0_exmimo_pci[card].adc_head[ant], ADAC_BUFFERSZ_PERCHAN_B);
close(openair0_fd);
if (openair0_exmimo_pci[card].dac_head[ant] != NULL && openair0_exmimo_pci[card].dac_head[ant] != MAP_FAILED)
munmap(openair0_exmimo_pci[card].dac_head[ant], ADAC_BUFFERSZ_PERCHAN_B);
}
for (card=0; card<openair0_num_detected_cards; card++) {
if (bigshm_top[card] != NULL && bigshm_top[card] != MAP_FAILED)
munmap(bigshm_top[card], BIGSHM_SIZE_PAGES<<PAGE_SHIFT);
for (ant=0; ant<openair0_num_antennas[card]; ant++) {
if (openair0_exmimo_pci[card].adc_head[ant] != NULL && openair0_exmimo_pci[card].adc_head[ant] != MAP_FAILED)
munmap(openair0_exmimo_pci[card].adc_head[ant], ADAC_BUFFERSZ_PERCHAN_B);
if (openair0_exmimo_pci[card].dac_head[ant] != NULL && openair0_exmimo_pci[card].dac_head[ant] != MAP_FAILED)
munmap(openair0_exmimo_pci[card].dac_head[ant], ADAC_BUFFERSZ_PERCHAN_B);
}
return 0;
}
return 0;
}
int openair0_dump_config(int card)
{
return ioctl(openair0_fd, openair_DUMP_CONFIG, card);
return ioctl(openair0_fd, openair_DUMP_CONFIG, card);
}
int openair0_get_frame(int card)
{
return ioctl(openair0_fd, openair_GET_FRAME, card);
return ioctl(openair0_fd, openair_GET_FRAME, card);
}
int openair0_start_rt_acquisition(int card)
{
return ioctl(openair0_fd, openair_START_RT_ACQUISITION, card);
return ioctl(openair0_fd, openair_START_RT_ACQUISITION, card);
}
int openair0_stop(int card)
{
return ioctl(openair0_fd, openair_STOP, card);
return ioctl(openair0_fd, openair_STOP, card);
}
int openair0_stop_without_reset(int card)
{
return ioctl(openair0_fd, openair_STOP_WITHOUT_RESET, card);
return ioctl(openair0_fd, openair_STOP_WITHOUT_RESET, card);
}
#define MY_RF_MODE (RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM + DMAMODE_RX + DMAMODE_TX)
#define RF_MODE_BASE (LNA1ON + RFBBNORM)
int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg)
{
// Initialize card
exmimo_config_t *p_exmimo_config;
@@ -263,17 +261,19 @@ int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cf
if ( ret != 0 ) {
if (ret == -1)
printf("Error opening /dev/openair0");
if (ret == -2)
printf("Error mapping bigshm");
if (ret == -3)
printf("Error mapping RX or TX buffer");
return(ret);
}
if (openair0_num_detected_cards>MAX_CARDS) {
printf ("Detected %d number of cards, but MAX_CARDS=%d\n", openair0_num_detected_cards, MAX_CARDS);
}
else {
} else {
printf ("Detected %d number of cards, %d number of antennas.\n", openair0_num_detected_cards, openair0_num_antennas[0]);
}
@@ -310,12 +310,12 @@ int openair0_config(openair0_config_t *openair0_cfg, int UE_flag)
p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
p_exmimo_id = openair0_exmimo_pci[card].exmimo_id_ptr;
if (p_exmimo_id->board_swrev>=9)
p_exmimo_config->framing.eNB_flag = 0;
else
p_exmimo_config->framing.eNB_flag = 0;
else
p_exmimo_config->framing.eNB_flag = !UE_flag;
p_exmimo_config->framing.tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_LSB;
if (openair0_num_detected_cards==1)
@@ -324,96 +324,97 @@ int openair0_config(openair0_config_t *openair0_cfg, int UE_flag)
p_exmimo_config->framing.multicard_syncmode=SYNCMODE_MASTER;
else
p_exmimo_config->framing.multicard_syncmode=SYNCMODE_SLAVE;
if (openair0_cfg[card].sample_rate==30.72e6) {
resampling_factor = 0;
rx_filter = RXLPF10;
tx_filter = TXLPF10;
}
else if (openair0_cfg[card].sample_rate==15.36e6) {
} else if (openair0_cfg[card].sample_rate==15.36e6) {
resampling_factor = 1;
rx_filter = RXLPF5;
tx_filter = TXLPF5;
}
else if (openair0_cfg[card].sample_rate==7.68e6) {
} else if (openair0_cfg[card].sample_rate==7.68e6) {
resampling_factor = 2;
rx_filter = RXLPF25;
tx_filter = TXLPF25;
}
else {
} else {
printf("Sampling rate not supported, using default 7.68MHz");
resampling_factor = 2;
rx_filter = RXLPF25;
tx_filter = TXLPF25;
}
#if (BOARD_SWREV_CNTL2>=0x0A)
for (ant=0; ant<4; ant++)
p_exmimo_config->framing.resampling_factor[ant] = resampling_factor;
#else
p_exmimo_config->framing.resampling_factor = resampling_factor;
#endif
for (ant=0;ant<4;ant++) {
for (ant=0; ant<4; ant++) {
if (openair0_cfg[card].rx_freq[ant] || openair0_cfg[card].tx_freq[ant]) {
p_exmimo_config->rf.rf_mode[ant] = RF_MODE_BASE;
p_exmimo_config->rf.do_autocal[ant] = 1;
p_exmimo_config->rf.rf_mode[ant] = RF_MODE_BASE;
p_exmimo_config->rf.do_autocal[ant] = 1;
}
if (openair0_cfg[card].tx_freq[ant]) {
p_exmimo_config->rf.rf_mode[ant] += (TXEN + DMAMODE_TX + TXLPFNORM + TXLPFEN + tx_filter);
p_exmimo_config->rf.rf_freq_tx[ant] = (unsigned int)openair0_cfg[card].tx_freq[ant];
p_exmimo_config->rf.tx_gain[ant][0] = (unsigned int)openair0_cfg[card].tx_gain[ant];
printf("openair0 : programming card %d TX antenna %d (freq %u, gain %d)\n",card,ant,p_exmimo_config->rf.rf_freq_tx[ant],p_exmimo_config->rf.tx_gain[ant][0]);
p_exmimo_config->rf.rf_mode[ant] += (TXEN + DMAMODE_TX + TXLPFNORM + TXLPFEN + tx_filter);
p_exmimo_config->rf.rf_freq_tx[ant] = (unsigned int)openair0_cfg[card].tx_freq[ant];
p_exmimo_config->rf.tx_gain[ant][0] = (unsigned int)openair0_cfg[card].tx_gain[ant];
printf("openair0 : programming card %d TX antenna %d (freq %u, gain %d)\n",card,ant,p_exmimo_config->rf.rf_freq_tx[ant],p_exmimo_config->rf.tx_gain[ant][0]);
}
if (openair0_cfg[card].rx_freq[ant]) {
p_exmimo_config->rf.rf_mode[ant] += (RXEN + DMAMODE_RX + RXLPFNORM + RXLPFEN + rx_filter);
p_exmimo_config->rf.rf_freq_rx[ant] = (unsigned int)openair0_cfg[card].rx_freq[ant];
p_exmimo_config->rf.rx_gain[ant][0] = (unsigned int)openair0_cfg[card].rx_gain[ant];
printf("openair0 : programming card %d RX antenna %d (freq %u, gain %d)\n",card,ant,p_exmimo_config->rf.rf_freq_rx[ant],p_exmimo_config->rf.rx_gain[ant][0]);
switch (openair0_cfg[card].rxg_mode[ant]) {
default:
case max_gain:
p_exmimo_config->rf.rf_mode[ant] += LNAMax;
break;
case med_gain:
p_exmimo_config->rf.rf_mode[ant] += LNAMed;
break;
case byp_gain:
p_exmimo_config->rf.rf_mode[ant] += LNAByp;
break;
}
p_exmimo_config->rf.rf_mode[ant] += (RXEN + DMAMODE_RX + RXLPFNORM + RXLPFEN + rx_filter);
p_exmimo_config->rf.rf_freq_rx[ant] = (unsigned int)openair0_cfg[card].rx_freq[ant];
p_exmimo_config->rf.rx_gain[ant][0] = (unsigned int)openair0_cfg[card].rx_gain[ant];
printf("openair0 : programming card %d RX antenna %d (freq %u, gain %d)\n",card,ant,p_exmimo_config->rf.rf_freq_rx[ant],p_exmimo_config->rf.rx_gain[ant][0]);
switch (openair0_cfg[card].rxg_mode[ant]) {
default:
case max_gain:
p_exmimo_config->rf.rf_mode[ant] += LNAMax;
break;
case med_gain:
p_exmimo_config->rf.rf_mode[ant] += LNAMed;
break;
case byp_gain:
p_exmimo_config->rf.rf_mode[ant] += LNAByp;
break;
}
} else {
p_exmimo_config->rf.rf_mode[ant] = 0;
p_exmimo_config->rf.do_autocal[ant] = 0;
}
else {
p_exmimo_config->rf.rf_mode[ant] = 0;
p_exmimo_config->rf.do_autocal[ant] = 0;
}
p_exmimo_config->rf.rf_local[ant] = rf_local[ant];
p_exmimo_config->rf.rf_rxdc[ant] = rf_rxdc[ant];
if (( p_exmimo_config->rf.rf_freq_tx[ant] >= 850000000) && ( p_exmimo_config->rf.rf_freq_tx[ant] <= 865000000)) {
p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal_850[ant];
p_exmimo_config->rf.rffe_band_mode[ant] = DD_TDD;
}
else if (( p_exmimo_config->rf.rf_freq_tx[ant] >= 1900000000) && ( p_exmimo_config->rf.rf_freq_tx[ant] <= 2000000000)) {
p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal[ant];
p_exmimo_config->rf.rffe_band_mode[ant] = B19G_TDD;
}
else {
p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal[ant];
p_exmimo_config->rf.rffe_band_mode[ant] = 0;
p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal_850[ant];
p_exmimo_config->rf.rffe_band_mode[ant] = DD_TDD;
} else if (( p_exmimo_config->rf.rf_freq_tx[ant] >= 1900000000) && ( p_exmimo_config->rf.rf_freq_tx[ant] <= 2000000000)) {
p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal[ant];
p_exmimo_config->rf.rffe_band_mode[ant] = B19G_TDD;
} else {
p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal[ant];
p_exmimo_config->rf.rffe_band_mode[ant] = 0;
}
}
ret = ioctl(openair0_fd, openair_DUMP_CONFIG, card);
if (ret!=0)
return(-1);
}
return(0);
}
@@ -434,39 +435,43 @@ int openair0_reconfig(openair0_config_t *openair0_cfg)
p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
p_exmimo_id = openair0_exmimo_pci[card].exmimo_id_ptr;
for (ant=0;ant<4;ant++) {
for (ant=0; ant<4; ant++) {
if (openair0_cfg[card].tx_freq[ant]) {
p_exmimo_config->rf.rf_freq_tx[ant] = (unsigned int)openair0_cfg[card].tx_freq[ant];
p_exmimo_config->rf.tx_gain[ant][0] = (unsigned int)openair0_cfg[card].tx_gain[ant];
//printf("openair0 : programming TX antenna %d (freq %u, gain %d)\n",ant,p_exmimo_config->rf.rf_freq_tx[ant],p_exmimo_config->rf.tx_gain[ant][0]);
p_exmimo_config->rf.rf_freq_tx[ant] = (unsigned int)openair0_cfg[card].tx_freq[ant];
p_exmimo_config->rf.tx_gain[ant][0] = (unsigned int)openair0_cfg[card].tx_gain[ant];
//printf("openair0 : programming TX antenna %d (freq %u, gain %d)\n",ant,p_exmimo_config->rf.rf_freq_tx[ant],p_exmimo_config->rf.tx_gain[ant][0]);
}
if (openair0_cfg[card].rx_freq[ant]) {
p_exmimo_config->rf.rf_freq_rx[ant] = (unsigned int)openair0_cfg[card].rx_freq[ant];
p_exmimo_config->rf.rx_gain[ant][0] = (unsigned int)openair0_cfg[card].rx_gain[ant];
//printf("openair0 : programming RX antenna %d (freq %u, gain %d)\n",ant,p_exmimo_config->rf.rf_freq_rx[ant],p_exmimo_config->rf.rx_gain[ant][0]);
switch (openair0_cfg[card].rxg_mode[ant]) {
default:
case max_gain:
p_exmimo_config->rf.rf_mode[ant] = (p_exmimo_config->rf.rf_mode[ant]&(~LNAGAINMASK))|LNAMax;
break;
case med_gain:
p_exmimo_config->rf.rf_mode[ant] = (p_exmimo_config->rf.rf_mode[ant]&(~LNAGAINMASK))|LNAMed;
break;
case byp_gain:
p_exmimo_config->rf.rf_mode[ant] = (p_exmimo_config->rf.rf_mode[ant]&(~LNAGAINMASK))|LNAByp;
break;
}
p_exmimo_config->rf.rf_freq_rx[ant] = (unsigned int)openair0_cfg[card].rx_freq[ant];
p_exmimo_config->rf.rx_gain[ant][0] = (unsigned int)openair0_cfg[card].rx_gain[ant];
//printf("openair0 : programming RX antenna %d (freq %u, gain %d)\n",ant,p_exmimo_config->rf.rf_freq_rx[ant],p_exmimo_config->rf.rx_gain[ant][0]);
switch (openair0_cfg[card].rxg_mode[ant]) {
default:
case max_gain:
p_exmimo_config->rf.rf_mode[ant] = (p_exmimo_config->rf.rf_mode[ant]&(~LNAGAINMASK))|LNAMax;
break;
case med_gain:
p_exmimo_config->rf.rf_mode[ant] = (p_exmimo_config->rf.rf_mode[ant]&(~LNAGAINMASK))|LNAMed;
break;
case byp_gain:
p_exmimo_config->rf.rf_mode[ant] = (p_exmimo_config->rf.rf_mode[ant]&(~LNAGAINMASK))|LNAByp;
break;
}
}
}
}
return(0);
}
unsigned int *openair0_daq_cnt() {
unsigned int *openair0_daq_cnt()
{
return((unsigned int *)openair0_exmimo_pci[0].rxcnt_ptr[0]);
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,27 +14,27 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/** openair0_lib : API to interface with ExpressMIMO kernel driver
*
* Authors: Matthias Ihmig <matthias.ihmig@mytum.de>, 2013
* Raymond Knopp <raymond.knopp@eurecom.fr>
*
* Changelog:
* 28.01.2013: Initial version
*/
/** openair0_lib : API to interface with ExpressMIMO kernel driver
*
* Authors: Matthias Ihmig <matthias.ihmig@mytum.de>, 2013
* Raymond Knopp <raymond.knopp@eurecom.fr>
*
* Changelog:
* 28.01.2013: Initial version
*/
#ifndef __OPENAIR0_LIB_H__
#define __OPENAIR0_LIB_H__
+303 -303
View File
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,23 +14,23 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/*============================================================================
File: elf.h
Include file for ELF file. Defines both 32-/64-bit files.
Copyright Hewlett-Packard Co. 1996. All rights reserved.
/*============================================================================
File: elf.h
Include file for ELF file. Defines both 32-/64-bit files.
Copyright Hewlett-Packard Co. 1996. All rights reserved.
============================================================================*/
#ifndef ELF_INCLUDED
@@ -43,41 +43,41 @@ extern "C" {
#endif
/*============================================================================
Constant values for the sizes of fundamental types
Constant values for the sizes of fundamental types
============================================================================*/
#define ELF64_FSZ_ADDR 8
#define ELF64_FSZ_HALF 2
#define ELF64_FSZ_OFF 8
#define ELF64_FSZ_SWORD 4
#define ELF64_FSZ_WORD 4
#define ELF64_FSZ_SXWORD 8
#define ELF64_FSZ_XWORD 8
#define ELF64_FSZ_ADDR 8
#define ELF64_FSZ_HALF 2
#define ELF64_FSZ_OFF 8
#define ELF64_FSZ_SWORD 4
#define ELF64_FSZ_WORD 4
#define ELF64_FSZ_SXWORD 8
#define ELF64_FSZ_XWORD 8
#define ELF32_FSZ_ADDR 4
#define ELF32_FSZ_HALF 2
#define ELF32_FSZ_OFF 4
#define ELF32_FSZ_SWORD 4
#define ELF32_FSZ_WORD 4
#define ELF32_FSZ_XWORD 4
#define ELF32_FSZ_ADDR 4
#define ELF32_FSZ_HALF 2
#define ELF32_FSZ_OFF 4
#define ELF32_FSZ_SWORD 4
#define ELF32_FSZ_WORD 4
#define ELF32_FSZ_XWORD 4
/*============================================================================
The EI_* macros define indices into the e_ident[] array of the
ElfXX_Ehdr structure.
============================================================================*/
#define EI_MAG0 0 /* File identification */
#define EI_MAG1 1 /* File identification */
#define EI_MAG2 2 /* File identification */
#define EI_MAG3 3 /* File identification */
#define EI_CLASS 4 /* File class */
#define EI_DATA 5 /* Data encoding */
#define EI_VERSION 6 /* File version */
#define EI_OSABI 7 /* OS/ABI identification */
#define EI_MAG0 0 /* File identification */
#define EI_MAG1 1 /* File identification */
#define EI_MAG2 2 /* File identification */
#define EI_MAG3 3 /* File identification */
#define EI_CLASS 4 /* File class */
#define EI_DATA 5 /* Data encoding */
#define EI_VERSION 6 /* File version */
#define EI_OSABI 7 /* OS/ABI identification */
#define EI_ABIVERSION 8 /* ABI version */
#define EI_PAD 9 /* Start of padding bytes */
#define EI_PAD 9 /* Start of padding bytes */
#define EI_NIDENT 16 /* Size of e_ident[] */
#define EI_NIDENT 16 /* Size of e_ident[] */
/*============================================================================
@@ -85,37 +85,37 @@ extern "C" {
============================================================================*/
typedef struct {
unsigned char e_ident[EI_NIDENT]; /* ELF identification */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Machine type */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point address */
Elf64_Off e_phoff; /* Program header offset */
Elf64_Off e_shoff; /* Section header offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size */
Elf64_Half e_phentsize; /* Size of program header entry */
Elf64_Half e_phnum; /* Number of program header entries */
Elf64_Half e_shentsize; /* Size of section header entry */
Elf64_Half e_shnum; /* Number of section header entries */
Elf64_Half e_shstrndx; /* Section name string table index */
unsigned char e_ident[EI_NIDENT]; /* ELF identification */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Machine type */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point address */
Elf64_Off e_phoff; /* Program header offset */
Elf64_Off e_shoff; /* Section header offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size */
Elf64_Half e_phentsize; /* Size of program header entry */
Elf64_Half e_phnum; /* Number of program header entries */
Elf64_Half e_shentsize; /* Size of section header entry */
Elf64_Half e_shnum; /* Number of section header entries */
Elf64_Half e_shstrndx; /* Section name string table index */
} Elf64_Ehdr;
typedef struct {
unsigned char e_ident[EI_NIDENT]; /*16/ ELF "magic number" */
Elf32_Half e_type; /* 2/ Identifies object file type */
Elf32_Half e_machine; /* 2/ Specifies required architecture */
Elf32_Word e_version; /* 4/ Identifies object file version */
Elf32_Addr e_entry; /* 4/ Entry point virtual address */
Elf32_Off e_phoff; /* 4/ Program header table file offset */
Elf32_Off e_shoff; /* 4/ Section header table file offset */
Elf32_Word e_flags; /* 4/ Processor-specific flags */
Elf32_Half e_ehsize; /* 2/ ELF header size in bytes */
Elf32_Half e_phentsize; /* 2/ Program header table entry size */
Elf32_Half e_phnum; /* 2/ Program header table entry count */
Elf32_Half e_shentsize; /* 2/ Section header table entry size */
Elf32_Half e_shnum; /* 2/ Section header table entry count */
Elf32_Half e_shstrndx; /* 2/ Section header string table index */
unsigned char e_ident[EI_NIDENT]; /*16/ ELF "magic number" */
Elf32_Half e_type; /* 2/ Identifies object file type */
Elf32_Half e_machine; /* 2/ Specifies required architecture */
Elf32_Word e_version; /* 4/ Identifies object file version */
Elf32_Addr e_entry; /* 4/ Entry point virtual address */
Elf32_Off e_phoff; /* 4/ Program header table file offset */
Elf32_Off e_shoff; /* 4/ Section header table file offset */
Elf32_Word e_flags; /* 4/ Processor-specific flags */
Elf32_Half e_ehsize; /* 2/ ELF header size in bytes */
Elf32_Half e_phentsize; /* 2/ Program header table entry size */
Elf32_Half e_phnum; /* 2/ Program header table entry count */
Elf32_Half e_shentsize; /* 2/ Section header table entry size */
Elf32_Half e_shnum; /* 2/ Section header table entry count */
Elf32_Half e_shstrndx; /* 2/ Section header string table index */
} Elf32_Ehdr;
@@ -123,38 +123,38 @@ typedef struct {
The ELFCLASS* macros are the defined values of e_ident[EI_CLASS].
============================================================================*/
#define ELFCLASSNONE 0 /* Invalid class */
#define ELFCLASS32 1 /* 32-bit objects */
#define ELFCLASS64 2 /* 64-bit objects */
#define ELFCLASSNONE 0 /* Invalid class */
#define ELFCLASS32 1 /* 32-bit objects */
#define ELFCLASS64 2 /* 64-bit objects */
#define ELFCLASS64_A 200 /* 64-bit objects (interim definition) */
#define ELFCLASS64_A 200 /* 64-bit objects (interim definition) */
/*============================================================================
The ELFDATA* macros are the allowed values of e_ident[EI_DATA].
============================================================================*/
#define ELFDATANONE 0 /* Invalid data encoding */
#define ELFDATA2LSB 1 /* 2's complement, LSB at lowest byte address */
#define ELFDATA2MSB 2 /* 2's complement, MSB at lowest byte address */
#define ELFDATANONE 0 /* Invalid data encoding */
#define ELFDATA2LSB 1 /* 2's complement, LSB at lowest byte address */
#define ELFDATA2MSB 2 /* 2's complement, MSB at lowest byte address */
/*============================================================================
The ELFOSIABI* macros are the allowed values of e_ident[EI_OSABI].
============================================================================*/
#define ELFOSABI_SYSV 0 /* System V ABI, third edition, no checking */
#define ELFOSABI_HPUX 1 /* HP-UX operating system */
#define ELFOSABI_SYSV 0 /* System V ABI, third edition, no checking */
#define ELFOSABI_HPUX 1 /* HP-UX operating system */
#define ELFOSABI_STANDALONE 255 /* STANDALONE operating system */
#define ELFOSABI_STANDALONE 255 /* STANDALONE operating system */
/*============================================================================
The ELFABIVERSION* macros are the allowed values of e_ident[EI_ABIVERSION].
============================================================================*/
#define ELFABI_HPUX_NONE 0 /* None specified */
#define ELFABI_HPUX_REL11 1
#define ELFABI_HPUX_NONE 0 /* None specified */
#define ELFABI_HPUX_REL11 1
/*============================================================================
@@ -162,17 +162,17 @@ typedef struct {
structure.
============================================================================*/
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* Relocatable file */
#define ET_EXEC 2 /* Executable file */
#define ET_DYN 3 /* Shared object file */
#define ET_CORE 4 /* Core file */
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* Relocatable file */
#define ET_EXEC 2 /* Executable file */
#define ET_DYN 3 /* Shared object file */
#define ET_CORE 4 /* Core file */
#define ET_LOOS 0xfe00 /* OS-specific lowest value */
#define ET_HIOS 0xfeff /* OS-specific highest value */
#define ET_LOOS 0xfe00 /* OS-specific lowest value */
#define ET_HIOS 0xfeff /* OS-specific highest value */
#define ET_LOPROC 0xff00 /* Processor-specific lowest value */
#define ET_HIPROC 0xffff /* Processor-specific highest value */
#define ET_LOPROC 0xff00 /* Processor-specific lowest value */
#define ET_HIPROC 0xffff /* Processor-specific highest value */
/*============================================================================
@@ -180,20 +180,20 @@ typedef struct {
ElfXX_Ehdr;
============================================================================*/
#define EV_NONE 0 /* Invalid version */
#define EV_CURRENT 1 /* Current version */
#define EV_NONE 0 /* Invalid version */
#define EV_CURRENT 1 /* Current version */
/*============================================================================
The ELFMAG* macros are the values of e_ident[EI_MAG0-4]
============================================================================*/
#define ELFMAG0 0x7f /* magic number, byte 0 */
#define ELFMAG1 'E' /* magic number, byte 1 */
#define ELFMAG2 'L' /* magic number, byte 2 */
#define ELFMAG3 'F' /* magic number, byte 3 */
#define ELFMAG "\177ELF" /* magic string */
#define SELFMAG 4 /* magic string length */
#define ELFMAG0 0x7f /* magic number, byte 0 */
#define ELFMAG1 'E' /* magic number, byte 1 */
#define ELFMAG2 'L' /* magic number, byte 2 */
#define ELFMAG3 'F' /* magic number, byte 3 */
#define ELFMAG "\177ELF" /* magic string */
#define SELFMAG 4 /* magic string length */
/*============================================================================
@@ -202,25 +202,25 @@ typedef struct {
============================================================================*/
typedef struct {
Elf64_Word p_type; /* Type of segment */
Elf64_Word p_flags; /* Segment attributes */
Elf64_Off p_offset; /* Offset in file */
Elf64_Addr p_vaddr; /* Virtual address in memory */
Elf64_Addr p_paddr; /* Reserved */
Elf64_Xword p_filesz; /* Size of segment in file */
Elf64_Xword p_memsz; /* Size of segment in memory */
Elf64_Xword p_align; /* Alignment of segment */
Elf64_Word p_type; /* Type of segment */
Elf64_Word p_flags; /* Segment attributes */
Elf64_Off p_offset; /* Offset in file */
Elf64_Addr p_vaddr; /* Virtual address in memory */
Elf64_Addr p_paddr; /* Reserved */
Elf64_Xword p_filesz; /* Size of segment in file */
Elf64_Xword p_memsz; /* Size of segment in memory */
Elf64_Xword p_align; /* Alignment of segment */
} Elf64_Phdr;
typedef struct {
Elf32_Word p_type; /* Type of segment */
Elf32_Off p_offset; /* Offset in file */
Elf32_Addr p_vaddr; /* Virtual address in memory */
Elf32_Addr p_paddr; /* Reserved */
Elf32_Xword p_filesz; /* Size of segment in file */
Elf32_Xword p_memsz; /* Size of segment in memory */
Elf32_Word p_flags; /* Segment attributes */
Elf32_Xword p_align; /* Alignment of segment */
Elf32_Word p_type; /* Type of segment */
Elf32_Off p_offset; /* Offset in file */
Elf32_Addr p_vaddr; /* Virtual address in memory */
Elf32_Addr p_paddr; /* Reserved */
Elf32_Xword p_filesz; /* Size of segment in file */
Elf32_Xword p_memsz; /* Size of segment in memory */
Elf32_Word p_flags; /* Segment attributes */
Elf32_Xword p_align; /* Alignment of segment */
} Elf32_Phdr;
@@ -228,32 +228,32 @@ typedef struct {
The PF_* macros are the segment flag bits in p_flags of ElfXX_Phdr.
============================================================================*/
#define PF_X 0x1 /* Execute */
#define PF_W 0x2 /* Write */
#define PF_R 0x4 /* Read */
#define PF_X 0x1 /* Execute */
#define PF_W 0x2 /* Write */
#define PF_R 0x4 /* Read */
#define PF_MASKOS 0x0ff00000 /* OS-specific */
#define PF_MASKOS 0x0ff00000 /* OS-specific */
#define PF_MASKPROC 0xf0000000 /* Processor-specific */
#define PF_MASKPROC 0xf0000000 /* Processor-specific */
/*============================================================================
The PT_* macros are the values of p_type in ElfXX_Phdr.
============================================================================*/
#define PT_NULL 0 /* Array element is unused. Ignore. */
#define PT_LOAD 1 /* Loadable segment. */
#define PT_DYNAMIC 2 /* Dynamic Section */
#define PT_INTERP 3 /* Section is a path to an interpreter */
#define PT_NOTE 4 /* Note Section */
#define PT_SHLIB 5 /* Currently unspecified semantics */
#define PT_PHDR 6 /* Program header table. */
#define PT_NULL 0 /* Array element is unused. Ignore. */
#define PT_LOAD 1 /* Loadable segment. */
#define PT_DYNAMIC 2 /* Dynamic Section */
#define PT_INTERP 3 /* Section is a path to an interpreter */
#define PT_NOTE 4 /* Note Section */
#define PT_SHLIB 5 /* Currently unspecified semantics */
#define PT_PHDR 6 /* Program header table. */
#define PT_LOOS 0x60000000 /* Lowest OS-specific type */
#define PT_HIOS 0x6fffffff /* Highest OS-specific type */
#define PT_LOOS 0x60000000 /* Lowest OS-specific type */
#define PT_HIOS 0x6fffffff /* Highest OS-specific type */
#define PT_LOPROC 0x70000000 /* Lowest Processor-specific type */
#define PT_HIPROC 0x7fffffff /* Highest Processor-specific type */
#define PT_LOPROC 0x70000000 /* Lowest Processor-specific type */
#define PT_HIPROC 0x7fffffff /* Highest Processor-specific type */
/*============================================================================
@@ -262,29 +262,29 @@ typedef struct {
============================================================================*/
typedef struct {
Elf64_Word sh_name; /* Section name */
Elf64_Word sh_type; /* Section type */
Elf64_Xword sh_flags; /* Section attributes */
Elf64_Addr sh_addr; /* Virtual address in memory */
Elf64_Off sh_offset; /* Offset in file */
Elf64_Xword sh_size; /* Size of section */
Elf64_Word sh_link; /* Link to other section */
Elf64_Word sh_info; /* Miscellaneous information */
Elf64_Xword sh_addralign; /* Address alignment boundary */
Elf64_Xword sh_entsize; /* Entry size, if section has table */
Elf64_Word sh_name; /* Section name */
Elf64_Word sh_type; /* Section type */
Elf64_Xword sh_flags; /* Section attributes */
Elf64_Addr sh_addr; /* Virtual address in memory */
Elf64_Off sh_offset; /* Offset in file */
Elf64_Xword sh_size; /* Size of section */
Elf64_Word sh_link; /* Link to other section */
Elf64_Word sh_info; /* Miscellaneous information */
Elf64_Xword sh_addralign; /* Address alignment boundary */
Elf64_Xword sh_entsize; /* Entry size, if section has table */
} Elf64_Shdr;
typedef struct {
Elf32_Word sh_name; /* Section name */
Elf32_Word sh_type; /* Section type */
Elf32_Xword sh_flags; /* Section attributes */
Elf32_Addr sh_addr; /* Virtual address in memory */
Elf32_Off sh_offset; /* Offset in file */
Elf32_Xword sh_size; /* Size of section */
Elf32_Word sh_link; /* Link to other section */
Elf32_Word sh_info; /* Miscellaneous information */
Elf32_Xword sh_addralign; /* Address alignment boundary*/
Elf32_Xword sh_entsize; /* Entry size, if section has table */
Elf32_Word sh_name; /* Section name */
Elf32_Word sh_type; /* Section type */
Elf32_Xword sh_flags; /* Section attributes */
Elf32_Addr sh_addr; /* Virtual address in memory */
Elf32_Off sh_offset; /* Offset in file */
Elf32_Xword sh_size; /* Size of section */
Elf32_Word sh_link; /* Link to other section */
Elf32_Word sh_info; /* Miscellaneous information */
Elf32_Xword sh_addralign; /* Address alignment boundary*/
Elf32_Xword sh_entsize; /* Entry size, if section has table */
} Elf32_Shdr;
@@ -292,51 +292,51 @@ typedef struct {
The ELF_STRING_xxx macros are names of common sections
============================================================================*/
#define ELF_STRING_bss ".bss"
#define ELF_STRING_hbss ".hbss"
#define ELF_STRING_sbss ".sbss"
#define ELF_STRING_tbss ".tbss"
#define ELF_STRING_data ".data"
#define ELF_STRING_hdata ".hdata"
#define ELF_STRING_sdata ".sdata"
#define ELF_STRING_fini ".fini"
#define ELF_STRING_init ".init"
#define ELF_STRING_interp ".interp"
#define ELF_STRING_rodata ".rodata"
#define ELF_STRING_text ".text"
#define ELF_STRING_comment ".comment"
#define ELF_STRING_dynamic ".dynamic"
#define ELF_STRING_dynstr ".dynstr"
#define ELF_STRING_dynsym ".dynsym"
#define ELF_STRING_dlt ".dlt"
#define ELF_STRING_note ".note"
#define ELF_STRING_bss ".bss"
#define ELF_STRING_hbss ".hbss"
#define ELF_STRING_sbss ".sbss"
#define ELF_STRING_tbss ".tbss"
#define ELF_STRING_data ".data"
#define ELF_STRING_hdata ".hdata"
#define ELF_STRING_sdata ".sdata"
#define ELF_STRING_fini ".fini"
#define ELF_STRING_init ".init"
#define ELF_STRING_interp ".interp"
#define ELF_STRING_rodata ".rodata"
#define ELF_STRING_text ".text"
#define ELF_STRING_comment ".comment"
#define ELF_STRING_dynamic ".dynamic"
#define ELF_STRING_dynstr ".dynstr"
#define ELF_STRING_dynsym ".dynsym"
#define ELF_STRING_dlt ".dlt"
#define ELF_STRING_note ".note"
#define ELF_STRING_opd ".opd"
#define ELF_STRING_plt ".plt"
#define ELF_STRING_plt ".plt"
#define ELF_STRING_bss_rela ".rela.bss"
#define ELF_STRING_hbss_rela ".rela.hbss"
#define ELF_STRING_hbss_rela ".rela.hbss"
#define ELF_STRING_data_rela ".rela.data"
#define ELF_STRING_dlt_rela ".rela.dlt"
#define ELF_STRING_plt_rela ".rela.plt"
#define ELF_STRING_sdata_rela ".rela.sdata"
#define ELF_STRING_strtab ".strtab"
#define ELF_STRING_symtab ".symtab"
#define ELF_STRING_hash ".hash"
#define ELF_STRING_shstrtab ".shstrtab"
#define ELF_STRING_shsymtab ".shsymtab"
#define ELF_STRING_rela ".rela"
#define ELF_STRING_rel ".rel"
#define ELF_STRING_strtab ".strtab"
#define ELF_STRING_symtab ".symtab"
#define ELF_STRING_hash ".hash"
#define ELF_STRING_shstrtab ".shstrtab"
#define ELF_STRING_shsymtab ".shsymtab"
#define ELF_STRING_rela ".rela"
#define ELF_STRING_rel ".rel"
/*============================================================================
The SHF_* macros are the allowed values of the sh_flags field of
The SHF_* macros are the allowed values of the sh_flags field of
ElfXX_Shdr. These 1-bit flags define attributes of a section.
============================================================================*/
#define SHF_WRITE 0x1 /* Writable during execution */
#define SHF_ALLOC 0x2 /* Occupies memory during execution */
#define SHF_EXECINSTR 0x4 /* Contains executable instructions */
#define SHF_WRITE 0x1 /* Writable during execution */
#define SHF_ALLOC 0x2 /* Occupies memory during execution */
#define SHF_EXECINSTR 0x4 /* Contains executable instructions */
#define SHF_MASKPROC 0xf0000000 /* mask for processor-specific bits */
#define SHF_MASKPROC 0xf0000000 /* mask for processor-specific bits */
/*============================================================================
@@ -344,44 +344,44 @@ typedef struct {
not have sections for these special indices.
============================================================================*/
#define SHN_UNDEF 0 /* undefined, e.g. undefined symbol */
#define SHN_UNDEF 0 /* undefined, e.g. undefined symbol */
#define SHN_LORESERVE 0xff00 /* Lower bound of reserved indices */
#define SHN_LORESERVE 0xff00 /* Lower bound of reserved indices */
#define SHN_LOPROC 0xff00 /* Lower bound processor-specific index */
#define SHN_HIPROC 0xff1f/* Upper bound processor-specific index */
#define SHN_LOPROC 0xff00 /* Lower bound processor-specific index */
#define SHN_HIPROC 0xff1f/* Upper bound processor-specific index */
#define SHN_LOOS 0xff20 /* Lower bound OS-specific index */
#define SHN_HIOS 0xff3f /* Upper bound OS-specific index */
#define SHN_LOOS 0xff20 /* Lower bound OS-specific index */
#define SHN_HIOS 0xff3f /* Upper bound OS-specific index */
#define SHN_ABS 0xfff1 /* Absolute value, not relocated */
#define SHN_COMMON 0xfff2/* FORTRAN common or unallocated C */
#define SHN_ABS 0xfff1 /* Absolute value, not relocated */
#define SHN_COMMON 0xfff2/* FORTRAN common or unallocated C */
#define SHN_HIRESERVE 0xffff /* Upper bound of reserved indices */
#define SHN_HIRESERVE 0xffff /* Upper bound of reserved indices */
/*============================================================================
SHT_* macros are the values of sh_type in ElfXX_Shdr
============================================================================*/
#define SHT_NULL 0 /* Inactive section header */
#define SHT_PROGBITS 1 /* Information defined by the program */
#define SHT_SYMTAB 2 /* Symbol table - not DLL */
#define SHT_STRTAB 3 /* String table */
#define SHT_RELA 4 /* Explicit addend relocations, Elf64_Rela */
#define SHT_HASH 5 /* Symbol hash table */
#define SHT_DYNAMIC 6 /* Information for dynamic linking */
#define SHT_NOTE 7 /* A Note section */
#define SHT_NOBITS 8 /* Like SHT_PROGBITS with no data */
#define SHT_REL 9 /* Implicit addend relocations, Elf64_Rel */
#define SHT_SHLIB 10 /* Currently unspecified semantics */
#define SHT_DYNSYM 11 /* Symbol table for a DLL */
#define SHT_NULL 0 /* Inactive section header */
#define SHT_PROGBITS 1 /* Information defined by the program */
#define SHT_SYMTAB 2 /* Symbol table - not DLL */
#define SHT_STRTAB 3 /* String table */
#define SHT_RELA 4 /* Explicit addend relocations, Elf64_Rela */
#define SHT_HASH 5 /* Symbol hash table */
#define SHT_DYNAMIC 6 /* Information for dynamic linking */
#define SHT_NOTE 7 /* A Note section */
#define SHT_NOBITS 8 /* Like SHT_PROGBITS with no data */
#define SHT_REL 9 /* Implicit addend relocations, Elf64_Rel */
#define SHT_SHLIB 10 /* Currently unspecified semantics */
#define SHT_DYNSYM 11 /* Symbol table for a DLL */
#define SHT_LOOS 0x60000000 /* Lowest OS-specific section type */
#define SHT_HIOS 0x6fffffff /* Highest OS-specific section type */
#define SHT_LOOS 0x60000000 /* Lowest OS-specific section type */
#define SHT_HIOS 0x6fffffff /* Highest OS-specific section type */
#define SHT_LOPROC 0x70000000 /* Lowest processor-specific section type */
#define SHT_HIPROC 0x7fffffff /* Highest processor-specific section type */
#define SHT_LOPROC 0x70000000 /* Lowest processor-specific section type */
#define SHT_HIPROC 0x7fffffff /* Highest processor-specific section type */
/*============================================================================
@@ -389,21 +389,21 @@ typedef struct {
============================================================================*/
typedef struct {
Elf64_Word st_name; /* Symbol name */
unsigned char st_info; /* Type and Binding attributes */
unsigned char st_other; /* Reserved */
Elf64_Half st_shndx; /* Section table index */
Elf64_Addr st_value; /* Symbol value */
Elf64_Xword st_size; /* Size of object (e.g., common) */
Elf64_Word st_name; /* Symbol name */
unsigned char st_info; /* Type and Binding attributes */
unsigned char st_other; /* Reserved */
Elf64_Half st_shndx; /* Section table index */
Elf64_Addr st_value; /* Symbol value */
Elf64_Xword st_size; /* Size of object (e.g., common) */
} Elf64_Sym;
typedef struct {
Elf32_Word st_name; /* Symbol name */
Elf32_Addr st_value; /* Symbol value */
Elf32_Xword st_size; /* Size of object (e.g., common) */
unsigned char st_info; /* Type and Binding attributes */
unsigned char st_other; /* Reserved */
Elf32_Half st_shndx; /* Section table index */
Elf32_Word st_name; /* Symbol name */
Elf32_Addr st_value; /* Symbol value */
Elf32_Xword st_size; /* Size of object (e.g., common) */
unsigned char st_info; /* Type and Binding attributes */
unsigned char st_other; /* Reserved */
Elf32_Half st_shndx; /* Section table index */
} Elf32_Sym;
@@ -413,13 +413,13 @@ typedef struct {
an st_info value from binding and type information.
============================================================================*/
#define ELF64_ST_BIND(val) ((val) >> 4)
#define ELF64_ST_TYPE(val) ((val) & 0xf)
#define ELF64_ST_INFO(bind,type) (((bind) << 4) + ((type) & 0xf))
#define ELF64_ST_BIND(val) ((val) >> 4)
#define ELF64_ST_TYPE(val) ((val) & 0xf)
#define ELF64_ST_INFO(bind,type) (((bind) << 4) + ((type) & 0xf))
#define ELF32_ST_BIND(val) ((val) >> 4)
#define ELF32_ST_TYPE(val) ((val) & 0xf)
#define ELF32_ST_INFO(bind,type) (((bind) << 4) + ((type) & 0xf))
#define ELF32_ST_BIND(val) ((val) >> 4)
#define ELF32_ST_TYPE(val) ((val) & 0xf)
#define ELF32_ST_INFO(bind,type) (((bind) << 4) + ((type) & 0xf))
/*============================================================================
@@ -427,7 +427,7 @@ typedef struct {
as the undefined symbol index.
============================================================================*/
#define STN_UNDEF 0
#define STN_UNDEF 0
/*============================================================================
@@ -435,15 +435,15 @@ typedef struct {
of st_info in ElfXX_Sym.
============================================================================*/
#define STB_LOCAL 0 /* Local symbols */
#define STB_GLOBAL 1 /* Globally visible symbols */
#define STB_WEAK 2 /* Global symbols with lower precedence */
#define STB_LOCAL 0 /* Local symbols */
#define STB_GLOBAL 1 /* Globally visible symbols */
#define STB_WEAK 2 /* Global symbols with lower precedence */
#define STB_LOOS 10 /* Lowest OS-specific value */
#define STB_HIOS 12 /* Highest OS-specific value */
#define STB_LOOS 10 /* Lowest OS-specific value */
#define STB_HIOS 12 /* Highest OS-specific value */
#define STB_LOPROC 13 /* Lowest processor-specific value */
#define STB_HIPROC 15 /* Highest processor-specific value */
#define STB_LOPROC 13 /* Lowest processor-specific value */
#define STB_HIPROC 15 /* Highest processor-specific value */
/*===========================================================================
@@ -451,17 +451,17 @@ typedef struct {
st_info in ElfXX_Sym.
============================================================================*/
#define STT_NOTYPE 0 /* Undefined symbol type */
#define STT_OBJECT 1 /* A data object, variable, array, etc. */
#define STT_FUNC 2 /* A function or other executable code */
#define STT_SECTION 3 /* Symbol associated with a section */
#define STT_FILE 4 /* Typically the name of the source file */
#define STT_NOTYPE 0 /* Undefined symbol type */
#define STT_OBJECT 1 /* A data object, variable, array, etc. */
#define STT_FUNC 2 /* A function or other executable code */
#define STT_SECTION 3 /* Symbol associated with a section */
#define STT_FILE 4 /* Typically the name of the source file */
#define STT_LOOS 10 /* Lowest OS-specific symbol type */
#define STT_HIOS 12 /* Highest OS-specific symbol type */
#define STT_LOOS 10 /* Lowest OS-specific symbol type */
#define STT_HIOS 12 /* Highest OS-specific symbol type */
#define STT_LOPROC 13 /* Lowest processor-specific symbol type */
#define STT_HIPROC 15 /* Highest processor-specific symbol type */
#define STT_LOPROC 13 /* Lowest processor-specific symbol type */
#define STT_HIPROC 15 /* Highest processor-specific symbol type */
/*============================================================================
@@ -469,13 +469,13 @@ typedef struct {
============================================================================*/
typedef struct {
Elf64_Addr r_offset; /* Address of reference */
Elf64_Xword r_info; /* Symbol index, relocation type */
Elf64_Addr r_offset; /* Address of reference */
Elf64_Xword r_info; /* Symbol index, relocation type */
} Elf64_Rel;
typedef struct {
Elf32_Addr r_offset; /* Address of reference */
Elf32_Xword r_info; /* Symbol index, reloc. type */
Elf32_Addr r_offset; /* Address of reference */
Elf32_Xword r_info; /* Symbol index, reloc. type */
} Elf32_Rel;
/*============================================================================
@@ -483,15 +483,15 @@ typedef struct {
============================================================================*/
typedef struct {
Elf64_Addr r_offset; /* Address of reference */
Elf64_Xword r_info; /* Symbol index, relocation type */
Elf64_Sxword r_addend; /* Constant part of expression */
Elf64_Addr r_offset; /* Address of reference */
Elf64_Xword r_info; /* Symbol index, relocation type */
Elf64_Sxword r_addend; /* Constant part of expression */
} Elf64_Rela;
typedef struct {
Elf32_Addr r_offset; /* Address of reference */
Elf32_Xword r_info; /* Symbol index, reloc. type */
Elf32_Sword r_addend; /* Constant part of expression */
Elf32_Addr r_offset; /* Address of reference */
Elf32_Xword r_info; /* Symbol index, reloc. type */
Elf32_Sword r_addend; /* Constant part of expression */
} Elf32_Rela;
@@ -502,15 +502,15 @@ typedef struct {
============================================================================*/
#define ELF64_R_INFO(sym,type) \
((((Elf64_Addr) (sym)) << 32) + ((Elf64_Addr) (type)))
((((Elf64_Addr) (sym)) << 32) + ((Elf64_Addr) (type)))
#define ELF64_R_SYM(info) \
((Elf64_Sword) (((Elf64_Addr) (info)) >> 32))
((Elf64_Sword) (((Elf64_Addr) (info)) >> 32))
#define ELF64_R_TYPE(info) \
((Elf64_Word) (((Elf64_Addr) (info)) & 0xffffffffLL))
((Elf64_Word) (((Elf64_Addr) (info)) & 0xffffffffLL))
#define ELF32_R_INFO(sym,type) (((sym) << 8) + ((unsigned char) (type)))
#define ELF32_R_SYM(info) ((info) >> 8)
#define ELF32_R_TYPE(info) ((unsigned char) (info))
#define ELF32_R_INFO(sym,type) (((sym) << 8) + ((unsigned char) (type)))
#define ELF32_R_SYM(info) ((info) >> 8)
#define ELF32_R_TYPE(info) ((unsigned char) (info))
/*============================================================================
@@ -518,21 +518,21 @@ typedef struct {
============================================================================*/
typedef struct {
Elf32_Sword d_tag;
union {
Elf32_Word d_val; /* unsigned word */
Elf32_Addr d_ptr; /* address */
} d_un;
Elf32_Sword d_tag;
union {
Elf32_Word d_val; /* unsigned word */
Elf32_Addr d_ptr; /* address */
} d_un;
} Elf32_Dyn;
extern Elf32_Dyn _DYNAMIC32[];
extern Elf32_Dyn _DYNAMIC32[];
typedef struct {
Elf64_Sxword d_tag;
union {
Elf64_Xword d_val; /* unsigned word */
Elf64_Addr d_ptr; /* address */
} d_un;
Elf64_Sxword d_tag;
union {
Elf64_Xword d_val; /* unsigned word */
Elf64_Addr d_ptr; /* address */
} d_un;
} Elf64_Dyn;
extern Elf64_Dyn _DYNAMIC[];
@@ -543,55 +543,55 @@ extern Elf64_Dyn _DYNAMIC[];
These are the Dynamic Array types.
============================================================================*/
/* (i)gnore (m)andatory (o)ptional */
/* d_un Exec DLL */
/* ---- ---- --- */
#define DT_NULL 0 /* ignored m m */
#define DT_NEEDED 1 /* d_val o o */
#define DT_PLTRELSZ 2 /* d_val o o */
#define DT_PLTGOT 3 /* d_ptr o o */
#define DT_HASH 4 /* d_ptr m m */
#define DT_STRTAB 5 /* d_ptr m m */
#define DT_SYMTAB 6 /* d_ptr m m */
#define DT_RELA 7 /* d_ptr m o */
#define DT_RELASZ 8 /* d_val m o */
#define DT_RELAENT 9 /* d_val m o */
#define DT_STRSZ 10 /* d_val m m */
#define DT_SYMENT 11 /* d_val m m */
#define DT_INIT 12 /* d_ptr o o */
#define DT_FINI 13 /* d_ptr o o */
#define DT_SONAME 14 /* d_val i o */
#define DT_RPATH 15 /* d_val o i */
#define DT_SYMBOLIC 16 /* ignored i o */
#define DT_REL 17 /* d_ptr m o */
#define DT_RELSZ 18 /* d_val m o */
#define DT_RELENT 19 /* d_val m o */
#define DT_PLTREL 20 /* d_val o o */
#define DT_DEBUG 21 /* d_ptr o i */
#define DT_TEXTREL 22 /* ignored o o */
#define DT_JMPREL 23 /* d_ptr o o */
#define DT_BIND_NOW 24 /* ignored */
#define DT_INIT_ARRAY 25 /* d_ptr o o */
#define DT_FINI_ARRAY 26 /* d_ptr o o */
#define DT_INIT_ARRAYSZ 27 /* d_val o o */
#define DT_FINI_ARRAYSZ 28 /* d_val o o */
/* (i)gnore (m)andatory (o)ptional */
/* d_un Exec DLL */
/* ---- ---- --- */
#define DT_NULL 0 /* ignored m m */
#define DT_NEEDED 1 /* d_val o o */
#define DT_PLTRELSZ 2 /* d_val o o */
#define DT_PLTGOT 3 /* d_ptr o o */
#define DT_HASH 4 /* d_ptr m m */
#define DT_STRTAB 5 /* d_ptr m m */
#define DT_SYMTAB 6 /* d_ptr m m */
#define DT_RELA 7 /* d_ptr m o */
#define DT_RELASZ 8 /* d_val m o */
#define DT_RELAENT 9 /* d_val m o */
#define DT_STRSZ 10 /* d_val m m */
#define DT_SYMENT 11 /* d_val m m */
#define DT_INIT 12 /* d_ptr o o */
#define DT_FINI 13 /* d_ptr o o */
#define DT_SONAME 14 /* d_val i o */
#define DT_RPATH 15 /* d_val o i */
#define DT_SYMBOLIC 16 /* ignored i o */
#define DT_REL 17 /* d_ptr m o */
#define DT_RELSZ 18 /* d_val m o */
#define DT_RELENT 19 /* d_val m o */
#define DT_PLTREL 20 /* d_val o o */
#define DT_DEBUG 21 /* d_ptr o i */
#define DT_TEXTREL 22 /* ignored o o */
#define DT_JMPREL 23 /* d_ptr o o */
#define DT_BIND_NOW 24 /* ignored */
#define DT_INIT_ARRAY 25 /* d_ptr o o */
#define DT_FINI_ARRAY 26 /* d_ptr o o */
#define DT_INIT_ARRAYSZ 27 /* d_val o o */
#define DT_FINI_ARRAYSZ 28 /* d_val o o */
#define DT_LOOS 0x60000000 /* unspecified - OS specific */
#define DT_HIOS 0x6fffffff /* unspecified - OS specific */
#define DT_LOOS 0x60000000 /* unspecified - OS specific */
#define DT_HIOS 0x6fffffff /* unspecified - OS specific */
#define DT_LOPROC 0x70000000 /* unspecified - processor specific */
#define DT_HIPROC 0x7fffffff /* unspecified - processor specific */
#define DT_LOPROC 0x70000000 /* unspecified - processor specific */
#define DT_HIPROC 0x7fffffff /* unspecified - processor specific */
#ifndef _HP_NO_ELF_DEPRICATED
/* These defines have been depricated and will be removed in a future release.*/
#define ELFOSABI_NONE 0 /* None specified */
#define ELFOSABI_NT 2 /* NT operating system */
#define ELFOSABI_SCOUNIX 3 /* SCO UNIX operating system */
#define SHF_COMDAT 0x8 /* Is a member of a COMDAT group */
#define SHT_COMDAT 12 /* COMDAT group directory -> SHT_HP_COMDAT */
#define ELFOSABI_NONE 0 /* None specified */
#define ELFOSABI_NT 2 /* NT operating system */
#define ELFOSABI_SCOUNIX 3 /* SCO UNIX operating system */
#define SHF_COMDAT 0x8 /* Is a member of a COMDAT group */
#define SHT_COMDAT 12 /* COMDAT group directory -> SHT_HP_COMDAT */
#endif /* ifndef _HP_NO_ELF_DEPRICATED */
@@ -600,7 +600,7 @@ extern Elf64_Dyn _DYNAMIC[];
#endif /* ifndef _HP_NO_ELF_DEPRICATED */
#if defined(ELF_TARGET_ALL) || defined(ELF_TARGET_PARISC)
#include <elf_parisc.h>
#include <elf_parisc.h>
#endif
#endif /* ELF_INCLUDED */
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,23 +14,23 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/*============================================================================
File: elftypes.h
Include file for Elf types. Define elf types for Elf structures.
Copyright Hewlett-Packard Co. 1995. All rights reserved.
/*============================================================================
File: elftypes.h
Include file for Elf types. Define elf types for Elf structures.
Copyright Hewlett-Packard Co. 1995. All rights reserved.
============================================================================*/
#ifndef ELFTYPES_INCLUDED
@@ -41,38 +41,38 @@ extern "C" {
#endif
#ifdef __LP64__
typedef unsigned int Elf32_Addr; /* Unsigned program address */
typedef unsigned int Elf32_Off; /* Unsigned file offset */
typedef int Elf32_Sword; /* Signed large integer */
typedef unsigned int Elf32_Xword; /* Unsigned large integer */
typedef unsigned int Elf32_Addr; /* Unsigned program address */
typedef unsigned int Elf32_Off; /* Unsigned file offset */
typedef int Elf32_Sword; /* Signed large integer */
typedef unsigned int Elf32_Xword; /* Unsigned large integer */
#else
typedef unsigned long Elf32_Addr; /* Unsigned program address */
typedef unsigned long Elf32_Off; /* Unsigned file offset */
typedef long Elf32_Sword; /* Signed large integer */
typedef unsigned long Elf32_Addr; /* Unsigned program address */
typedef unsigned long Elf32_Off; /* Unsigned file offset */
typedef long Elf32_Sword; /* Signed large integer */
typedef unsigned long Elf32_Xword; /* Unsigned large integer */
#endif
typedef unsigned int Elf32_Word; /* Unsigned large integer */
typedef unsigned short Elf32_Half; /* Unsigned medium integer */
typedef unsigned char Elf32_Char; /* Unsigned tiny integer */
typedef unsigned char Elf32_Byte; /* Unsigned tiny integer */
typedef unsigned int Elf32_Word; /* Unsigned large integer */
typedef unsigned short Elf32_Half; /* Unsigned medium integer */
typedef unsigned char Elf32_Char; /* Unsigned tiny integer */
typedef unsigned char Elf32_Byte; /* Unsigned tiny integer */
#ifdef __LP64__
typedef unsigned long Elf64_Addr;
typedef unsigned long Elf64_Off;
typedef unsigned long Elf64_Xword;
typedef long Elf64_Sxword;
typedef unsigned long Elf64_Addr;
typedef unsigned long Elf64_Off;
typedef unsigned long Elf64_Xword;
typedef long Elf64_Sxword;
#else
typedef unsigned long long Elf64_Addr;
typedef unsigned long long Elf64_Off;
typedef unsigned long long Elf64_Xword;
typedef long long Elf64_Sxword;
typedef unsigned long long Elf64_Addr;
typedef unsigned long long Elf64_Off;
typedef unsigned long long Elf64_Xword;
typedef long long Elf64_Sxword;
#endif
typedef unsigned short Elf64_Half;
typedef int Elf64_Sword;
typedef unsigned int Elf64_Word;
typedef unsigned char Elf64_Byte; /* Unsigned tiny integer */
typedef unsigned short Elf64_Half;
typedef int Elf64_Sword;
typedef unsigned int Elf64_Word;
typedef unsigned char Elf64_Byte; /* Unsigned tiny integer */
#ifdef __cplusplus
}
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,19 +14,19 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/*
C Header file <updatefw.h> for updatefw tool.
@@ -86,28 +86,56 @@ struct option updatefw_longopts[LONGOPTIONS_NB+1] = {
#define TRUE 1
#define FALSE 0
void show_usage(char* pgname) {
void show_usage(char* pgname)
{
unsigned int i;
fprintf(stderr, " %s : Tool to update firmware of Cardbus-MIMO-1/Leon3 card through the PCI interface,\n", pgname);
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " that is, even without using the Xilinx parallel cable. The tool performs sequentially\n");
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " the 5 following operations:\n");
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " 1) Ask card driver to reboot (optionally)\n");
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " 2) Ask card driver to transfer .text section\n");
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " 3) Ask card driver to transfer .data section\n");
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " 4) Ask card driver to clear .bss section\n");
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " 5) Ask card driver to have Leon processor set stack-pointer\n");
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, " and jump to firmware entry.\n");
fprintf(stderr, "Usage:\n");
fprintf(stderr, " %s [-f|--firmware 'filename'] [-s|--stackptr value] [-b|--forcereboot]\n",pgname);
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
fprintf(stderr, " ");
for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");
fprintf(stderr, "[-v|-vv|-vvv|-vvvv] [-h|--help] [-p|--pretend]\n\n");
fprintf(stderr, " [-f|--firmware ] Mandatory option, to set the name of the executable file\n");
fprintf(stderr, " of the firmware to update the remote card with.\n");
@@ -124,13 +152,16 @@ void show_usage(char* pgname) {
fprintf(stderr, " [-h|--help] Displays this help.\n");
}
int get_elf_header(Elf32_Ehdr* p_Elf32_hdr, FILE* p_file) {
int get_elf_header(Elf32_Ehdr* p_Elf32_hdr, FILE* p_file)
{
int nbread;
nbread = fread(p_Elf32_hdr, sizeof(elf_Ehdr), 1, p_file);
if (nbread != 1) {
fprintf(stderr, "Error : while reading ELF header (fread() returned %d)\n", nbread);
exit(-1);
}
invert2(p_Elf32_hdr->e_type); /* $$$$KMK: bad code !!! Endianess dependant ! */
invert2(p_Elf32_hdr->e_machine);
invert4(p_Elf32_hdr->e_version);
@@ -145,24 +176,27 @@ int get_elf_header(Elf32_Ehdr* p_Elf32_hdr, FILE* p_file) {
invert2(p_Elf32_hdr->e_shnum);
invert2(p_Elf32_hdr->e_shstrndx);
return (p_Elf32_hdr->e_type == ET_EXEC)
&& (p_Elf32_hdr->e_machine == EM_SPARC)
&& (p_Elf32_hdr->e_version == EV_CURRENT)
&& (p_Elf32_hdr->e_ident[EI_CLASS] == ELFCLASS32)
&& (p_Elf32_hdr->e_ident[EI_DATA] == ELFDATA2MSB)
&& (p_Elf32_hdr->e_ident[EI_VERSION] == EV_CURRENT);
&& (p_Elf32_hdr->e_machine == EM_SPARC)
&& (p_Elf32_hdr->e_version == EV_CURRENT)
&& (p_Elf32_hdr->e_ident[EI_CLASS] == ELFCLASS32)
&& (p_Elf32_hdr->e_ident[EI_DATA] == ELFDATA2MSB)
&& (p_Elf32_hdr->e_ident[EI_VERSION] == EV_CURRENT);
}
int get_elf_section_header(Elf32_Shdr* p_Elf32_Shdr, FILE* p_file, unsigned int section_ndx) {
int get_elf_section_header(Elf32_Shdr* p_Elf32_Shdr, FILE* p_file, unsigned int section_ndx)
{
int nbread;
/* retrieve the position of the section header table */
fseek(p_file, Shdr_pos + (section_ndx * elf_Ehdr.e_shentsize), 0);
/* set file pointer to the position of the section header section_ndx */
// seekrst = fseek(p_file, (long), 0);
nbread = fread(p_Elf32_Shdr, sizeof(elf_Shdr), 1, p_file);
if (nbread != 1) {
fprintf(stderr, "Error : while reading elf section header (fread() returned %d)\n", nbread);
exit(-1);
}
invert4(p_Elf32_Shdr->sh_name); /* $$$$KMK: bad code !!! Endianess dependant ! */
invert4(p_Elf32_Shdr->sh_type);
invert4(p_Elf32_Shdr->sh_flags);
@@ -179,7 +213,8 @@ int get_elf_section_header(Elf32_Shdr* p_Elf32_Shdr, FILE* p_file, unsigned int
return nbread;
}
void find_and_transfer_section(char* section_name, unsigned int verboselevel) {
void find_and_transfer_section(char* section_name, unsigned int verboselevel)
{
/* Interface with driver */
int ioctlretval;
int ifile;
@@ -189,9 +224,11 @@ void find_and_transfer_section(char* section_name, unsigned int verboselevel) {
for (secnb = 0 ; secnb < elf_Ehdr.e_shnum; secnb++) {
get_elf_section_header(&elf_Shdr, p_elfimage, secnb);
if (!strcmp(SecNameStnTable + elf_Shdr.sh_name, section_name)) {
if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS)
printf("Info: ok, found section %s (as section nb. %d)\n", SecNameStnTable + elf_Shdr.sh_name, secnb);
/* Check that section size is a multiple of 4 bytes. */
if (elf_Shdr.sh_size % 4) {
fprintf(stderr, "Error: section %s has a non-multiple-of-4-bytes size (%d).\n",
@@ -202,8 +239,10 @@ void find_and_transfer_section(char* section_name, unsigned int verboselevel) {
printf("Info: ok, section %s has size %d bytes (multiple of 4 bytes).\n",
SecNameStnTable + elf_Shdr.sh_name, elf_Shdr.sh_size);
}
/* Dynamically allocate a chunk of memory to store the section into. */
section_content = (char*)malloc(elf_Shdr.sh_size);
if (!section_content) {
fprintf(stderr, "Error: could not dynamically allocate %d bytes for section %s.\n",
elf_Shdr.sh_size, SecNameStnTable + elf_Shdr.sh_name);
@@ -213,10 +252,12 @@ void find_and_transfer_section(char* section_name, unsigned int verboselevel) {
printf("Info: ok, dynamically allocated a %d bytes buffer for section %s.\n",
elf_Shdr.sh_size, SecNameStnTable + elf_Shdr.sh_name);
}
/* Position the file cursor at the begining of proper section. */
fseek(p_elfimage, (long)(elf_Shdr.sh_offset), 0);
/* Copy the section's content into this temporary buffer. */
nbread = fread(section_content, elf_Shdr.sh_size, 1, p_elfimage);
if (nbread != 1) {
fprintf(stderr, "Error: could not read %d bytes from ELF file into dynamic buffer.\n", elf_Shdr.sh_size);
free(section_content);
@@ -226,9 +267,11 @@ void find_and_transfer_section(char* section_name, unsigned int verboselevel) {
printf("Info: ok, copied content of section %s into dynamic buffer (%d bytes copied).\n",
SecNameStnTable + elf_Shdr.sh_name, elf_Shdr.sh_size);
}
/* Open the special device file. */
if (!pflag) {
ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
if (ifile<0) {
fprintf(stderr, "Error: could not open %s (open() returned %d, errno=%u)\n", DEVICE_NAME, ifile, errno);
free(section_content);
@@ -237,6 +280,7 @@ void find_and_transfer_section(char* section_name, unsigned int verboselevel) {
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, successfully opened %s.\n", DEVICE_NAME);
}
/* Collect control data for ioctl. */
ioctl_params[0] = UPDATE_FIRMWARE_TRANSFER_BLOCK;
ioctl_params[1] = elf_Shdr.sh_addr;
@@ -246,6 +290,7 @@ void find_and_transfer_section(char* section_name, unsigned int verboselevel) {
//invert4(ioctl_params[2]);
/* Call ioctl driver */
ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
if (ioctlretval) {
fprintf(stderr, "Error: ioctl on %s failed.\n", DEVICE_NAME);
close(ifile);
@@ -256,14 +301,17 @@ void find_and_transfer_section(char* section_name, unsigned int verboselevel) {
printf("Info: ok, successful ioctl on %s for section %s.\n",
DEVICE_NAME, SecNameStnTable + elf_Shdr.sh_name);
}
close(ifile);
} /* pflag */
free(section_content);
} /* section_name */
} /* for secnb */
}
void find_and_clear_section_bss(unsigned int verboselevel) {
void find_and_clear_section_bss(unsigned int verboselevel)
{
/* Interface with driver */
int ioctlretval;
int ifile;
@@ -271,12 +319,15 @@ void find_and_clear_section_bss(unsigned int verboselevel) {
for (secnb = 0 ; secnb < elf_Ehdr.e_shnum; secnb++) {
get_elf_section_header(&elf_Shdr, p_elfimage, secnb);
if (!strcmp(SecNameStnTable + elf_Shdr.sh_name, ".bss")) {
if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS)
printf("Info: ok, found section %s (as section nb. %d)\n", SecNameStnTable + elf_Shdr.sh_name, secnb);
/* Open the special device file. */
if (!pflag) {
ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
if (ifile<0) {
fprintf(stderr, "Error: could not open %s (open() returned %d, errno=%u)\n", DEVICE_NAME, ifile, errno);
fclose(p_elfimage);
@@ -284,6 +335,7 @@ void find_and_clear_section_bss(unsigned int verboselevel) {
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, successfully opened %s.\n", DEVICE_NAME);
}
/* Collect control data for ioctl. */
ioctl_params[0] = UPDATE_FIRMWARE_CLEAR_BSS;
ioctl_params[1] = elf_Shdr.sh_addr;
@@ -292,6 +344,7 @@ void find_and_clear_section_bss(unsigned int verboselevel) {
//invert4(ioctl_params[2]);
/* Call ioctl driver */
ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
if (ioctlretval) {
fprintf(stderr, "Error: ioctl on %s failed.\n", DEVICE_NAME);
close(ifile);
@@ -301,13 +354,15 @@ void find_and_clear_section_bss(unsigned int verboselevel) {
printf("Info: ok, successful ioctl on %s for section %s.\n",
DEVICE_NAME, SecNameStnTable + elf_Shdr.sh_name);
}
close(ifile);
} /* pflag */
} /* section_name */
} /* for secnb */
}
int main(int argc, char** argv) {
int main(int argc, char** argv)
{
/* Interface with driver */
int ioctlretval;
int ifile;
@@ -331,35 +386,46 @@ int main(int argc, char** argv) {
while ((getoptret = getopt_long_only (argc, argv, "f:vhpns:b", updatefw_longopts, &indexptr)) != -1)
switch (getoptret) {
/* Without-argument options */
case 0: /* means that the option just sets a flag. Nothing has to be done,
case 0: /* means that the option just sets a flag. Nothing has to be done,
since getopt_long already sets the flag. */
break;
break;
/* With-argument options & equivalent short options */
case 'v':
verboselevel++;
break;
case 'h': /* short switch -h was used */
helpflag = SWITCH_IS_ON;
break;
case 'p': /* short switch -p was used */
pflag = SWITCH_IS_ON;
break;
case 'n': /* short switch -n was used */
noexecflag = SWITCH_IS_ON;
break;
case 'f': /* short switch -f was used */
fflag = SWITCH_IS_ON; p_str_fwn = optarg;
break;
case 's': /* short switch -s was used */
sflag = SWITCH_IS_ON; p_str_stkptr = optarg;
break;
case 'b': /* short switch -b was used */
rebootflag = SWITCH_IS_ON;
break;
default:
erroroption = TRUE;
break;
case 'v':
verboselevel++;
break;
case 'h': /* short switch -h was used */
helpflag = SWITCH_IS_ON;
break;
case 'p': /* short switch -p was used */
pflag = SWITCH_IS_ON;
break;
case 'n': /* short switch -n was used */
noexecflag = SWITCH_IS_ON;
break;
case 'f': /* short switch -f was used */
fflag = SWITCH_IS_ON;
p_str_fwn = optarg;
break;
case 's': /* short switch -s was used */
sflag = SWITCH_IS_ON;
p_str_stkptr = optarg;
break;
case 'b': /* short switch -b was used */
rebootflag = SWITCH_IS_ON;
break;
default:
erroroption = TRUE;
break;
};
/* End of while */
/********************************
@@ -370,38 +436,44 @@ int main(int argc, char** argv) {
fprintf(stderr, "%s: Misuse (--help to show usage)\n", argv[0]);
exit(-1);
}
/* Let print the help if it has been explicitly asked for */
if (helpflag == SWITCH_IS_ON) {
show_usage(argv[0]);
exit(0);
}
/* Check that mandatory firmware option was specified */
if (fflag != SWITCH_IS_ON) {
fprintf(stderr, "%s: missing mandatory [-f|--firmware] option (--help to show usage).\n", argv[0]);
exit(-1);
}
/* Check that mandatory stack pointer option was specified */
if (sflag != SWITCH_IS_ON) {
fprintf(stderr, "%s: missing mandatory [-s|--stackptr] option (--help to show usage).\n", argv[0]);
exit(-1);
}
/* Check consistency of stack pointer value. */
/* 1/2 - The address must start with the 2 characters '0x' and be exactly 10 characters long. */
if ((strncmp(p_str_stkptr, "0x", 2)) || (strlen(p_str_stkptr) != 10)) { /* 10 is for 0x + 8 hex digits. */
fprintf(stderr, "%s: Invalid value to [s|--stackptr] option (--help to show usage).\n", argv[0]);
exit(-1);
}
/* 2/2 - The address must only be made of hexadecimal digits. */
for (i=0,c=p_str_stkptr+2; i < 8 ; i++,c++) {
if (!
( ((*c >= '0') && (*c <= '9'))
|| ((*c >= 'a') && (*c <= 'f'))
|| ((*c >= 'A') && (*c <= 'F'))
)
) {
( ((*c >= '0') && (*c <= '9'))
|| ((*c >= 'a') && (*c <= 'f'))
|| ((*c >= 'A') && (*c <= 'F'))
)
) {
fprintf(stderr, "%s: Invalid value to [s|--stackptr] option (--help to show usage).\n", argv[0]);
exit(-1);
}
/* Transcode string hexadecinmal value into binary value */
if ((*c <= '9') && (*c >= '0'))
stackpointer |= (*c - '0') << 28-(i*4);
@@ -410,21 +482,26 @@ int main(int argc, char** argv) {
else if ((*c <= 'f') && (*c >= 'a'))
stackpointer |= ((*c - 'a') + 10) << 28-(i*4);
}
/* Open firmware file in READ_ONLY mode. */
filename = p_str_fwn;
p_elfimage = fopen(filename, READ_FILE_MODE);
if (p_elfimage == NULL) {
fprintf(stderr, "Error : could not open file <%s> in %s mode.\n", filename, READ_FILE_MODE);
exit(-1);
}
if (verboselevel >= VERBOSE_LEVEL_ACCESS_FILES)
printf("Info: using file <%s> (successfully opened in %s mode).\n", filename, READ_FILE_MODE);
/* Read elf binary image file */
/* Get informations from header file */
if (!(get_elf_header(&elf_Ehdr, p_elfimage))) {
fprintf(stderr, "Error : file doesn't match expected format.\n");
exit(-1);
}
if (verboselevel >= VERBOSE_LEVEL_ACCESS_FILES)
printf("Info: ok, file matches expected format.\n");
@@ -436,13 +513,15 @@ int main(int argc, char** argv) {
fseek(p_elfimage, (long)(elf_Shdr.sh_offset), 0);
StringSec_pos = ftell(p_elfimage);
StringSec_size = elf_Shdr.sh_size;
/* copy the string table into global variable */
if (StringSec_size > MAX_SIZE_STRING_TABLE) {
fprintf(stderr, "Error: section name string table too big (%d > %d);"
" increase max. allowed value in source code and recompile\n",
" increase max. allowed value in source code and recompile\n",
StringSec_size, MAX_SIZE_STRING_TABLE);
exit(-1);
}
fread(SecNameStnTable, 1, StringSec_size, p_elfimage);
/* Action 1: force reboot (if option was specified) */
@@ -452,8 +531,10 @@ int main(int argc, char** argv) {
else
printf("Info: squeezed action #1 (forcing reboot of Leon).\n");
}
if ((rebootflag == SWITCH_IS_ON) && (!pflag)) {
ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
if (ifile<0) {
fprintf(stderr, "Error: could not open %s (open() returned %d, errno=%u).\n", DEVICE_NAME, ifile, errno);
fclose(p_elfimage);
@@ -461,9 +542,11 @@ int main(int argc, char** argv) {
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, successfully opened %s.\n", DEVICE_NAME);
}
ioctl_params[0] = UPDATE_FIRMWARE_FORCE_REBOOT;
/* Call ioctl driver */
ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
if (ioctlretval) {
fprintf(stderr, "Error: ioctl on %s failed.\n", DEVICE_NAME);
close(ifile);
@@ -472,6 +555,7 @@ int main(int argc, char** argv) {
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, successful ioctl on %s to force reboot.\n", DEVICE_NAME);
}
/* If the card received the boot order, then
1) The firmware who handled the order must have cleared the BOOT_GOK bit
before rebooting ;
@@ -483,49 +567,65 @@ int main(int argc, char** argv) {
ever not to reboot cleanly. If the loop was to not end, user can simply
gives up the update-firmware operation by issuing a Ctrl-C. */
ioctl_params[0] = UPDATE_FIRMWARE_TEST_GOK;
/* Call ioctl driver */
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS)
printf("Info: waiting for GOK bit (as acknowledge of reboot command) - May take a few seconds...\n");
ioctl_test_gok = 0;
do {
ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
ioctl_test_gok++;
sleep(1); /* sleep 1 second */
if (!(ioctl_test_gok % 10))
printf("Warning: card does not seem to have rebooted cleanly (no GOK bit). Still trying ([Ctrl-C] to abort).\n");
} while (ioctlretval);
if (verboselevel >= VERBOSE_LEVEL_IOCTL)
printf("Info: ok, card set again GOK bit (after %u seconds).\n", ioctl_test_gok);
close(ifile);
} /* rebootflag && pflag */
if ((verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) && (rebootflag == SWITCH_IS_ON))
printf("Info: action #1 done.\n");
/* Action 2: Find the .text section */
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: entering action #2 (Transfer .text section).\n");
find_and_transfer_section(".text", verboselevel);
sleep(1);
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: action #2 done.\n");
/* Action 3 : Find the .data section */
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: entering action #3 (Transfer .data section).\n");
find_and_transfer_section(".data", verboselevel);
sleep(1);
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: action #3 done.\n");
/* Action 4 : Find the .bss section */
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: entering action #4 (Clear .bss section).\n");
find_and_clear_section_bss(verboselevel);
sleep(1);
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: action #4 done.\n");
/* Action 5 : Find the entry address */
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: entering action #5 (Jump to firmware/set stack-pointer).\n");
if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS)
printf("Info: Firmware entry point = 0x%08x, setting stack pointer = 0x%08x.\n", elf_Ehdr.e_entry, stackpointer);
/* Open the special device file. */
if (!pflag) {
ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
if (ifile<0) {
fprintf(stderr, "Error: could not open %s (open() returned %d, errno=%u).\n", DEVICE_NAME, ifile, errno);
fclose(p_elfimage);
@@ -533,15 +633,18 @@ int main(int argc, char** argv) {
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
printf("Info: ok, successfully opened %s.\n", DEVICE_NAME);
}
/* Collect control data for ioctl. */
ioctl_params[0] = UPDATE_FIRMWARE_START_EXECUTION;
ioctl_params[1] = elf_Ehdr.e_entry;
ioctl_params[2] = stackpointer;
//invert4(ioctl_params[1]);
//invert4(ioctl_params[2]);
/* Call ioctl driver */
if ( noexecflag == SWITCH_IS_OFF ) {
ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
if (ioctlretval) {
fprintf(stderr, "Error: ioctl on %s failed.\n", DEVICE_NAME);
close(ifile);
@@ -551,13 +654,16 @@ int main(int argc, char** argv) {
printf("Info: ok, successful ioctl on %s for stack-pointer setting/firmware-execution.\n", DEVICE_NAME);
}
}
close(ifile);
} /* pflag */
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: action #5 done.\n");
fclose(p_elfimage);
/* Did we pretend ? */
if (pflag) printf("Nothing done.\n");
exit(0);
}
@@ -1,5 +1,5 @@
/*******************************************************************************
OpenAirInterface
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
@@ -14,19 +14,19 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/*
C Header file <updatefw.h> for updatefw tool.
@@ -53,7 +53,7 @@ unsigned long ltmp;
#define invert4(x) {ltmp=x; x=((ltmp & 0xff)<<24) | ((ltmp & 0xff00)<<8) | \
((ltmp & 0xff0000)>>8) | ((ltmp & 0xff000000)>>24); }
unsigned short stmp;
#define invert2(x) {stmp=x; x=((stmp & 0xff)<< 8) | ((stmp & 0xff00)>>8);}
#define invert2(x) {stmp=x; x=((stmp & 0xff)<< 8) | ((stmp & 0xff00)>>8);}
/* static variables, global */