devLib2  2.11
osdPciShared.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2010 Brookhaven Science Associates, as Operator of
3 * Brookhaven National Laboratory.
4 * devLib2 is distributed subject to a Software License Agreement found
5 * in file LICENSE that is included with this distribution.
6 \*************************************************************************/
7 /*
8  * Author: Michael Davidsaver <mdavidsaver@gmail.com>
9  */
10 
11 #include <stdlib.h>
12 
13 #include <errlog.h>
14 #include <epicsMutex.h>
15 #include <epicsInterrupt.h>
16 
17 #include "devLibPCIImpl.h"
18 
19 #include "devLibPCI.h"
20 
21 #define epicsExportSharedSymbols
22 #include "osdPciShared.h"
23 
24 #ifndef PCI_MEM_OFFSET
25 # define PCI_MEM_OFFSET 0
26 #endif
27 
28 #ifndef PCI_IO_OFFSET
29 # define PCI_IO_OFFSET 0
30 #endif
31 
32 /* List of osdPCIDevice */
33 static ELLLIST devices;
34 
35 int
37 {
38  unsigned int b, d, f, bar;
39  osdPCIDevice *next;
40  uint8_t val8, header;
41  PCIUINT32 val32;
42 
43  /*
44  * Ensure all entries for the requested device/vendor pairs
45  * are in the 'devices' list.
46  * This function runs in single threaded context.
47  * Later the device list never changes.
48  * Thus there is no need for a semaphore.
49  */
50 
51  /* Read config space */
52  for (b=0; b<256; b++)
53  for (d=0; d<32; d++)
54  for (f=0; f<8; f++) {
55  /* no special bus cycle */
56  if (d == 31 && f == 7)
57  continue;
58 
59  /* check for existing device */
60  pci_read_config_dword(b,d,f,PCI_VENDOR_ID, &val32);
61  if (val32 == 0xffffffff)
62  break;
63 
64  if (devPCIDebug >= 1)
65  errlogPrintf("sharedDevPCIInit found %d.%d.%d: %08x\n",b,d,f, (unsigned)val32);
66 
67  next=calloc(1,sizeof(osdPCIDevice));
68  if (!next)
69  return S_dev_noMemory;
70 
71  next->dev.slot = DEVPCI_NO_SLOT;
72  next->dev.bus = b;
73  next->dev.device = d;
74  next->dev.function = f;
75  next->dev.id.vendor = val32&0xffff;
76  next->dev.id.device = val32>>16;
77 
78  pci_read_config_dword(b,d,f,PCI_SUBSYSTEM_VENDOR_ID, &val32);
79  next->dev.id.sub_vendor = val32&0xffff;
80  next->dev.id.sub_device = val32>>16;
81 
82  pci_read_config_dword(b,d,f,PCI_CLASS_REVISION, &val32);
83  next->dev.id.revision = val32&0xff;
84  next->dev.id.pci_class = val32>>8;
85 
86  if(devPCIDebug>=1)
87  errlogPrintf(" as pri %04x:%04x sub %04x:%04x cls %06x\n",
88  next->dev.id.vendor, next->dev.id.device,
89  next->dev.id.sub_vendor, next->dev.id.sub_device,
90  next->dev.id.pci_class);
91 
92  pci_read_config_byte(b,d,f,PCI_HEADER_TYPE, &header);
93  for (bar=0;bar<PCIBARCOUNT;bar++) {
94  if (bar>=2 && (header & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE)
95  {
96  if(devPCIDebug>=1)
97  errlogPrintf(" bridge device\n");
98  break;
99  }
100  pci_read_config_dword(b,d,f,PCI_BASE_ADDRESS(bar), &val32);
101  next->dev.bar[bar].ioport = (val32 & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO;
102  if (next->dev.bar[bar].ioport) {
103  /* This BAR is I/O ports */
104  next->base[bar] = PCI_IO_OFFSET + (val32 & PCI_BASE_ADDRESS_IO_MASK);
105  } else {
106  /* This BAR is memory mapped */
107  next->dev.bar[bar].below1M = !!(val32&PCI_BASE_ADDRESS_MEM_TYPE_1M);
108  next->dev.bar[bar].addr64 = !!(val32&PCI_BASE_ADDRESS_MEM_TYPE_64);
109  next->base[bar] = PCI_MEM_OFFSET + (val32 & PCI_BASE_ADDRESS_MEM_MASK);
110  /* TODO: Take care of 64 bit BARs! */
111  if (next->dev.bar[bar].addr64)
112  {
113  bar++;
114  pci_read_config_dword(b,d,f,PCI_BASE_ADDRESS(bar), &val32);
115  next->base[bar] = val32;
116  }
117  }
118  }
119 
120  pci_read_config_dword(b,d,f,PCI_ROM_ADDRESS, &val32);
121  next->erom = val32 & PCI_ROM_ADDRESS_MASK;
122 
123  pci_read_config_byte(b,d,f,PCI_INTERRUPT_LINE, &val8);
124  next->dev.irq = val8;
125 
126  ellInsert(&devices,ellLast(&devices),&next->node);
127 
128  if (f == 0 && !(header & PCI_HEADER_MULTI_FUNC))
129  {
130  if(devPCIDebug>=1)
131  errlogPrintf(" single function device\n");
132 
133  break;
134  }
135  }
136  return 0;
137 }
138 
139 /*
140  * Machinery for searching for PCI devices.
141  *
142  * This is a general function to support all possible
143  * search filtering conditions.
144  */
145 int
147  const epicsPCIID *idlist,
148  devPCISearchFn searchfn,
149  void *arg,
150  unsigned int opt /* always 0 */
151  )
152 {
153  int err=0;
154  ELLNODE *cur;
155  osdPCIDevice *curdev=NULL;
156  const epicsPCIID *search;
157 
158  (void)opt;
159  if (devPCIDebug>=1)
160  errlogPrintf("sharedDevPCIFindCB\n");
161 
162  if(!searchfn || !idlist)
163  return S_dev_badArgument;
164 
165  cur=ellFirst(&devices);
166  for(; cur; cur=ellNext(cur)){
167  curdev=CONTAINER(cur,osdPCIDevice,node);
168 
169  for(search=idlist; search && !!search->device; search++){
170 
171  if(!devLibPCIMatch(search, &curdev->dev.id))
172  continue;
173 
174  /* Match found */
175 
176  err=searchfn(arg,&curdev->dev);
177  switch(err){
178  case 0: /* Continue search */
179  break;
180  case 1: /* Abort search OK */
181  err=0;
182  default:/* Abort search Err */
183  goto done;
184  }
185  }
186  }
187 
188  err=0;
189 done:
190  return err;
191 }
192 
193 int
195  const epicsPCIDevice* dev,
196  unsigned int bar,
197  volatile void **ppLocalAddr,
198  unsigned int opt
199  )
200 {
201  struct osdPCIDevice *osd=pcidev2osd(dev);
202  (void)opt;
203 
204  /* No locking since the base address is not changed
205  * after the osdPCIDevice is created
206  */
207 
208  if(!osd->base[bar])
209  return S_dev_addrMapFail;
210 
211  if (dev->bar[bar].addr64)
212  {
213 #if __SIZEOF_POINTER__ > 4
214  *ppLocalAddr=(volatile void*)(osd->base[bar] | (long long)osd->base[bar+1] << 32);
215  return 0;
216 #else
217  if (osd->base[bar+1])
218  {
219  errlogPrintf("sharedDevPCIToLocalAddr: Unable map a 64 bit BAR on a 32 bit system");
220  return S_dev_addrMapFail;
221  }
222 #endif
223  }
224  *ppLocalAddr=(volatile void*)osd->base[bar];
225 
226  return 0;
227 }
228 
229 int
231  const epicsPCIDevice* dev,
232  unsigned int bar,
233  epicsUInt32 *len
234  )
235 {
236  struct osdPCIDevice *osd=pcidev2osd(dev);
237  int b=dev->bus, d=dev->device, f=dev->function;
238  PCIUINT32 start, max, mask;
239  long iflag;
240 
241  if(!osd->base[bar])
242  return S_dev_badSignalNumber;
243 
244  /* Disable interrupts since we are changing a device's PCI BAR
245  * register. This is not safe to do on an active device.
246  * Disabling interrupts avoids some, but not all, of these problems
247  */
248  iflag=epicsInterruptLock();
249 
250  if(osd->len[bar]) {
251  *len=osd->len[bar];
252  epicsInterruptUnlock(iflag);
253  return 0;
254  }
255 
256  /* Note: the following assumes the bar is 32-bit */
257 
258  if(dev->bar[bar].ioport)
259  mask=PCI_BASE_ADDRESS_IO_MASK;
260  else
261  mask=PCI_BASE_ADDRESS_MEM_MASK;
262 
263  /*
264  * The idea here is to find the least significant bit which
265  * is set by writing 1 to all the address bits.
266  *
267  * For example the mask for 32-bit IO Memory is 0xfffffff0
268  * If a base address is currently set to 0x00043000
269  * and when the mask is written the address becomes
270  * 0xffffff80 then the length is 0x80 (128) bytes
271  */
272  pci_read_config_dword(b,d,f,PCI_BASE_ADDRESS(bar), &start);
273 
274  /* If the BIOS didn't set this BAR then don't mess with it */
275  if((start&mask)==0) {
276  epicsInterruptUnlock(iflag);
277  return S_dev_badRequest;
278  }
279 
280  pci_write_config_dword(b,d,f,PCI_BASE_ADDRESS(bar), mask);
281  pci_read_config_dword(b,d,f,PCI_BASE_ADDRESS(bar), &max);
282  pci_write_config_dword(b,d,f,PCI_BASE_ADDRESS(bar), start);
283 
284  /* mask out bits which aren't address bits */
285  max&=mask;
286 
287  /* Find lsb */
288  osd->len[bar] = max & ~(max-1);
289 
290  *len=osd->len[bar];
291  epicsInterruptUnlock(iflag);
292  return 0;
293 }
294 
295 int
296 sharedDevPCIConfigAccess(const epicsPCIDevice *dev, unsigned offset, void *pArg, devPCIAccessMode mode)
297 {
298  int st = 1;
299 
300  if ( CFG_ACC_WRITE(mode) ) {
301  switch ( CFG_ACC_WIDTH(mode) ) {
302  default:
303  case 1:
304  st = pci_write_config_byte( dev->bus, dev->device, dev->function, (unsigned char)offset, *(uint8_t*)pArg );
305  break;
306 
307  case 2:
308  st = pci_write_config_word( dev->bus, dev->device, dev->function, (unsigned char)offset, *(uint16_t*)pArg );
309  break;
310  case 4:
311  st = pci_write_config_dword( dev->bus, dev->device, dev->function, (unsigned char)offset, *(uint32_t*)pArg );
312  break;
313  }
314  } else {
315  switch ( CFG_ACC_WIDTH(mode) ) {
316  default:
317  case 1:
318  st = pci_read_config_byte( dev->bus, dev->device, dev->function, (unsigned char)offset, pArg );
319  break;
320 
321  case 2:
322  st = pci_read_config_word( dev->bus, dev->device, dev->function, (unsigned char)offset, pArg );
323  break;
324  case 4:
325  st = pci_read_config_dword( dev->bus, dev->device, dev->function, (unsigned char)offset, pArg );
326  break;
327  }
328  }
329 
330  if (st) {
331  errlogPrintf("devLibPCIOSD: Unable to %s %u bytes %s configuration space: PCIBIOS error code 0x%02x\n",
332  CFG_ACC_WRITE(mode) ? "write" : "read",
333  CFG_ACC_WIDTH(mode),
334  CFG_ACC_WRITE(mode) ? "to" : "from",
335  st);
336 
337  return S_dev_internal;
338  } else {
339  return 0;
340  }
341 }
int(* devPCISearchFn)(void *ptr, const epicsPCIDevice *dev)
PCI search callback prototype.
Definition: devLibPCI.h:136
epicsUInt32 sub_device
Definition: devLibPCI.h:57
int sharedDevPCIFindCB(const epicsPCIID *idlist, devPCISearchFn searchfn, void *arg, unsigned int opt)
Definition: osdPciShared.c:146
unsigned int ioport
Definition: devLibPCI.h:98
epicsUInt32 len[PCIBARCOUNT]
Definition: osdPciShared.h:41
epicsPCIDevice dev
Definition: osdPciShared.h:36
int sharedDevPCIBarLen(const epicsPCIDevice *dev, unsigned int bar, epicsUInt32 *len)
Definition: osdPciShared.c:230
int devLibPCIMatch(const epicsPCIID *match, const epicsPCIID *dev)
Definition: devLibPCI.c:153
unsigned int below1M
Definition: devLibPCI.h:100
devPCIAccessMode
Definition: devLibPCIImpl.h:27
ELLNODE node
Definition: osdPciShared.h:44
epicsUInt32 sub_vendor
Definition: devLibPCI.h:57
unsigned int bus
Definition: devLibPCI.h:114
epicsUInt8 irq
Definition: devLibPCI.h:120
#define PCIBARCOUNT
The maximum number of base address registers (BARs).
Definition: devLibPCI.h:126
int devPCIDebug
Definition: devLibPCI.c:48
#define CONTAINER(ptr, structure, member)
Definition: devLibPCI.c:33
#define CFG_ACC_WRITE(mode)
Definition: devLibPCIImpl.h:37
int sharedDevPCIToLocalAddr(const epicsPCIDevice *dev, unsigned int bar, volatile void **ppLocalAddr, unsigned int opt)
Definition: osdPciShared.c:194
#define PCI_IO_OFFSET
Definition: osdPciShared.c:29
#define DEVPCI_NO_SLOT
Definition: devLibPCI.h:95
epicsUInt32 device
Definition: devLibPCI.h:56
#define CFG_ACC_WIDTH(mode)
Definition: devLibPCIImpl.h:36
Device token.
Definition: devLibPCI.h:112
unsigned int device
Definition: devLibPCI.h:115
#define PCI_MEM_OFFSET
Definition: osdPciShared.c:25
struct PCIBar bar[6]
Definition: devLibPCI.h:119
epicsUInt32 base[PCIBARCOUNT]
Definition: osdPciShared.h:40
PCI device identifier.
Definition: devLibPCI.h:55
unsigned int addr64
Definition: devLibPCI.h:99
epicsUInt32 erom
Definition: osdPciShared.h:42
epicsUInt16 revision
Definition: devLibPCI.h:59
const char * slot
Definition: devLibPCI.h:118
int sharedDevPCIConfigAccess(const epicsPCIDevice *dev, unsigned offset, void *pArg, devPCIAccessMode mode)
Definition: osdPciShared.c:296
int sharedDevPCIInit(void)
Definition: osdPciShared.c:36
epicsPCIID id
Exact ID of device.
Definition: devLibPCI.h:113
INLINE osdPCIDevice * pcidev2osd(const epicsPCIDevice *devptr)
Definition: osdPciShared.h:52
epicsUInt32 pci_class
Definition: devLibPCI.h:58
epicsUInt32 vendor
Definition: devLibPCI.h:56
unsigned int function
Definition: devLibPCI.h:116