mrfioc2  2.6.0
Classes | Macros | Functions
evgInit.cpp File Reference
#include <iostream>
#include <stdexcept>
#include <string>
#include <sstream>
#include <epicsExit.h>
#include <epicsThread.h>
#include <epicsStdio.h>
#include <epicsString.h>
#include <iocsh.h>
#include <drvSup.h>
#include <initHooks.h>
#include <errlog.h>
#include "mrf/object.h"
#include "mrf/databuf.h"
#include "mrf/pollirq.h"
#include "mrmpci.h"
#include <devcsr.h>
#include <mrfcsr.h>
#include <mrfCommonIO.h>
#include <devLibPCI.h>
#include "plx9030.h"
#include <epicsExport.h>
#include "evgRegMap.h"
#include "evgInit.h"
Include dependency graph for evgInit.cpp:

Go to the source code of this file.

Classes

struct  printreg
 

Macros

#define REGINFO(label, name, size)   {label, U##size##_##name, size}
 

Functions

void checkVersion (volatile epicsUInt8 *base, const MRFVersion &required, const MRFVersion &recommended)
 
epicsStatus mrmEvgSetupVME (const char *id, epicsInt32 slot, epicsUInt32 vmeAddress, epicsInt32 irqLevel, epicsInt32 irqVector)
 
epicsStatus mrmEvgSetupPCI (const char *id, const char *spec, int d, int f)
 
 epicsExportRegistrar (evgMrmRegistrar)
 
 epicsExportAddress (drvet, drvEvgMrm)
 

Macro Definition Documentation

◆ REGINFO

