EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: [Merge] lp:~mdavidsaver/epics-base/devlib-pci into lp:epics-base
From: mdavidsaver <[email protected]>
To: [email protected]
Date: Fri, 09 Jul 2010 19:36:08 -0000
mdavidsaver has proposed merging lp:~mdavidsaver/epics-base/devlib-pci into lp:epics-base.

Requested reviews:
  EPICS Core Developers (epics-core)


Extends devLib with a set of functions for PCI devices.

Currently implemented for RTEMS and vxWorks only.

The API is kept small.  It provides the following public functions in devLibPCI.h.

devPCIFindCB and devPCIFindBDF

Given a list of PCI identifiers or wildcards (an array of type epicsPCIID) the system is scanned for devices which match.  Search functions give back a pointer to a epicsPCIDevice structure.  This structure is populated with information taken from the PCI config space.  This information is read once when the device is first searched.

Once a device has been found there are four actions which can be performed on it: devPCIToLocalAddr, devPCIBarLen, devPCIConnectInterrupt, and devPCIDisconnectInterrupt.

devPCIToLocalAddr gets the CPU address corresponding to on of the Base Address Registers.

devPCIBarLen finds the size of a BAR in bytes.

devPCIConnectInterrupt and devPCIDisconnectInterrupt attach and detach interrupt handlers.  As with all PCI devices these handlers should be prepared to share the CPU interrupt line with several devices.


In order to implement support on other OSs the header devLibPCI.h provides access to the devLibPCI structure.

-- 
https://code.launchpad.net/~mdavidsaver/epics-base/devlib-pci/+merge/29603
Your team EPICS Core Developers is requested to review the proposed merge of lp:~mdavidsaver/epics-base/devlib-pci into lp:epics-base.
=== modified file 'src/libCom/Makefile'
--- src/libCom/Makefile	2010-05-25 12:58:49 +0000
+++ src/libCom/Makefile	2010-07-09 19:35:58 +0000
@@ -195,6 +195,8 @@
 INC += devLibVME.h
 INC += devLibVMEImpl.h
 INC += osdVME.h
+INC += devLibPCI.h
+INC += devLibPCIImpl.h
 
 SRCS += epicsThread.cpp
 SRCS += epicsMutex.cpp
@@ -234,6 +236,11 @@
 
 SRCS += devLibVME.c
 SRCS += devLibVMEOSD.c
+SRCS += devLibPCI.c
+SRCS += devLibPCIOSD.c
+
+SRCS_RTEMS   += osdPciShared.c
+SRCS_vxWorks += osdPciShared.c
 
 SRC_DIRS += $(LIBCOM)/taskwd
 INC += taskwd.h

