2 * Copyright (c) 2008 Mark Kettenis
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <sys/param.h>
18 #include <sys/ioctl.h>
19 #include <sys/memrange.h>
21 #include <sys/pciio.h>
23 #include <dev/pci/pcireg.h>
24 #include <dev/pci/pcidevs.h>
33 #include "pciaccess.h"
34 #include "pciaccess_private.h"
36 static int pcifd = -1;
37 static int aperturefd = -1;
40 pci_read(int bus, int dev, int func, uint32_t reg, uint32_t *val)
45 bzero(&io, sizeof(io));
46 io.pi_sel.pc_bus = bus;
47 io.pi_sel.pc_dev = dev;
48 io.pi_sel.pc_func = func;
52 err = ioctl(pcifd, PCIOCREAD, &io);
62 pci_write(int bus, int dev, int func, uint32_t reg, uint32_t val)
66 bzero(&io, sizeof(io));
67 io.pi_sel.pc_bus = bus;
68 io.pi_sel.pc_dev = dev;
69 io.pi_sel.pc_func = func;
74 return ioctl(pcifd, PCIOCWRITE, &io);
78 pci_nfuncs(int bus, int dev)
82 if (pci_read(bus, dev, 0, PCI_BHLC_REG, &hdr) != 0)
85 return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1);
89 pci_device_openbsd_map_range(struct pci_device *dev,
90 struct pci_device_mapping *map)
92 struct mem_range_desc mr;
93 struct mem_range_op mo;
96 if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
99 map->memory = mmap(NULL, map->size, prot, MAP_SHARED, aperturefd,
101 if (map->memory == MAP_FAILED)
104 /* No need to set an MTRR if it's the default mode. */
105 if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
106 (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
107 mr.mr_base = map->base;
108 mr.mr_len = map->size;
110 if (map->flags & PCI_DEV_MAP_FLAG_CACHABLE)
111 mr.mr_flags |= MDF_WRITEBACK;
112 if (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)
113 mr.mr_flags |= MDF_WRITECOMBINE;
114 strlcpy(mr.mr_owner, "pciaccess", sizeof(mr.mr_owner));
117 mo.mo_arg[0] = MEMRANGE_SET_UPDATE;
119 if (ioctl(aperturefd, MEMRANGE_SET, &mo))
127 pci_device_openbsd_unmap_range(struct pci_device *dev,
128 struct pci_device_mapping *map)
130 struct mem_range_desc mr;
131 struct mem_range_op mo;
133 if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
134 (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
135 mr.mr_base = map->base;
136 mr.mr_len = map->size;
137 mr.mr_flags = MDF_UNCACHEABLE;
138 strlcpy(mr.mr_owner, "pciaccess", sizeof(mr.mr_owner));
141 mo.mo_arg[0] = MEMRANGE_SET_REMOVE;
143 (void)ioctl(aperturefd, MEMRANGE_SET, &mo);
146 return pci_device_generic_unmap_range(dev, map);
150 pci_device_openbsd_read(struct pci_device *dev, void *data,
151 pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
155 io.pi_sel.pc_bus = dev->bus;
156 io.pi_sel.pc_dev = dev->dev;
157 io.pi_sel.pc_func = dev->func;
161 int toread = MIN(size, 4 - (offset & 0x3));
163 io.pi_reg = (offset & ~0x3);
166 if (ioctl(pcifd, PCIOCREAD, &io) == -1)
169 io.pi_data = htole32(io.pi_data);
170 io.pi_data >>= ((offset & 0x3) * 8);
172 memcpy(data, &io.pi_data, toread);
175 data = (char *)data + toread;
177 *bytes_read += toread;
184 pci_device_openbsd_write(struct pci_device *dev, const void *data,
185 pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
189 if ((offset % 4) != 0 || (size % 4) != 0)
192 io.pi_sel.pc_bus = dev->bus;
193 io.pi_sel.pc_dev = dev->dev;
194 io.pi_sel.pc_func = dev->func;
200 memcpy(&io.pi_data, data, 4);
202 if (ioctl(pcifd, PCIOCWRITE, &io) == -1)
206 data = (char *)data + 4;
215 pci_system_openbsd_destroy(void)
226 pci_device_openbsd_probe(struct pci_device *device)
228 struct pci_device_private *priv = (struct pci_device_private *)device;
229 struct pci_mem_region *region;
230 uint64_t reg64, size64;
231 uint32_t bar, reg, size;
232 int bus, dev, func, err;
238 err = pci_read(bus, dev, func, PCI_BHLC_REG, ®);
242 priv->header_type = PCI_HDRTYPE_TYPE(reg);
243 if (priv->header_type != 0)
246 region = device->regions;
247 for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
248 bar += sizeof(uint32_t), region++) {
249 err = pci_read(bus, dev, func, bar, ®);
253 /* Probe the size of the region. */
254 err = pci_write(bus, dev, func, bar, ~0);
257 pci_read(bus, dev, func, bar, &size);
258 pci_write(bus, dev, func, bar, reg);
260 if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
262 region->base_addr = PCI_MAPREG_IO_ADDR(reg);
263 region->size = PCI_MAPREG_IO_SIZE(size);
265 if (PCI_MAPREG_MEM_PREFETCHABLE(reg))
266 region->is_prefetchable = 1;
267 switch(PCI_MAPREG_MEM_TYPE(reg)) {
268 case PCI_MAPREG_MEM_TYPE_32BIT:
269 case PCI_MAPREG_MEM_TYPE_32BIT_1M:
270 region->base_addr = PCI_MAPREG_MEM_ADDR(reg);
271 region->size = PCI_MAPREG_MEM_SIZE(size);
273 case PCI_MAPREG_MEM_TYPE_64BIT:
279 bar += sizeof(uint32_t);
281 err = pci_read(bus, dev, func, bar, ®);
284 reg64 |= (uint64_t)reg << 32;
286 err = pci_write(bus, dev, func, bar, ~0);
289 pci_read(bus, dev, func, bar, &size);
290 pci_write(bus, dev, func, bar, reg64 >> 32);
291 size64 |= (uint64_t)size << 32;
293 region->base_addr = PCI_MAPREG_MEM64_ADDR(reg64);
294 region->size = PCI_MAPREG_MEM64_SIZE(size64);
304 static const struct pci_system_methods openbsd_pci_methods = {
305 pci_system_openbsd_destroy,
308 pci_device_openbsd_probe,
309 pci_device_openbsd_map_range,
310 pci_device_openbsd_unmap_range,
311 pci_device_openbsd_read,
312 pci_device_openbsd_write,
313 pci_fill_capabilities_generic
317 pci_system_openbsd_create(void)
319 struct pci_device_private *device;
320 int bus, dev, func, ndevs, nfuncs;
326 pcifd = open("/dev/pci", O_RDWR);
330 pci_sys = calloc(1, sizeof(struct pci_system));
331 if (pci_sys == NULL) {
337 pci_sys->methods = &openbsd_pci_methods;
340 for (bus = 0; bus < 256; bus++) {
341 for (dev = 0; dev < 32; dev++) {
342 nfuncs = pci_nfuncs(bus, dev);
343 for (func = 0; func < nfuncs; func++) {
344 if (pci_read(bus, dev, func, PCI_ID_REG,
347 if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
348 PCI_VENDOR(reg) == 0)
356 pci_sys->num_devices = ndevs;
357 pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
358 if (pci_sys->devices == NULL) {
364 device = pci_sys->devices;
365 for (bus = 0; bus < 256; bus++) {
366 for (dev = 0; dev < 32; dev++) {
367 nfuncs = pci_nfuncs(bus, dev);
368 for (func = 0; func < nfuncs; func++) {
369 if (pci_read(bus, dev, func, PCI_ID_REG,
372 if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
373 PCI_VENDOR(reg) == 0)
376 device->base.domain = 0;
377 device->base.bus = bus;
378 device->base.dev = dev;
379 device->base.func = func;
380 device->base.vendor_id = PCI_VENDOR(reg);
381 device->base.device_id = PCI_PRODUCT(reg);
383 if (pci_read(bus, dev, func, PCI_CLASS_REG,
387 device->base.device_class =
388 PCI_INTERFACE(reg) | PCI_CLASS(reg) << 16 |
389 PCI_SUBCLASS(reg) << 8;
390 device->base.revision = PCI_REVISION(reg);
392 if (pci_read(bus, dev, func, PCI_SUBVEND_0,
396 device->base.subvendor_id = PCI_VENDOR(reg);
397 device->base.subdevice_id = PCI_PRODUCT(reg);
408 pci_system_openbsd_init_dev_mem(int fd)