#define REGINFO (   label,
  name,
  size 
)    {label, U##size##_##name, size}

Function Documentation

◆ checkVersion()

void checkVersion ( volatile epicsUInt8 *  base,
const MRFVersion &  required,
const MRFVersion &  recommended 
)

Definition at line 165 of file evgInit.cpp.

167 {
168  epicsUInt32 type;
169  epicsUInt32 v = READ32(base, FPGAVersion);
170 
171  type = v & FPGAVersion_TYPE_MASK;
172  type = v >> FPGAVersion_TYPE_SHIFT;
173 
174  if(type != 0x2)
175  throw std::runtime_error("Address does not correspond to an EVG");
176 
177  MRFVersion ver(v);
178 
179  if(ver < required) {
180  std::ostringstream msg;
181  msg<<"Firmware version >= "<<required<<" is required\n";
182  throw std::runtime_error(msg.str());
183 
184  } else if(ver < recommended) {
185  std::cout<<"Firmware version >= "<<recommended<<" is recommended, please consider upgrading\n";
186  }
187 }
#define READ32(base, offset)
Definition: mrfCommonIO.h:114
#define FPGAVersion
Definition: mrf.h:133
#define FPGAVersion_TYPE_SHIFT
Definition: evgRegMap.h:107
#define FPGAVersion_TYPE_MASK
Definition: evgRegMap.h:104

◆ epicsExportAddress()

epicsExportAddress ( drvet  ,
drvEvgMrm   
)

◆ epicsExportRegistrar()

epicsExportRegistrar ( evgMrmRegistrar  )

◆ mrmEvgSetupPCI()

epicsStatus mrmEvgSetupPCI ( const char *  id,
const char *  spec,
int  d,
int  f 
)

Definition at line 365 of file evgInit.cpp.

370 {
371  if(d!=0 || f!=0) {
372  std::istringstream strm(spec);
373  unsigned B =0xf;
374  strm >> B;
375  char buf[40];
376  epicsSnprintf(buf, sizeof(buf), "%x:%x.%x", B, d, f);
377  buf[sizeof(buf)-1] = '\0';
378  spec = epicsStrDup(buf);
379  fprintf(stderr, "Deprecated call. Replace with:\n"
380  " mrmEvgSetupPCI(\"%s\", \"%s\")\n",
381  id, spec);
382  }
383 
384  try {
385  if (mrf::Object::getObject(id)) {
386  printf("ID %s already in use\n", id);
387  return -1;
388  }
389 
390  /* Linux only
391  * kernel driver interface version.
392  * 0 - Broken
393  * 1 - Use of irqcontrol callback to avoid races for plx pci bridges
394  * 2 - Use of new PCI master enable register to avoid races for soft pci bridges
395  */
396  int kifacever = -1;
397  if(checkUIOVersion(1,2,&kifacever))
398  return -1;
399 
400  /* Find PCI device from devLib2 */
401  const epicsPCIDevice *cur = 0;
402  if (devPCIFindSpec(mrmevgs, spec, &cur, 0)) {
403  printf("PCI Device not found\n");
404  return -1;
405  }
406 
407  bus_configuration bus;
408 
409  bus.busType = busType_pci;
410  bus.pci.dev = cur;
411 
412  printf("Device %s %x:%x.%x\n", id, cur->bus, cur->device,
413  cur->function);
414  printf("Using IRQ %u\n", cur->irq);
415 
416  /* MMap BAR0(plx) and BAR2(EVG)*/
417  volatile epicsUInt8 *BAR_plx, *BAR_evg;
418 
419  if (devPCIToLocalAddr(cur, 0, (volatile void**) (void *) &BAR_plx, 0)) {
420  printf("Failed to map BARs 0\n");
421  return -1;
422  }
423  if (!BAR_plx) {
424  printf("BAR0 mapped to zero? (%08lx)\n",
425  (unsigned long) BAR_plx);
426  return -1;
427  }
428 
429  switch(cur->id.device) {
430  case PCI_DEVICE_ID_PLX_9030: /* cPCI-EVG-220 and cPCI-EVG-230 */
431  if (devPCIToLocalAddr(cur, 2, (volatile void**) (void *) &BAR_evg, 0)) {
432  printf("Failed to map BARs 2\n");
433  return -1;
434  }
435  if (!BAR_evg) {
436  printf("BAR2 mapped to zero? (%08lx)\n",
437  (unsigned long) BAR_evg);
438  return -1;
439  }
440 
441 #if EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG
442  BITSET(LE,32, BAR_plx, LAS0BRD, LAS0BRD_ENDIAN);
443 #elif EPICS_BYTE_ORDER == EPICS_ENDIAN_LITTLE
444  BITCLR(LE,32, BAR_plx, LAS0BRD, LAS0BRD_ENDIAN);
445 #endif
446  break;
449  BAR_evg = BAR_plx;
450  /* the endianness the 300 series devices w/o PLX bridge
451  * is a little tricky to setup. byte order swapping is controlled
452  * through the EVR's Control register and access to this register
453  * is subject to byte order swapping...
454  */
455 
456  // Disable EVG and set's byte order to big endian
457  NAT_WRITE32(BAR_evg, Control, 0);
458  // Disable reception, and enable byte order swapping if necessary
459 #if EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG
460  BE_WRITE32(BAR_evg, Control, 0x70000000);
461 #elif EPICS_BYTE_ORDER == EPICS_ENDIAN_LITTLE
462  BE_WRITE32(BAR_evg, Control, 0x72000000);
463 #endif
464 
465  break;
466  default:
467  printf("Unknown/unsupported PCI device 0x%04x\n", (unsigned)cur->device);
468  return -1;
469  }
470 
471  printf("FPGA version: %08x\n", READ32(BAR_evg, FPGAVersion));
472  checkVersion(BAR_evg, MRFVersion(0, 3, 0), MRFVersion(0, 8, 0));
473 
474  /*Disable the interrupts and enable them at the end of iocInit via initHooks*/
475  WRITE32(BAR_evg, IrqFlag, READ32(BAR_evg, IrqFlag));
476  WRITE32(BAR_evg, IrqEnable, 0);
477 
478  const evgMrm::Config *conf = &conf_pci_misc;
479 
480  if(cur->id.device==PCI_DEVICE_ID_MRF_CPCIEVG300) {
481  conf = &conf_cpci_evg_300;
482  } else switch(cur->id.sub_device) {
483  case PCI_SUBDEVICE_ID_MRF_PXIEVG_220: conf = &conf_cpci_evg_220; break;
484  case PCI_DEVICE_ID_MRF_PXIEVG230: conf = &conf_cpci_evg_230; break;
485  case PCI_DEVICE_ID_MRF_MTCA_EVM_300: conf = &conf_mtca_evm_300; break;
486  }
487 
488  printf("%s #Inputs FP:%u UV:%u RB:%u\n", conf->model, conf->numFrontInp,
489  conf->numUnivInp, conf->numRearInp);
490 
491  evgMrm* evg = new evgMrm(id, conf, bus, BAR_evg, cur);
492 
493  MRFVersion ver(evg->version());
494 
495 #if !defined(__linux__) && !defined(_WIN32)
496  if(cur->id.device==PCI_DEVICE_ID_PLX_9030) {
497  // Enable active high interrupt1 through the PLX to the PCI bus.
499  }
500  if(ver>=MRFVersion(0, 8, 0)) {
501  // RTOS doesn't need this, so always enable
502  WRITE32(BAR_evg, PCI_MIE, EVG_MIE_ENABLE);
503  }
504 #else
505  if(ver>=MRFVersion(0, 8, 0) && kifacever>=2) {
506  // PCI master enable supported by firmware and kernel module.
507  // the kernel will set this bit when devPCIEnableInterrupt() is called
508  } else if(cur->id.device==PCI_DEVICE_ID_PLX_9030) {
509  // PLX based devices don't need special handling
510  WRITE32(BAR_evg, PCI_MIE, EVG_MIE_ENABLE);
511  } else if(ver<MRFVersion(0, 8, 0)) {
512  // old firmware and (maybe) old kernel module.
513  // this will still work, so just complain
514  printf("Warning: this configuration of FW and SW is known to have race conditions in interrupt handling.\n"
515  " Please consider upgrading to FW version 8.\n");
516  if(kifacever<2)
517  printf(" Also upgrade the linux kernel module to interface version 2.");
518  } else if(ver>=MRFVersion(0, 8, 0) && kifacever<2) {
519  // New firmware w/ old kernel module, this won't work
520  throw std::runtime_error("FW version 8 for this device requires a linux kernel module w/ interface version 2");
521  } else {
522  throw std::logic_error("logic error in FW/kernel module compatibility check.");
523  }
524  if(devPCIEnableInterrupt(cur)) {
525  printf("Failed to enable interrupt\n");
526  return -1;
527  }
528 #endif
529 
530  int ret;
531  /*Connect Interrupt handler to isr thread*/
532  if ((ret=devPCIConnectInterrupt(cur, &evgMrm::isr_pci, (void*) evg, 0))!=0) {
533  char buf[80];
534  errSymLookup(ret, buf, sizeof(buf));
535  printf("ERROR:Failed to connect PCI interrupt. err (%d) %s\n", ret, buf);
536  delete evg;
537  return -1;
538  } else {
539  // By default the IRQPollers for EVRU/D are disabled.
540  // __IRQP_EVRU/D_PRD selects the polling perdiod [s] and enables the equivalent EVM embedded EVR.
541 #ifdef __IRQP_EVRU_PRD
542  new IRQPoller(&EVRMRM::isr_poll, static_cast<void *>(evg->getEvruMrm()), __IRQP_EVRU_PRD);
543 #endif
544 #ifdef __IRQP_EVRD_PRD
545  new IRQPoller(&EVRMRM::isr_poll, static_cast<void *>(evg->getEvrdMrm()), __IRQP_EVRD_PRD);
546 #endif
547  printf("PCI interrupt connected!\n");
548  }
549 
550  return 0;
551 
552  } catch (std::exception& e) {
553  printf("Error: %s\n", e.what());
554  }
555  return -1;
556 } //mrmEvgSetupPCI
enum busType busType
#define PCI_DEVICE_ID_MRF_MTCA_EVM_300
Definition: uio_mrf.c:67
#define BITCLR(ord, len, base, offset, mask)
Definition: mrfBitOps.h:26
#define LE_WRITE16(base, offset, value)
Definition: mrfCommonIO.h:199
#define READ32(base, offset)
Definition: mrfCommonIO.h:114
#define LAS0BRD
Definition: mrf.h:41
unsigned numUnivInp
Definition: evgMrm.h:63
#define BE_WRITE32(base, offset, value)
Definition: mrfCommonIO.h:170
#define PCI_DEVICE_ID_MRF_CPCIEVG300
Definition: mrmpci.h:49
static Object * getObject(const std::string &name)
Definition: object.cpp:107
#define PCI_DEVICE_ID_XILINX_DEV
Definition: uio_mrf.c:48
#define FPGAVersion
Definition: mrf.h:133
struct configuration_pci pci
const epicsPCIDevice * dev
#define LAS0BRD_ENDIAN
Definition: plx9030.h:24
#define INTCSR_INT1_Polarity
Definition: plx9030.h:29
#define PCI_SUBDEVICE_ID_MRF_PXIEVG_220
Definition: uio_mrf.c:58
#define EVG_MIE_ENABLE
Definition: evgRegMap.h:64
#define NAT_WRITE32(base, offset, value)
Definition: mrfCommonIO.h:148
#define INTCSR
Definition: mrf.h:46
#define BITSET(ord, len, base, offset, mask)
Definition: mrfBitOps.h:21
static void isr_poll(void *)
Definition: drvem.cpp:1155
void checkVersion(volatile epicsUInt8 *base, const MRFVersion &required, const MRFVersion &recommended)
Definition: evgInit.cpp:165
static void isr_pci(void *)
Definition: evgMrm.cpp:289
unsigned numFrontInp
Definition: evgMrm.h:63
const char * model
Definition: evgMrm.h:62
#define WRITE32(base, offset, value)
Definition: mrfCommonIO.h:119
#define PCI_DEVICE_ID_MRF_PXIEVG230
Definition: mrmpci.h:45
Definition: evgMrm.h:56
#define PCI_DEVICE_ID_PLX_9030
Definition: uio_mrf.c:50
#define INTCSR_INT1_Enable
Definition: plx9030.h:28
#define INTCSR_PCI_Enable
Definition: plx9030.h:34
MRFVersion version() const
Definition: evgMrm.cpp:227
unsigned numRearInp
Definition: evgMrm.h:63

◆ mrmEvgSetupVME()

epicsStatus mrmEvgSetupVME ( const char *  id,
epicsInt32  slot,
epicsUInt32  vmeAddress,
epicsInt32  irqLevel,
epicsInt32  irqVector 
)

Definition at line 191 of file evgInit.cpp.

197 {
198  volatile epicsUInt8* regCpuAddr = 0;
199  struct VMECSRID info;
200  bus_configuration bus;
201 
202  info.board = 0; info.revision = 0; info.vendor = 0;
203 
204  bus.busType = busType_vme;
205  bus.vme.slot = slot;
206  bus.vme.address = vmeAddress;
207  bus.vme.irqLevel = irqLevel;
208  bus.vme.irqVector = irqVector;
209 
210  try {
211  if(mrf::Object::getObject(id)){
212  printf("ID %s already in use\n",id);
213  return -1;
214  }
215 
216  /*csrCpuAddr is VME-CSR space CPU address for the board*/
217  volatile unsigned char* csrCpuAddr =
218  devCSRTestSlot(vmeEvgIDs,slot,&info);
219 
220  if(!csrCpuAddr) {
221  printf("No EVG in slot %d\n",slot);
222  return -1;
223  }
224 
225  printf("##### Setting up MRF EVG in VME Slot %d #####\n",slot);
226  printf("Found Vendor: %08x\nBoard: %08x\nRevision: %08x\n",
227  info.vendor, info.board, info.revision);
228 
229  epicsUInt32 xxx = CSRRead32(csrCpuAddr + CSR_FN_ADER(1));
230  if(xxx)
231  printf("Warning: EVG not in power on state! (%08x)\n", xxx);
232 
233  /*Setting the base address of Register Map on VME Board (EVG)*/
234  CSRSetBase(csrCpuAddr, 1, vmeAddress, VME_AM_STD_SUP_DATA);
235 
236  {
237  epicsUInt32 temp=CSRRead32((csrCpuAddr) + CSR_FN_ADER(1));
238 
239  if(temp != CSRADER((epicsUInt32)vmeAddress,VME_AM_STD_SUP_DATA)) {
240  printf("Failed to set CSR Base address in ADER1. Check VME bus and card firmware version.\n");
241  return -1;
242  }
243  }
244 
245  /* Create a static string for the card description (needed by vxWorks) */
246  char *Description = allocSNPrintf(40, "EVG-%d '%s' slot %d",
247  info.board & MRF_BID_SERIES_MASK,
248  id, slot);
249 
250  /*Register VME address and get corresponding CPU address */
251  int status = devRegisterAddress (
252  Description, // Event Generator card description
253  atVMEA24, // A24 Address space
254  vmeAddress, // Physical address of register space
255  EVG_REGMAP_SIZE, // Size of card's register space
256  (volatile void **)(void *)&regCpuAddr // Local address of card's register map
257  );
258 
259  if(status) {
260  printf("Failed to map VME address %08x\n", vmeAddress);
261  return -1;
262  }
263 
264  {
265  epicsUInt32 junk;
266  if(devReadProbe(sizeof(junk), (volatile void*)(regCpuAddr+U32_FPGAVersion), (void*)&junk)) {
267  printf("Failed to read from MRM registers (but could read CSR registers)\n");
268  return -1;
269  }
270  }
271  printf("FPGA version: %08x\n", READ32(regCpuAddr, FPGAVersion));
272  checkVersion(regCpuAddr, MRFVersion(0, 3, 0), MRFVersion(0, 3, 0));
273 
274  const evgMrm::Config *conf = &conf_vme_evg_230;
275 
276  printf("%s #Inputs FP:%u UV:%u RB:%u\n", conf->model, conf->numFrontInp,
277  conf->numUnivInp, conf->numRearInp);
278 
279  evgMrm* evg = new evgMrm(id, conf, bus, regCpuAddr, NULL);
280 
281  if(irqLevel > 0 && irqVector >= 0) {
282  /*Configure the Interrupt level and vector on the EVG board*/
283  CSRWrite8(csrCpuAddr + MRF_UCSR_DEFAULT + UCSR_IRQ_LEVEL, irqLevel&0x7);
284  CSRWrite8(csrCpuAddr + MRF_UCSR_DEFAULT + UCSR_IRQ_VECTOR, irqVector&0xff);
285 
286  printf("IRQ Level: %d\nIRQ Vector: %d\n",
287  CSRRead8(csrCpuAddr + MRF_UCSR_DEFAULT + UCSR_IRQ_LEVEL),
288  CSRRead8(csrCpuAddr + MRF_UCSR_DEFAULT + UCSR_IRQ_VECTOR)
289  );
290 
291 
292  printf("csrCpuAddr : %p\nregCpuAddr : %p\n",csrCpuAddr, regCpuAddr);
293 
294  /*Disable the interrupts and enable them at the end of iocInit via initHooks*/
295  WRITE32(regCpuAddr, IrqFlag, READ32(regCpuAddr, IrqFlag));
296  WRITE32(regCpuAddr, IrqEnable, 0);
297 
298  // VME IRQ level will be enabled later during iocInit()
299  vme_level_mask |= 1 << ((irqLevel&0x7)-1);
300 
301  /*Connect Interrupt handler to vector*/
302  if(devConnectInterruptVME(irqVector & 0xff, &evgMrm::isr_vme, evg)){
303  printf("ERROR:Failed to connect VME IRQ vector %d\n"
304  ,irqVector&0xff);
305  delete evg;
306  return -1;
307  }
308  }
309 
310  errlogFlush();
311  return 0;
312  } catch(std::exception& e) {
313  printf("Error: %s\n",e.what());
314  }
315  errlogFlush();
316  return -1;
317 } //mrmEvgSetupVME
enum busType busType
static void isr_vme(void *)
Definition: evgMrm.cpp:308
#define READ32(base, offset)
Definition: mrfCommonIO.h:114
unsigned numUnivInp
Definition: evgMrm.h:63
#define EVG_REGMAP_SIZE
Definition: evgRegMap.h:242
#define MRF_UCSR_DEFAULT
Definition: evgInit.h:11
#define UCSR_IRQ_LEVEL
Definition: mrfcsr.h:59
#define MRF_BID_SERIES_MASK
Definition: mrfcsr.h:31
#define U32_FPGAVersion
Definition: evgRegMap.h:102
char * allocSNPrintf(size_t N, const char *fmt,...)
Definition: mrfCommon.cpp:58
static Object * getObject(const std::string &name)
Definition: object.cpp:107
#define FPGAVersion
Definition: mrf.h:133
#define UCSR_IRQ_VECTOR
Definition: mrfcsr.h:60
void checkVersion(volatile epicsUInt8 *base, const MRFVersion &required, const MRFVersion &recommended)
Definition: evgInit.cpp:165
unsigned numFrontInp
Definition: evgMrm.h:63
const char * model
Definition: evgMrm.h:62
#define WRITE32(base, offset, value)
Definition: mrfCommonIO.h:119
Definition: evgMrm.h:56
unsigned numRearInp
Definition: evgMrm.h:63