=== added file 'src/libCom/osi/devLibPCI.c'
--- src/libCom/osi/devLibPCI.c	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/devLibPCI.c	2010-07-09 19:35:58 +0000
@@ -0,0 +1,180 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven Science Associates, as Operator of
+*     Brookhaven National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+#include <stdlib.h>
+
+#include <ellLib.h>
+#include <epicsThread.h>
+
+#include "devLibPCIImpl.h"
+
+#define epicsExportSharedSymbols
+#include "devLibPCI.h"
+
+static epicsThreadOnceId devPCIInit_once = EPICS_THREAD_ONCE_INIT;
+static int devPCIInit_result = 42;
+
+static
+void devInit(void* junk)
+{
+  if(!pdevLibPCI) {
+    devPCIInit_result = S_dev_internal;
+    return;
+  }
+
+  if(!!pdevLibPCI->pDevInit)
+    devPCIInit_result = (*pdevLibPCI->pDevInit)();
+
+  devPCIInit_result = 0;
+}
+
+#define PCIINIT \
+do { \
+     epicsThreadOnce(&devPCIInit_once, &devInit, NULL); \
+     if (devPCIInit_result) return devPCIInit_result; \
+} while(0)
+
+
+/**************** API functions *****************/
+
+epicsShareFunc
+int devPCIFindCB(
+     const epicsPCIID *idlist,
+     devPCISearchFn searchfn,
+     void *arg,
+     unsigned int opt /* always 0 */
+)
+{
+  if(!idlist || !searchfn)
+    return S_dev_badArgument;
+
+  PCIINIT;
+
+  return (*pdevLibPCI->pDevPCIFind)(idlist,searchfn,arg,opt);
+}
+
+
+struct bdfmatch
+{
+  unsigned int b,d,f;
+  epicsPCIDevice* found;
+};
+
+static
+int bdfsearch(void* ptr, epicsPCIDevice* cur)
+{
+  struct bdfmatch *mt=ptr;
+
+  if( cur->bus==mt->b && cur->device==mt->d &&
+      cur->function==mt->f )
+  {
+    mt->found=cur;
+    return 1;
+  }
+
+  return 0;
+}
+
+/*
+ * The most common PCI search using only id fields and BDF.
+ */
+epicsShareFunc
+int devPCIFindBDF(
+     const epicsPCIID *idlist,
+     unsigned int      b,
+     unsigned int      d,
+     unsigned int      f,
+      epicsPCIDevice **found,
+     unsigned int      opt
+)
+{
+  int err;
+  struct bdfmatch find;
+
+  if(!found)
+    return 2;
+
+  find.b=b;
+  find.d=d;
+  find.f=f;
+  find.found=NULL;
+
+  /* PCIINIT is called by devPCIFindCB()  */
+
+  err=devPCIFindCB(idlist,&bdfsearch,&find, opt);
+  if(err!=0){
+    /* Search failed? */
+    return err;
+  }
+
+  if(!find.found){
+    /* Not found */
+    return S_dev_noDevice;
+  }
+
+  *found=find.found;
+  return 0;
+}
+
+int
+devPCIToLocalAddr(
+  epicsPCIDevice *curdev,
+  unsigned int bar,
+  volatile void **ppLocalAddr,
+  unsigned int opt
+)
+{
+  PCIINIT;
+
+  if(bar>=PCIBARCOUNT)
+    return S_dev_badArgument;
+
+  return (*pdevLibPCI->pDevPCIToLocalAddr)(curdev,bar,ppLocalAddr,opt);
+}
+
+
+
+epicsShareFunc
+epicsUInt32
+devPCIBarLen(
+  epicsPCIDevice *curdev,
+          unsigned int  bar
+)
+{
+  PCIINIT;
+
+  if(bar>=PCIBARCOUNT)
+    return S_dev_badArgument;
+
+  return (*pdevLibPCI->pDevPCIBarLen)(curdev,bar);
+}
+
+epicsShareFunc
+int devPCIConnectInterrupt(
+  epicsPCIDevice *curdev,
+  void (*pFunction)(void *),
+  void  *parameter
+)
+{
+  PCIINIT;
+
+  return (*pdevLibPCI->pDevPCIConnectInterrupt)
+                (curdev,pFunction,parameter);
+}
+
+epicsShareFunc
+int devPCIDisconnectInterrupt(
+  epicsPCIDevice *curdev,
+  void (*pFunction)(void *),
+  void  *parameter
+)
+{
+  PCIINIT;
+
+  return (*pdevLibPCI->pDevPCIDisconnectInterrupt)
+                (curdev,pFunction,parameter);
+}

