|
22 | 22 | #include <errlog.h> |
23 | 23 | #include <epicsString.h> |
24 | 24 | #include <epicsThread.h> |
25 | | -#include <epicsMutex.h> |
26 | 25 | #include <epicsEvent.h> |
27 | 26 | #include <epicsInterrupt.h> |
28 | 27 | #include <compilerDependencies.h> |
29 | 28 |
|
30 | | - |
31 | | -#include "devLibPCIImpl.h" |
| 29 | +#include "devLibPCIOSD.h" |
32 | 30 |
|
33 | 31 | /**@file devLibPCIOSD.c |
34 | 32 | * @brief Userspace PCI access in Linux |
|
82 | 80 | * |
83 | 81 | * Access after init is guarded by devLock |
84 | 82 | */ |
85 | | -struct osdPCIDevice { |
86 | | - epicsPCIDevice dev; /* "public" data */ |
87 | | - |
88 | | - /* result of mmap(), add offset before passing to user */ |
89 | | - volatile void *base[PCIBARCOUNT]; |
90 | | - /* offset from start of page to start of BAR */ |
91 | | - epicsUInt32 offset[PCIBARCOUNT]; |
92 | | - /* BAR length (w/o offset) */ |
93 | | - epicsUInt32 len[PCIBARCOUNT]; |
94 | | - volatile void *erom; |
95 | | - epicsUInt32 eromlen; |
96 | | - |
97 | | - epicsUInt32 displayBAR[PCIBARCOUNT]; /* Raw PCI address */ |
98 | | - epicsUInt32 displayErom; |
99 | | - |
100 | | - int fd; /* /dev/uio# */ |
101 | | - int cfd; /* config-space descriptor */ |
102 | | - int rfd[PCIBARCOUNT]; |
103 | | - int cmode; /* config-space mode */ |
104 | | - |
105 | | - epicsMutexId devLock; /* guard access to isrs list */ |
106 | | - |
107 | | - ELLNODE node; |
108 | | - |
109 | | - ELLLIST isrs; /* contains struct osdISR */ |
110 | | -}; |
111 | | -typedef struct osdPCIDevice osdPCIDevice; |
112 | 83 |
|
113 | 84 | #define dev2osd(dev) CONTAINER(dev, osdPCIDevice, dev) |
114 | 85 |
|
@@ -507,7 +478,7 @@ int linuxDevPCIInit(void) |
507 | 478 | /* Read BAR info */ |
508 | 479 |
|
509 | 480 | /* Base address */ |
510 | | - |
| 481 | + |
511 | 482 | filename = allocPrintf(BUSBASE "resource", |
512 | 483 | osd->dev.domain, osd->dev.bus, osd->dev.device, osd->dev.function); |
513 | 484 | if (!filename) { |
@@ -548,10 +519,10 @@ int linuxDevPCIInit(void) |
548 | 519 |
|
549 | 520 | osd->displayErom = start; |
550 | 521 | osd->eromlen = (start || stop ) ? (stop - start + 1) : 0; |
551 | | - |
| 522 | + |
552 | 523 | fclose(file); |
553 | 524 | free(filename); |
554 | | - |
| 525 | + |
555 | 526 | /* driver name */ |
556 | 527 | filename = allocPrintf(BUSBASE "driver", |
557 | 528 | osd->dev.domain, osd->dev.bus, osd->dev.device, osd->dev.function); |
@@ -922,6 +893,28 @@ int linuxDevPCIConnectInterrupt( |
922 | 893 | return ret; |
923 | 894 | } |
924 | 895 |
|
| 896 | +static int reopen_uio(struct osdPCIDevice *osd) |
| 897 | +{ |
| 898 | + int uio = find_uio_number(osd); |
| 899 | + if (uio < 0) |
| 900 | + return -1; |
| 901 | + |
| 902 | + char *devname = allocPrintf("/dev/uio%u", uio); |
| 903 | + if (!devname) |
| 904 | + return -1; |
| 905 | + |
| 906 | + int newfd = open(devname, O_RDWR); |
| 907 | + free(devname); |
| 908 | + if (newfd < 0) |
| 909 | + return -1; |
| 910 | + |
| 911 | + if (osd->fd != -1) |
| 912 | + close(osd->fd); |
| 913 | + |
| 914 | + osd->fd = newfd; |
| 915 | + return 0; |
| 916 | +} |
| 917 | + |
925 | 918 | static |
926 | 919 | void isrThread(void* arg) |
927 | 920 | { |
@@ -959,18 +952,36 @@ void isrThread(void* arg) |
959 | 952 | epicsInterruptUnlock(isrflag); |
960 | 953 | } |
961 | 954 |
|
962 | | - ret=read(osd->fd, &event, sizeof(event)); |
963 | | - if (ret==-1) { |
964 | | - switch(errno) { |
| 955 | + ret = read(osd->fd, &event, sizeof(event)); |
| 956 | + if (ret == -1) { |
| 957 | + switch (errno) { |
965 | 958 | case EINTR: /* interrupted by a signal */ |
966 | 959 | break; |
| 960 | + |
| 961 | + case EIO: |
| 962 | + case EINVAL: |
| 963 | + case ENODEV: |
| 964 | + errlogPrintf("isrThread '%s': Device removed or UIO invalid (errno=%d: %s)\n", name, errno, strerror(errno)); |
| 965 | + |
| 966 | + epicsMutexMustLock(osd->devLock); |
| 967 | + if (reopen_uio(osd) == 0) { |
| 968 | + errlogPrintf("isrThread '%s': Successfully reopened UIO device\n", name); |
| 969 | + if (osd->onHotSwapHook) osd->onHotSwapHook(osd); |
| 970 | + } else { |
| 971 | + errlogPrintf("isrThread '%s': UIO reopen failed. Will retry.\n", name); |
| 972 | + } |
| 973 | + epicsMutexUnlock(osd->devLock); |
| 974 | + epicsThreadSleep(1); |
| 975 | + continue; |
| 976 | + |
967 | 977 | default: |
968 | | - errlogPrintf("isrThread '%s' read error %d\n", |
969 | | - name,errno); |
970 | | - epicsThreadSleep(0.5); |
| 978 | + errlogPrintf("isrThread '%s': read error %d (%s)\n", name, errno, strerror(errno)); |
| 979 | + epicsThreadSleep(1); |
971 | 980 | } |
972 | | - } else |
973 | | - interrupted=1; |
| 981 | + } else { |
| 982 | + interrupted = 1; |
| 983 | + } |
| 984 | + |
974 | 985 |
|
975 | 986 | if (next!=event && next!=0) { |
976 | 987 | errlogPrintf("isrThread '%s' missed %d events\n", |
|
0 commit comments