diff --git a/configure/CONFIG_DEVLIB2_VERSION b/configure/CONFIG_DEVLIB2_VERSION index 4ae96e1..3cfb7da 100644 --- a/configure/CONFIG_DEVLIB2_VERSION +++ b/configure/CONFIG_DEVLIB2_VERSION @@ -1,2 +1,2 @@ DEVLIB2_MAJOR_VERSION = 2 -DEVLIB2_MINOR_VERSION = 12 +DEVLIB2_MINOR_VERSION = 13 diff --git a/pciApp/Makefile b/pciApp/Makefile index 41d101f..7b1ae88 100644 --- a/pciApp/Makefile +++ b/pciApp/Makefile @@ -20,6 +20,7 @@ DBD += epicspci.dbd INC += devLibPCI.h INC += devLibPCIImpl.h +INC += devLibPCIOSD.h epicspci_SRCS += devLibPCI.c epicspci_SRCS += devLibPCIStrings.c @@ -37,4 +38,3 @@ epicspci_LIBS += Com include $(TOP)/configure/RULES #---------------------------------------- # ADD RULES AFTER THIS LINE - diff --git a/pciApp/os/Linux/devLibPCIOSD.c b/pciApp/os/Linux/devLibPCIOSD.c index be0010d..1f138a6 100644 --- a/pciApp/os/Linux/devLibPCIOSD.c +++ b/pciApp/os/Linux/devLibPCIOSD.c @@ -22,13 +22,11 @@ #include #include #include -#include #include #include #include - -#include "devLibPCIImpl.h" +#include "devLibPCIOSD.h" /**@file devLibPCIOSD.c * @brief Userspace PCI access in Linux @@ -82,33 +80,6 @@ * * Access after init is guarded by devLock */ -struct osdPCIDevice { - epicsPCIDevice dev; /* "public" data */ - - /* result of mmap(), add offset before passing to user */ - volatile void *base[PCIBARCOUNT]; - /* offset from start of page to start of BAR */ - epicsUInt32 offset[PCIBARCOUNT]; - /* BAR length (w/o offset) */ - epicsUInt32 len[PCIBARCOUNT]; - volatile void *erom; - epicsUInt32 eromlen; - - epicsUInt32 displayBAR[PCIBARCOUNT]; /* Raw PCI address */ - epicsUInt32 displayErom; - - int fd; /* /dev/uio# */ - int cfd; /* config-space descriptor */ - int rfd[PCIBARCOUNT]; - int cmode; /* config-space mode */ - - epicsMutexId devLock; /* guard access to isrs list */ - - ELLNODE node; - - ELLLIST isrs; /* contains struct osdISR */ -}; -typedef struct osdPCIDevice osdPCIDevice; #define dev2osd(dev) CONTAINER(dev, osdPCIDevice, dev) @@ -507,7 +478,7 @@ int linuxDevPCIInit(void) /* Read BAR info */ /* Base address */ - + filename = allocPrintf(BUSBASE "resource", osd->dev.domain, osd->dev.bus, osd->dev.device, osd->dev.function); if (!filename) { @@ -548,10 +519,10 @@ int linuxDevPCIInit(void) osd->displayErom = start; osd->eromlen = (start || stop ) ? (stop - start + 1) : 0; - + fclose(file); free(filename); - + /* driver name */ filename = allocPrintf(BUSBASE "driver", osd->dev.domain, osd->dev.bus, osd->dev.device, osd->dev.function); @@ -922,6 +893,28 @@ int linuxDevPCIConnectInterrupt( return ret; } +static int reopen_uio(struct osdPCIDevice *osd) +{ + int uio = find_uio_number(osd); + if (uio < 0) + return -1; + + char *devname = allocPrintf("/dev/uio%u", uio); + if (!devname) + return -1; + + int newfd = open(devname, O_RDWR); + free(devname); + if (newfd < 0) + return -1; + + if (osd->fd != -1) + close(osd->fd); + + osd->fd = newfd; + return 0; +} + static void isrThread(void* arg) { @@ -959,18 +952,36 @@ void isrThread(void* arg) epicsInterruptUnlock(isrflag); } - ret=read(osd->fd, &event, sizeof(event)); - if (ret==-1) { - switch(errno) { + ret = read(osd->fd, &event, sizeof(event)); + if (ret == -1) { + switch (errno) { case EINTR: /* interrupted by a signal */ break; + + case EIO: + case EINVAL: + case ENODEV: + errlogPrintf("isrThread '%s': Device removed or UIO invalid (errno=%d: %s)\n", name, errno, strerror(errno)); + + epicsMutexMustLock(osd->devLock); + if (reopen_uio(osd) == 0) { + errlogPrintf("isrThread '%s': Successfully reopened UIO device\n", name); + if (osd->onHotSwapHook) osd->onHotSwapHook(osd); + } else { + errlogPrintf("isrThread '%s': UIO reopen failed. Will retry.\n", name); + } + epicsMutexUnlock(osd->devLock); + epicsThreadSleep(1); + continue; + default: - errlogPrintf("isrThread '%s' read error %d\n", - name,errno); - epicsThreadSleep(0.5); + errlogPrintf("isrThread '%s': read error %d (%s)\n", name, errno, strerror(errno)); + epicsThreadSleep(1); } - } else - interrupted=1; + } else { + interrupted = 1; + } + if (next!=event && next!=0) { errlogPrintf("isrThread '%s' missed %d events\n", diff --git a/pciApp/os/Linux/devLibPCIOSD.h b/pciApp/os/Linux/devLibPCIOSD.h new file mode 100644 index 0000000..dfbe566 --- /dev/null +++ b/pciApp/os/Linux/devLibPCIOSD.h @@ -0,0 +1,56 @@ +/*************************************************************************\ +* Copyright (c) 2010 Brookhaven Science Associates, as Operator of +* Brookhaven National Laboratory. +* devLib2 is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#ifndef DEVLIBPCIOSD_H_INC +#define DEVLIBPCIOSD_H_INC + +#include + +#include "devLibPCIImpl.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +struct osdPCIDevice +{ + epicsPCIDevice dev; /* "public" data */ + + /* result of mmap(), add offset before passing to user */ + volatile void* base[PCIBARCOUNT]; + /* offset from start of page to start of BAR */ + epicsUInt32 offset[PCIBARCOUNT]; + /* BAR length (w/o offset) */ + epicsUInt32 len[PCIBARCOUNT]; + volatile void* erom; + epicsUInt32 eromlen; + + epicsUInt32 displayBAR[PCIBARCOUNT]; /* Raw PCI address */ + epicsUInt32 displayErom; + + int fd; /* /dev/uio# */ + int cfd; /* config-space descriptor */ + int rfd[PCIBARCOUNT]; + int cmode; /* config-space mode */ + + epicsMutexId devLock; /* guard access to isrs list */ + + /* Optional callback invoked on PCI device hot-swap.*/ + void (*onHotSwapHook)(struct osdPCIDevice*); + + ELLNODE node; + + ELLLIST isrs; /* contains struct osdISR */ +}; +typedef struct osdPCIDevice osdPCIDevice; + +#ifdef __cplusplus +} +#endif + +#endif /* DEVLIBPCIOSD_H_INC */