=== added file 'src/libCom/osi/devLibPCI.h'
--- src/libCom/osi/devLibPCI.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/devLibPCI.h	2010-07-09 19:35:58 +0000
@@ -0,0 +1,143 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven Science Associates, as Operator of
+*     Brookhaven National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+#ifndef DEVLIBPCI_H_INC
+#define DEVLIBPCI_H_INC 1
+
+#include <dbDefs.h>
+#include <epicsTypes.h>
+#include <devLib.h>
+#include <shareLib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* PCI device identifier
+ */
+
+typedef struct {
+  epicsUInt32 device, vendor;
+  epicsUInt32 sub_device, sub_vendor;
+  epicsUInt32 pci_class;
+  epicsUInt16 revision;
+} epicsPCIID;
+
+/* sub*, class, and revision are oversized to allow a
+ * distinct wildcard match value.
+ */
+#define DEVPCI_ANY_DEVICE 0x10000
+#define DEVPCI_ANY_VENDOR 0x10000
+#define DEVPCI_ANY_SUBDEVICE 0x10000
+#define DEVPCI_ANY_SUBVENDOR 0x10000
+#define DEVPCI_ANY_CLASS 0x1000000
+#define DEVPCI_ANY_REVISION 0x100
+
+/* Use the following macros when defining ID search lists.
+ *
+ * ie.
+ * static const epicsPCIID mydevs[] = {
+ *    DEVPCI_SUBDEVICE_SUBVENDOR( 0x1234, 0x1030, 0x0001, 0x4321 ),
+ *    DEVPCI_SUBDEVICE_SUBVENDOR( 0x1234, 0x1030, 0x0002, 0x4321 ),
+ *    DEVPCI_END
+ * };
+ */
+
+#define DEVPCI_END {0,0,0,0,0,0}
+
+#define DEVPCI_DEVICE_VENDOR(dev,vend) \
+{ dev, vend, DEVPCI_ANY_SUBDEVICE, DEVPCI_ANY_SUBVENDOR, \
+DEVPCI_ANY_CLASS, DEVPCI_ANY_REVISION }
+
+#define DEVPCI_DEVICE_VENDOR_CLASS(dev,vend,pclass) \
+{ dev, vend, DEVPCI_ANY_SUBDEVICE, DEVPCI_ANY_SUBVENDOR, \
+pclass, DEVPCI_ANY_REVISION }
+
+#define DEVPCI_SUBDEVICE_SUBVENDOR(dev,vend,sdev,svend) \
+{ dev, vend, sdev, svend, \
+DEVPCI_ANY_CLASS, DEVPCI_ANY_REVISION }
+
+#define DEVPCI_SUBDEVICE_SUBVENDOR_CLASS(dev,vend,sdev,svend,revision,pclass) \
+{ dev, vend, sdev, svend, \
+pclass, revision }
+
+struct PCIBar {
+  unsigned int ioport:1; /* 0 memory, 1 I/O */
+  unsigned int addr64:1; /* 0 32 bit, 1 64 bit */
+  unsigned int below1M:1; /* 0 Normal, 1 Must be mapped below 1M */
+};
+
+typedef struct {
+  epicsPCIID   id;
+  unsigned int bus;
+  unsigned int device;
+  unsigned int function;
+  struct PCIBar bar[6];
+  epicsUInt8 irq;
+  void *devpvt; /* For devLib clients */
+} epicsPCIDevice;
+
+#define PCIBARCOUNT NELEMENTS( ((epicsPCIDevice*)0)->bar )
+
+typedef int (*devPCISearchFn)(void*,epicsPCIDevice*);
+
+/*
+ * Expects a NULL terminated list of identifiers
+ */
+epicsShareFunc
+int devPCIFindCB(
+     const epicsPCIID *idlist,
+     devPCISearchFn searchfn,
+     void *arg,
+     unsigned int opt /* always 0 */
+);
+
+epicsShareFunc
+int devPCIFindBDF(
+     const epicsPCIID *idlist,
+     unsigned int      b,
+     unsigned int      d,
+     unsigned int      f,
+      epicsPCIDevice **found,
+     unsigned int opt /* always 0 */
+);
+
+epicsShareFunc
+int
+devPCIToLocalAddr(
+        epicsPCIDevice *id,
+          unsigned int  bar,
+        volatile void **ppLocalAddr,
+           unsigned int opt /* always 0 */
+);
+
+epicsShareFunc
+epicsUInt32
+devPCIBarLen(
+        epicsPCIDevice *id,
+          unsigned int  bar
+);
+
+epicsShareFunc
+int devPCIConnectInterrupt(
+        epicsPCIDevice *id,
+  void (*pFunction)(void *),
+  void  *parameter
+);
+
+epicsShareFunc
+int devPCIDisconnectInterrupt(
+        epicsPCIDevice *id,
+  void (*pFunction)(void *),
+  void  *parameter
+);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* DEVLIBPCI_H_INC */

=== added file 'src/libCom/osi/devLibPCIImpl.h'
--- src/libCom/osi/devLibPCIImpl.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/devLibPCIImpl.h	2010-07-09 19:35:58 +0000
@@ -0,0 +1,52 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven Science Associates, as Operator of
+*     Brookhaven National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+#ifndef DEVLIBPCIIMPL_H_INC
+#define DEVLIBPCIIMPL_H_INC
+
+#include <stddef.h>
+
+#include <dbDefs.h>
+#include <ellLib.h>
+#include <shareLib.h>
+#include <epicsTypes.h>
+
+#include "devLibPCI.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+
+  int (*pDevInit)(void);
+
+  int (*pDevFinal)(void);
+
+  int (*pDevPCIFind)(const epicsPCIID *ids, devPCISearchFn searchfn, void *arg, unsigned int o);
+
+  int (*pDevPCIToLocalAddr)(epicsPCIDevice* dev,unsigned int bar,volatile void **a,unsigned int o);
+
+  epicsUInt32 (*pDevPCIBarLen)(epicsPCIDevice* dev,unsigned int bar);
+
+  int (*pDevPCIConnectInterrupt)(epicsPCIDevice *id,
+                                 void (*pFunction)(void *),
+                                 void  *parameter);
+
+  int (*pDevPCIDisconnectInterrupt)(epicsPCIDevice *id,
+                                    void (*pFunction)(void *),
+                                    void  *parameter);
+
+} devLibPCI;
+
+epicsShareExtern devLibPCI *pdevLibPCI;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* DEVLIBPCIIMPL_H_INC */

=== added file 'src/libCom/osi/os/RTEMS/devLibPCIOSD.c'
--- src/libCom/osi/os/RTEMS/devLibPCIOSD.c	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/RTEMS/devLibPCIOSD.c	2010-07-09 19:35:58 +0000
@@ -0,0 +1,92 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven Science Associates, as Operator of
+*     Brookhaven National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+#include <stdlib.h>
+#include <epicsAssert.h>
+
+#include <rtems/pci.h>
+#include <rtems/endian.h>
+#include <rtems/irq.h>
+
+#include <dbDefs.h>
+
+#include "devLibPCIImpl.h"
+#include "osdPciShared.h"
+
+
+static
+int rtemsDevPCIConnectInterrupt(
+  epicsPCIDevice *dev,
+  void (*pFunction)(void *),
+  void  *parameter
+)
+{
+  struct osdPCIDevice *id=pcidev2osd(dev);
+
+  rtems_irq_connect_data isr;
+
+  isr.name = id->dev.irq;
+  isr.hdl = pFunction;
+  isr.handle = parameter;
+
+  isr.on = NULL;
+  isr.off= NULL;
+  isr.isOn=NULL;
+
+#if BSP_SHARED_HANDLER_SUPPORT > 0
+  isr.next_handler=NULL;
+
+  if (!BSP_install_rtems_shared_irq_handler(&isr))
+    return S_dev_vecInstlFail;
+#else
+  if (!BSP_install_rtems_irq_handler(&isr))
+    return S_dev_vecInstlFail;
+#endif
+
+  return 0;
+}
+
+static
+int rtemsDevPCIDisconnectInterrupt(
+  epicsPCIDevice *dev,
+  void (*pFunction)(void *),
+  void  *parameter
+)
+{
+  struct osdPCIDevice *id=pcidev2osd(dev);
+
+  rtems_irq_connect_data isr;
+
+  isr.name = id->dev.irq;
+  isr.hdl = pFunction;
+  isr.handle = parameter;
+
+  isr.on = NULL;
+  isr.off= NULL;
+  isr.isOn=NULL;
+
+#if BSP_SHARED_HANDLER_SUPPORT > 0
+  isr.next_handler=NULL;
+#endif
+
+  if(!BSP_remove_rtems_irq_handler(&isr))
+    return S_dev_intDisconnect;
+
+  return 0;
+}
+
+
+devLibPCI prtemsPCI = {
+  NULL, NULL,
+  sharedDevPCIFindCB,
+  sharedDevPCIToLocalAddr,
+  sharedDevPCIBarLen,
+  rtemsDevPCIConnectInterrupt,
+  rtemsDevPCIDisconnectInterrupt
+};
+
+devLibPCI *pdevLibPCI = &prtemsPCI;

=== added file 'src/libCom/osi/os/RTEMS/devLibPCIOSD.h'
--- src/libCom/osi/os/RTEMS/devLibPCIOSD.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/RTEMS/devLibPCIOSD.h	2010-07-09 19:35:58 +0000
@@ -0,0 +1,13 @@
+#ifndef OSDPCI_H_INC
+#define OSDPCI_H_INC
+
+#include <rtems/pci.h>
+#include <rtems/endian.h>
+#include <rtems/irq.h>
+
+/* 0 <= N <= 5 */
+#define PCI_BASE_ADDRESS(N) ( PCI_BASE_ADDRESS_0 + 4*(N) )
+
+#define UINT32 uint32_t
+
+#endif /* OSDPCI_H_INC */

=== added file 'src/libCom/osi/os/default/devLibPCIOSD.c'
--- src/libCom/osi/os/default/devLibPCIOSD.c	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/default/devLibPCIOSD.c	2010-07-09 19:35:58 +0000
@@ -0,0 +1,12 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven Science Associates, as Operator of
+*     Brookhaven National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+#include <stdlib.h>
+
+#include <devLibPCIImpl.h>
+
+devLibPCI *pdevLibPCI = NULL;

=== added file 'src/libCom/osi/os/vxWorks/devLibPCIOSD.c'
--- src/libCom/osi/os/vxWorks/devLibPCIOSD.c	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/vxWorks/devLibPCIOSD.c	2010-07-09 19:35:58 +0000
@@ -0,0 +1,95 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven Science Associates, as Operator of
+*     Brookhaven National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+#include <stdlib.h>
+#include <epicsAssert.h>
+
+#include <vxWorks.h>
+#include <types.h>
+#include <sysLib.h>
+#include <intLib.h>
+#include <iv.h>
+#include <drv/pci/pciIntLib.h>
+#include <vxLib.h>
+
+#include <dbDefs.h>
+
+#include "devLibPCIImpl.h"
+#include "osdPciShared.h"
+
+#if defined(VXPCIINTOFFSET)
+// do nothing
+
+#elif defined(INT_NUM_IRQ0)
+#define VXPCIINTOFFSET INT_NUM_IRQ0
+
+#elif defined(INT_VEC_IRQ0)
+#define VXPCIINTOFFSET INT_VEC_IRQ0
+
+#else
+#define VXPCIINTOFFSET 0
+
+#endif
+
+static
+int vxworksDevPCIConnectInterrupt(
+  epicsPCIDevice *dev,
+  void (*pFunction)(void *),
+  void  *parameter
+)
+{
+  int status;
+  struct osdPCIDevice *osd=pcidev2osd(dev);
+
+  status=pciIntConnect((void*)INUM_TO_IVEC(VXPCIINTOFFSET + osd->dev.irq),
+                       pFunction, (int)parameter);
+
+  if(status<0)
+    return S_dev_vecInstlFail;
+
+  return 1;
+}
+
+static
+int vxworksDevPCIDisconnectInterrupt(
+  epicsPCIDevice *dev,
+  void (*pFunction)(void *),
+  void  *parameter
+)
+{
+  int status;
+  struct osdPCIDevice *osd=pcidev2osd(dev);
+
+#ifdef VXWORKS_PCI_OLD
+
+  status=pciIntDisconnect((void*)INUM_TO_IVEC(VXPCIINTOFFSET + osd->dev.irq),
+                       pFunction);
+
+#else
+
+  status=pciIntDisconnect2((void*)INUM_TO_IVEC(VXPCIINTOFFSET + osd->dev.irq),
+                       pFunction, (int)parameter);
+
+#endif
+
+  if(status<0)
+    return S_dev_intDisconnect;
+
+  return 1;
+}
+
+
+devLibPCI pvxworksPCI = {
+  NULL, NULL,
+  sharedDevPCIFindCB,
+  sharedDevPCIToLocalAddr,
+  sharedDevPCIBarLen,
+  vxworksDevPCIConnectInterrupt,
+  vxworksDevPCIDisconnectInterrupt
+};
+
+devLibPCI *pdevLibPCI = &pvxworksPCI;

=== added file 'src/libCom/osi/os/vxWorks/devLibPCIOSD.h'
--- src/libCom/osi/os/vxWorks/devLibPCIOSD.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/vxWorks/devLibPCIOSD.h	2010-07-09 19:35:58 +0000
@@ -0,0 +1,50 @@
+#ifndef OSDPCI_H_INC
+#define OSDPCI_H_INC
+
+#include <vxWorks.h>
+#include <types.h>
+#include <drv/pci/pciConfigLib.h>
+#include <sysLib.h>
+#include <vxLib.h>
+
+/* The interfaces for PCI access on vxWorks and RTEMS
+ * are almost identical, except for the names.
+ *
+ * Here we map the RTEMS names to their vxWorks
+ * equivalent.
+ */
+
+#define pci_find_device pciFindDevice
+
+#define pci_read_config_byte  pciConfigInByte
+#define pci_read_config_word  pciConfigInWord
+#define pci_read_config_dword pciConfigInLong
+
+#define pci_write_config_byte  pciConfigOutByte
+#define pci_write_config_word  pciConfigOutWord
+#define pci_write_config_dword pciConfigOutLong
+
+
+/* 0 <= N <= 5 */
+#define PCI_BASE_ADDRESS(N) ( PCI_CFG_BASE_ADDRESS_0 + 4*(N) )
+
+#define PCI_DEVICE_ID           PCI_CFG_DEVICE_ID
+#define PCI_VENDOR_ID           PCI_CFG_VENDOR_ID
+#define PCI_SUBSYSTEM_ID        PCI_CFG_SUB_SYSTEM_ID
+#define PCI_SUBSYSTEM_VENDOR_ID PCI_CFG_SUB_VENDER_ID
+#define PCI_CLASS_REVISION      PCI_CFG_REVISION
+
+#define PCI_BASE_ADDRESS_SPACE    PCI_BAR_SPACE_MASK
+#define PCI_BASE_ADDRESS_SPACE_IO PCI_BAR_SPACE_IO
+
+#define PCI_BASE_ADDRESS_IO_MASK PCI_IOBASE_MASK
+
+#define PCI_BASE_ADDRESS_MEM_MASK    PCI_MEMBASE_MASK
+#define PCI_BASE_ADDRESS_MEM_TYPE_1M PCI_BAR_MEM_BELOW_1MB
+#define PCI_BASE_ADDRESS_MEM_TYPE_64 PCI_BAR_MEM_ADDR64
+
+#define PCI_ROM_ADDRESS      PCI_CFG_EXPANSION_ROM
+#define PCI_ROM_ADDRESS_MASK (~0x7ffUL)
+#define PCI_INTERRUPT_LINE   PCI_CFG_DEV_INT_LINE
+
+#endif /* OSDPCI_H_INC */

=== added file 'src/libCom/osi/osdPciShared.c'
--- src/libCom/osi/osdPciShared.c	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/osdPciShared.c	2010-07-09 19:35:58 +0000
@@ -0,0 +1,314 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven Science Associates, as Operator of
+*     Brookhaven National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+#include <stdlib.h>
+
+#include <ellLib.h>
+#include <errlog.h>
+
+#include "devLibPCIImpl.h"
+
+#include "devLibPCI.h"
+
+#define epicsExportSharedSymbols
+#include "osdPciShared.h"
+
+/* List of osdPCIDevice */
+static ELLLIST devices;
+
+typedef struct {
+  ELLNODE node;
+  epicsUInt16 device,vendor;
+} dev_vend_entry;
+
+/* List of dev_vend_entry */
+static ELLLIST dev_vend_cache;
+
+static
+int fill_cache(epicsUInt16 dev,epicsUInt16 vend);
+
+/*
+ * Machinery for searching for PCI devices.
+ *
+ * This is a general function to support all possible
+ * search filtering conditions.
+ */
+int
+sharedDevPCIFindCB(
+     const epicsPCIID *idlist,
+     devPCISearchFn searchfn,
+     void *arg,
+     unsigned int opt /* always 0 */
+)
+{
+  int err=0;
+  ELLNODE *cur;
+  osdPCIDevice *curdev=NULL;
+  const epicsPCIID *search;
+
+  if(!searchfn)
+    return S_dev_badArgument;
+
+  /*
+   * Ensure all entries for the requested device/vendor pairs
+   * are in the 'devices' list.
+   */
+  for(search=idlist; search && !!search->device; search++){
+    if(search->device==DEVPCI_ANY_DEVICE ||
+       search->vendor==DEVPCI_ANY_VENDOR)
+    {
+      errlogPrintf("devPCI: Wildcards are not supported in Device and Vendor fields\n");
+      return S_dev_badRequest;
+    }
+    if( (err=fill_cache(search->device, search->vendor)) )
+      return err;
+  }
+
+  /*
+   * The search proceeds once through the list of devices.
+   *
+   * Each device is compared to the list of ids.
+   * If it matches then control goes to the end of the outer
+   *  loop to determine if this is the requested instance.
+   * If not then the next device is searched.
+   *
+   * After the loops, 'curdev' can be non-NULL only if
+   * control did not hit one of the break statements.
+   */
+
+  cur=ellFirst(&devices);
+  for(; cur; cur=ellNext(cur)){
+    curdev=CONTAINER(cur,osdPCIDevice,node);
+
+    for(search=idlist; search && !!search->device; search++){
+
+      if(search->device!=curdev->dev.id.device)
+        break;
+      else
+      if(search->vendor!=curdev->dev.id.vendor)
+        break;
+      else
+      if( search->sub_device!=DEVPCI_ANY_SUBDEVICE &&
+          search->sub_device!=curdev->dev.id.sub_device
+        )
+        break;
+      else
+      if( search->sub_vendor!=DEVPCI_ANY_SUBVENDOR &&
+          search->sub_vendor!=curdev->dev.id.sub_vendor
+        )
+        break;
+      else
+      if( search->pci_class!=DEVPCI_ANY_CLASS &&
+          search->pci_class!=curdev->dev.id.pci_class
+        )
+        break;
+      else
+      if( search->revision!=DEVPCI_ANY_REVISION &&
+          search->revision!=curdev->dev.id.revision
+        )
+        break;
+
+      /* Match found */
+
+      err=searchfn(arg,&curdev->dev);
+      switch(err){
+      case 0: /* Continue search */
+        break;
+      case 1: /* Abort search OK */
+        return 0;
+      default:/* Abort search Err */
+        return err;
+      }
+
+    }
+
+  }
+
+  return 0;
+}
+
+int
+sharedDevPCIToLocalAddr(
+  epicsPCIDevice* dev,
+  unsigned int bar,
+  volatile void **ppLocalAddr,
+  unsigned int opt
+)
+{
+  struct osdPCIDevice *osd=pcidev2osd(dev);
+
+  if(!osd->base[bar])
+    return S_dev_addrMapFail;
+
+  *ppLocalAddr=osd->base[bar];
+  return 0;
+}
+
+epicsUInt32
+sharedDevPCIBarLen(
+  epicsPCIDevice* dev,
+  unsigned int bar
+)
+{
+  struct osdPCIDevice *osd=pcidev2osd(dev);
+  int b=dev->bus, d=dev->device, f=dev->function;
+  UINT32 start, max, mask;
+
+  if(!osd->base[bar])
+    return 0;
+
+  if(osd->len[bar])
+    return osd->len[bar];
+
+  /* Note: the following assumes the bar is 32-bit */
+
+  if(dev->bar[bar].ioport)
+    mask=PCI_BASE_ADDRESS_IO_MASK;
+  else
+    mask=PCI_BASE_ADDRESS_MEM_MASK;
+
+  /*
+   * The idea here is to find the least significant bit which
+   * is set by writing 1 to all the address bits.
+   *
+   * For example the mask for 32-bit IO Memory is 0xfffffff0
+   * If a base address is currently set to 0x00043000
+   * and when the mask is written the address becomes
+   * 0xffffff80 then the length is 0x80 (128) bytes
+   */
+  pci_read_config_dword(b,d,f,PCI_BASE_ADDRESS(bar), &start);
+
+  /* If the BIOS didn't set this BAR then don't mess with it */
+  if((start&mask)==0)
+    return 0;
+
+  pci_write_config_dword(b,d,f,PCI_BASE_ADDRESS(bar), mask);
+  pci_read_config_dword(b,d,f,PCI_BASE_ADDRESS(bar), &max);
+  pci_write_config_dword(b,d,f,PCI_BASE_ADDRESS(bar), start);
+
+  /* mask out bits which aren't address bits */
+  max&=mask;
+
+  /* Find lsb */
+  osd->len[bar] = max & ~(max-1);
+
+  return osd->len[bar];
+}
+
+
+
+/**************** local functions *****************/
+
+static
+int sharedDevPCIFind(epicsUInt16 dev,epicsUInt16 vend,ELLLIST* store)
+{
+  int N, ret=0, err;
+  int b, d, f, region;
+
+  /* Read config space */
+  uint8_t val8;
+  uint16_t val16;
+  UINT32 val32;
+
+  for(N=0; ; N++){
+
+    osdPCIDevice *next=calloc(1,sizeof(osdPCIDevice));
+    if(!next)
+      return S_dev_noMemory;
+
+    err=pci_find_device(vend,dev,N, &b, &d, &f);
+    if(err){ /* No more */
+      free(next);
+      break;
+    }
+    next->dev.bus=b;
+    next->dev.device=d;
+    next->dev.function=f;
+
+    pci_read_config_word(b,d,f,PCI_DEVICE_ID, &val16);
+    next->dev.id.device=val16;
+
+    pci_read_config_word(b,d,f,PCI_VENDOR_ID, &val16);
+    next->dev.id.vendor=val16;
+
+    pci_read_config_word(b,d,f,PCI_SUBSYSTEM_ID, &val16);
+    next->dev.id.sub_device=val16;
+
+    pci_read_config_word(b,d,f,PCI_SUBSYSTEM_VENDOR_ID, &val16);
+    next->dev.id.sub_vendor=val16;
+
+    pci_read_config_dword(b,d,f,PCI_CLASS_REVISION, &val32);
+    next->dev.id.revision=val32&0xff;
+    next->dev.id.pci_class=val32>>8;
+
+    for(region=0;region<PCIBARCOUNT;region++){
+      pci_read_config_dword(b,d,f,PCI_BASE_ADDRESS(region), &val32);
+
+      next->dev.bar[region].ioport=(val32 & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
+      if(next->dev.bar[region].ioport){
+        /* This BAR is I/O ports */
+        next->dev.bar[region].below1M=0;
+        next->dev.bar[region].addr64=0;
+
+        next->base[region]=(volatile void*)( val32 & PCI_BASE_ADDRESS_IO_MASK );
+
+        next->len[region]=0;
+
+      }else{
+        /* This BAR is memory mapped */
+        next->dev.bar[region].below1M=!!(val32&PCI_BASE_ADDRESS_MEM_TYPE_1M);
+        next->dev.bar[region].addr64=!!(val32&PCI_BASE_ADDRESS_MEM_TYPE_64);
+
+        next->base[region]=(volatile void*)( val32 & PCI_BASE_ADDRESS_MEM_MASK );
+
+        next->len[region]=0;
+      }
+    }
+
+    pci_read_config_dword(b,d,f,PCI_ROM_ADDRESS, &val32);
+    next->erom=(volatile void*)(val32 & PCI_ROM_ADDRESS_MASK);
+
+    pci_read_config_byte(b,d,f,PCI_INTERRUPT_LINE, &val8);
+    next->dev.irq=val8;
+
+    ellInsert(store,NULL,&next->node);
+  }
+
+  return ret;
+}
+
+static
+int fill_cache(epicsUInt16 dev,epicsUInt16 vend)
+{
+  ELLNODE *cur;
+  const dev_vend_entry *current;
+  dev_vend_entry *next;
+
+  for(cur=ellFirst(&dev_vend_cache); cur; cur=ellNext(cur)){
+    current=CONTAINER(cur,const dev_vend_entry,node);
+
+    /* If one device is found then all must be in cache */
+    if( current->device==dev && current->vendor==vend )
+      return 0;
+  }
+
+  next=malloc(sizeof(dev_vend_entry));
+  if(!next)
+    return S_dev_noMemory;
+  next->device=dev;
+  next->vendor=vend;
+
+  if( sharedDevPCIFind(dev,vend,&devices) ){
+    free(next);
+    return S_dev_addressNotFound;
+  }
+
+  /* Prepend */
+  ellInsert(&dev_vend_cache, NULL, &next->node);
+
+  return 0;
+}

=== added file 'src/libCom/osi/osdPciShared.h'
--- src/libCom/osi/osdPciShared.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/osdPciShared.h	2010-07-09 19:35:58 +0000
@@ -0,0 +1,67 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven Science Associates, as Operator of
+*     Brookhaven National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+#ifndef OSDPCISHARED_H_INC
+#define OSDPCISHARED_H_INC
+
+#include "devLibPCIOSD.h"
+
+/* Subtract member byte offset, returning pointer to parent object
+ *
+ * Added in Base 3.14.11
+ */
+#ifndef CONTAINER
+# ifdef __GNUC__
+#   define CONTAINER(ptr, structure, member) ({                     \
+        const __typeof(((structure*)0)->member) *_ptr = (ptr);      \
+        (structure*)((char*)_ptr - offsetof(structure, member));    \
+    })
+# else
+#   define CONTAINER(ptr, structure, member) \
+        ((structure*)((char*)(ptr) - offsetof(structure, member)))
+# endif
+#endif
+
+struct osdPCIDevice {
+  epicsPCIDevice dev; /* "public" data */
+
+  /* Can be used to cache values */
+  volatile void *base[PCIBARCOUNT];
+  epicsUInt32    len[PCIBARCOUNT];
+  volatile void *erom;
+
+  ELLNODE node;
+
+  void *drvpvt; /* for out of tree drivers */
+};
+typedef struct osdPCIDevice osdPCIDevice;
+
+#define pcidev2osd(devptr) CONTAINER(devptr,osdPCIDevice,dev)
+
+int
+sharedDevPCIFindCB(
+     const epicsPCIID *idlist,
+     devPCISearchFn searchfn,
+     void *arg,
+     unsigned int opt /* always 0 */
+);
+
+int
+sharedDevPCIToLocalAddr(
+  epicsPCIDevice* dev,
+  unsigned int bar,
+  volatile void **ppLocalAddr,
+  unsigned int opt
+);
+
+epicsUInt32
+sharedDevPCIBarLen(
+  epicsPCIDevice* dev,
+  unsigned int bar
+);
+
+#endif /* OSDPCISHARED_H_INC */


Replies:
Re: [Merge] lp:~mdavidsaver/epics-base/devlib-pci into lp:epics-base Eric Norum

Navigate by Date:
Prev: Re: [Merge] lp:~dirk.zimoch/epics-base/fix-aai-and-aao into lp:epics-base Dirk Zimoch
Next: Re: [Merge] lp:~mdavidsaver/epics-base/devlib-pci into lp:epics-base Eric Norum
Index: 2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: Merges: 3.14.12 vs 3.15 Andrew Johnson
Next: Re: [Merge] lp:~mdavidsaver/epics-base/devlib-pci into lp:epics-base Eric Norum
Index: 2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 02 Feb 2012 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·