netbsd_pci.c revision 6c7645b9
1/*
2 * Copyright (c) 2008 Juan Romero Pardines
3 * Copyright (c) 2008 Mark Kettenis
4 * Copyright (c) 2009 Michael Lorenz
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/param.h>
20#include <sys/ioctl.h>
21#include <sys/mman.h>
22#include <sys/types.h>
23
24#ifdef HAVE_MTRR
25#include <machine/sysarch.h>
26#include <machine/mtrr.h>
27#define netbsd_set_mtrr(mr, num)	_X86_SYSARCH_L(set_mtrr)(mr, num)
28#endif
29
30#include <dev/pci/pcidevs.h>
31#include <dev/pci/pciio.h>
32#include <dev/pci/pcireg.h>
33
34#include <errno.h>
35#include <fcntl.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40
41
42#include <pci.h>
43
44#include "pciaccess.h"
45#include "pciaccess_private.h"
46
47typedef struct _pcibus {
48	int fd;		/* /dev/pci* */
49	int num;	/* bus number */
50	int maxdevs;	/* maximum number of devices */
51} PciBus;
52
53static PciBus buses[32];	/* indexed by pci_device.domain */
54static int nbuses = 0;		/* number of buses found */
55
56/*
57 * NetBSD's userland has a /dev/pci* entry for each bus but userland has no way
58 * to tell if a bus is a subordinate of another one or if it's on a different
59 * host bridge. On some architectures ( macppc for example ) all root buses have
60 * bus number 0 but on sparc64 for example the two roots in an Ultra60 have
61 * different bus numbers - one is 0 and the other 128.
62 * With each /dev/pci* we can map everything on the same root and we can also
63 * see all devices on the same root, trying to do that causes problems though:
64 * - since we can't tell which /dev/pci* is a subordinate we would find some
65 *   devices more than once
66 * - we would have to guess subordinate bus numbers which is a waste of time
67 *   since we can ask each /dev/pci* for its bus number so we can scan only the
68 *   buses we know exist, not all 256 which may exist in each domain.
69 * - some bus_space_mmap() methods may limit mappings to address ranges which
70 *   belong to known devices on that bus only.
71 * Each host bridge may or may not have its own IO range, to avoid guesswork
72 * here each /dev/pci* will let userland map its appropriate IO range at
73 * PCI_MAGIC_IO_RANGE if defined in <machine/param.h>
74 * With all this we should be able to use any PCI graphics device on any PCI
75 * bus on any architecture as long as Xorg has a driver, without allowing
76 * arbitrary mappings via /dev/mem and without userland having to know or care
77 * about translating bus addresses to physical addresses or the other way
78 * around.
79 */
80
81static int
82pci_read(int domain, int bus, int dev, int func, uint32_t reg, uint32_t *val)
83{
84	uint32_t rval;
85
86	if ((domain < 0) || (domain > nbuses))
87		return -1;
88
89	if (pcibus_conf_read(buses[domain].fd, (unsigned int)bus,
90	    (unsigned int)dev, (unsigned int)func, reg, &rval) == -1)
91		return (-1);
92
93	*val = rval;
94
95	return 0;
96}
97
98static int
99pci_write(int domain, int bus, int dev, int func, uint32_t reg, uint32_t val)
100{
101
102	if ((domain < 0) || (domain > nbuses))
103		return -1;
104
105	return pcibus_conf_write(buses[domain].fd, (unsigned int)bus,
106	    (unsigned int)dev, (unsigned int)func, reg, val);
107}
108
109static int
110pci_nfuncs(int domain, int bus, int dev)
111{
112	uint32_t hdr;
113
114	if ((domain < 0) || (domain > nbuses))
115		return -1;
116
117	if (pci_read(domain, bus, dev, 0, PCI_BHLC_REG, &hdr) != 0)
118		return -1;
119
120	return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1);
121}
122
123/*ARGSUSED*/
124static int
125pci_device_netbsd_map_range(struct pci_device *dev,
126    struct pci_device_mapping *map)
127{
128#ifdef HAVE_MTRR
129	struct mtrr m;
130	int n = 1;
131#endif
132	int prot, ret = 0;
133
134	prot = PROT_READ;
135
136	if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
137		prot |= PROT_WRITE;
138	map->memory = mmap(NULL, map->size, prot, MAP_SHARED,
139	    buses[dev->domain].fd, (off_t)map->base);
140	if (map->memory == MAP_FAILED)
141		return errno;
142
143#ifdef HAVE_MTRR
144	memset(&m, 0, sizeof(m));
145
146	/* No need to set an MTRR if it's the default mode. */
147	if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
148	    (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
149		m.base = base;
150		m.flags = MTRR_VALID | MTRR_PRIVATE;
151		m.len = size;
152		m.owner = getpid();
153		if (map->flags & PCI_DEV_MAP_FLAG_CACHEABLE)
154			m.type = MTRR_TYPE_WB;
155		if (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)
156			m.type = MTRR_TYPE_WC;
157
158		if ((netbsd_set_mtrr(&m, &n)) == -1)
159			ret = errno;
160	}
161#endif
162
163	return ret;
164}
165
166static int
167pci_device_netbsd_unmap_range(struct pci_device *dev,
168    struct pci_device_mapping *map)
169{
170#ifdef HAVE_MTRR
171	struct mtrr m;
172	int n = 1;
173
174	memset(&m, 0, sizeof(m));
175
176	if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
177	    (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
178		m.base = map->base;
179		m.flags = 0;
180		m.len = size;
181		m.type = MTRR_TYPE_UC;
182		(void)netbsd_set_mtrr(&m, &n);
183	}
184#endif
185
186	return pci_device_generic_unmap_range(dev, map);
187}
188
189static int
190pci_device_netbsd_read(struct pci_device *dev, void *data,
191    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
192{
193	u_int reg, rval;
194
195	*bytes_read = 0;
196	while (size > 0) {
197		size_t toread = MIN(size, 4 - (offset & 0x3));
198
199		reg = (u_int)(offset & ~0x3);
200
201		if ((pcibus_conf_read(buses[dev->domain].fd,
202		    (unsigned int)dev->bus, (unsigned int)dev->dev,
203		    (unsigned int)dev->func, reg, &rval)) == -1)
204			return errno;
205
206		rval = htole32(rval);
207		rval >>= ((offset & 0x3) * 8);
208
209		memcpy(data, &rval, toread);
210
211		offset += toread;
212		data = (char *)data + toread;
213		size -= toread;
214		*bytes_read += toread;
215	}
216
217	return 0;
218}
219
220static int
221pci_device_netbsd_write(struct pci_device *dev, const void *data,
222    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
223{
224	u_int reg, val;
225
226	if ((offset % 4) != 0 || (size % 4) != 0)
227		return EINVAL;
228
229	*bytes_written = 0;
230	while (size > 0) {
231		reg = (u_int)offset;
232		memcpy(&val, data, 4);
233
234		if ((pcibus_conf_write(buses[dev->domain].fd,
235		    (unsigned int)dev->bus, (unsigned int)dev->dev,
236		    (unsigned int)dev->func, reg, val)) == -1)
237			return errno;
238
239		offset += 4;
240		data = (const char *)data + 4;
241		size -= 4;
242		*bytes_written += 4;
243	}
244
245	return 0;
246}
247
248static void
249pci_system_netbsd_destroy(void)
250{
251	int i;
252
253	for (i = 0; i < nbuses; i++) {
254		close(buses[i].fd);
255	}
256	free(pci_sys);
257	pci_sys = NULL;
258}
259
260static int
261pci_device_netbsd_probe(struct pci_device *device)
262{
263	struct pci_device_private *priv =
264	    (struct pci_device_private *)(void *)device;
265	struct pci_mem_region *region;
266	uint64_t reg64, size64;
267	uint32_t bar, reg, size;
268	int bus, dev, func, err, domain;
269
270	domain = device->domain;
271	bus = device->bus;
272	dev = device->dev;
273	func = device->func;
274
275	/* Enable the device if necessary */
276	err = pci_read(domain, bus, dev, func, PCI_COMMAND_STATUS_REG, &reg);
277	if (err)
278		return err;
279	if ((reg & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE)) !=
280	    (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE)) {
281		reg |= PCI_COMMAND_IO_ENABLE |
282		       PCI_COMMAND_MEM_ENABLE |
283		       PCI_COMMAND_MASTER_ENABLE;
284		err = pci_write(domain, bus, dev, func, PCI_COMMAND_STATUS_REG,
285				reg);
286		if (err)
287			return err;
288	}
289
290	err = pci_read(domain, bus, dev, func, PCI_BHLC_REG, &reg);
291	if (err)
292		return err;
293
294	priv->header_type = PCI_HDRTYPE_TYPE(reg);
295	if (priv->header_type != 0)
296		return 0;
297
298	region = device->regions;
299	for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
300	     bar += sizeof(uint32_t), region++) {
301		err = pci_read(domain, bus, dev, func, bar, &reg);
302		if (err)
303			return err;
304
305		/* Probe the size of the region. */
306		err = pci_write(domain, bus, dev, func, bar, (unsigned int)~0);
307		if (err)
308			return err;
309		pci_read(domain, bus, dev, func, bar, &size);
310		pci_write(domain, bus, dev, func, bar, reg);
311
312		if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
313			region->is_IO = 1;
314			region->base_addr = PCI_MAPREG_IO_ADDR(reg);
315			region->size = PCI_MAPREG_IO_SIZE(size);
316		} else {
317			if (PCI_MAPREG_MEM_PREFETCHABLE(reg))
318				region->is_prefetchable = 1;
319			switch(PCI_MAPREG_MEM_TYPE(reg)) {
320			case PCI_MAPREG_MEM_TYPE_32BIT:
321			case PCI_MAPREG_MEM_TYPE_32BIT_1M:
322				region->base_addr = PCI_MAPREG_MEM_ADDR(reg);
323				region->size = PCI_MAPREG_MEM_SIZE(size);
324				break;
325			case PCI_MAPREG_MEM_TYPE_64BIT:
326				region->is_64 = 1;
327
328				reg64 = reg;
329				size64 = size;
330
331				bar += sizeof(uint32_t);
332
333				err = pci_read(domain, bus, dev, func, bar, &reg);
334				if (err)
335					return err;
336				reg64 |= (uint64_t)reg << 32;
337
338				err = pci_write(domain, bus, dev, func, bar,
339				    (unsigned int)~0);
340				if (err)
341					return err;
342				pci_read(domain, bus, dev, func, bar, &size);
343				pci_write(domain, bus, dev, func, bar,
344				    (unsigned int)(reg64 >> 32));
345				size64 |= (uint64_t)size << 32;
346
347				region->base_addr =
348				    (unsigned long)PCI_MAPREG_MEM64_ADDR(reg64);
349				region->size =
350				    (unsigned long)PCI_MAPREG_MEM64_SIZE(size64);
351				region++;
352				break;
353			}
354		}
355	}
356
357	return 0;
358}
359
360/**
361 * Read a VGA rom using the 0xc0000 mapping.
362 *
363 * This function should be extended to handle access through PCI resources,
364 * which should be more reliable when available.
365 */
366static int
367pci_device_netbsd_read_rom(struct pci_device *dev, void *buffer)
368{
369    struct pci_device_private *priv = (struct pci_device_private *)(void *)dev;
370    void *bios;
371    pciaddr_t rom_base;
372    size_t rom_size;
373    uint32_t bios_val, command_val;
374    int pci_rom, memfd;
375
376    if (((priv->base.device_class >> 16) & 0xff) != PCI_CLASS_DISPLAY ||
377	((priv->base.device_class >> 8) & 0xff) != PCI_SUBCLASS_DISPLAY_VGA)
378	return ENOSYS;
379
380    if (priv->rom_base == 0) {
381#if defined(__amd64__) || defined(__i386__)
382	rom_base = 0xc0000;
383	rom_size = 0x10000;
384	pci_rom = 0;
385#else
386	return ENOSYS;
387#endif
388    } else {
389	rom_base = priv->rom_base;
390	rom_size = dev->rom_size;
391	pci_rom = 1;
392	if ((pcibus_conf_read(buses[dev->domain].fd, (unsigned int)dev->bus,
393	    (unsigned int)dev->dev, (unsigned int)dev->func,
394	    PCI_COMMAND_STATUS_REG, &command_val)) == -1)
395	    return errno;
396	if ((command_val & PCI_COMMAND_MEM_ENABLE) == 0) {
397	    if ((pcibus_conf_write(buses[dev->domain].fd,
398	        (unsigned int)dev->bus, (unsigned int)dev->dev,
399		(unsigned int)dev->func, PCI_COMMAND_STATUS_REG,
400		command_val | PCI_COMMAND_MEM_ENABLE)) == -1)
401		return errno;
402	}
403	if ((pcibus_conf_read(buses[dev->domain].fd, (unsigned int)dev->bus,
404	    (unsigned int)dev->dev, (unsigned int)dev->func,
405	    PCI_MAPREG_ROM, &bios_val)) == -1)
406	    return errno;
407	if ((bios_val & PCI_MAPREG_ROM_ENABLE) == 0) {
408	    if ((pcibus_conf_write(buses[dev->domain].fd,
409	        (unsigned int)dev->bus,
410		(unsigned int)dev->dev, (unsigned int)dev->func,
411		PCI_MAPREG_ROM, bios_val | PCI_MAPREG_ROM_ENABLE)) == -1)
412		return errno;
413	}
414    }
415
416    fprintf(stderr, "Using rom_base = 0x%lx (pci_rom=%d)\n", (long)rom_base,
417	pci_rom);
418    memfd = open("/dev/mem", O_RDONLY);
419    if (memfd == -1)
420	return errno;
421
422    bios = mmap(NULL, rom_size, PROT_READ, 0, memfd, (off_t)rom_base);
423    if (bios == MAP_FAILED) {
424	int serrno = errno;
425	close(memfd);
426	return serrno;
427    }
428
429    memcpy(buffer, bios, rom_size);
430
431    munmap(bios, rom_size);
432    close(memfd);
433
434    if (pci_rom) {
435	if ((command_val & PCI_COMMAND_MEM_ENABLE) == 0) {
436	    if ((pcibus_conf_write(buses[dev->domain].fd,
437	        (unsigned int)dev->bus,
438		(unsigned int)dev->dev, (unsigned int)dev->func,
439		PCI_COMMAND_STATUS_REG, command_val)) == -1)
440		return errno;
441	}
442	if ((bios_val & PCI_MAPREG_ROM_ENABLE) == 0) {
443	    if ((pcibus_conf_write(buses[dev->domain].fd,
444	        (unsigned int)dev->bus,
445		(unsigned int)dev->dev, (unsigned int)dev->func,
446		PCI_MAPREG_ROM, bios_val)) == -1)
447		return errno;
448	}
449    }
450
451    return 0;
452}
453
454static const struct pci_system_methods netbsd_pci_methods = {
455	.destroy = pci_system_netbsd_destroy,
456	.destroy_device = NULL,
457	.read_rom = pci_device_netbsd_read_rom,
458	.probe = pci_device_netbsd_probe,
459	.map_range = pci_device_netbsd_map_range,
460	.unmap_range = pci_device_netbsd_unmap_range,
461	.read = pci_device_netbsd_read,
462	.write = pci_device_netbsd_write,
463	.fill_capabilities = pci_fill_capabilities_generic
464};
465
466int
467pci_system_netbsd_create(void)
468{
469	struct pci_device_private *device;
470	int bus, dev, func, ndevs, nfuncs, domain, pcifd;
471	uint32_t reg;
472	char netbsd_devname[32];
473	struct pciio_businfo businfo;
474
475	pci_sys = calloc(1, sizeof(struct pci_system));
476
477	pci_sys->methods = &netbsd_pci_methods;
478
479	ndevs = 0;
480	nbuses = 0;
481	snprintf(netbsd_devname, 32, "/dev/pci%d", nbuses);
482	pcifd = open(netbsd_devname, O_RDWR);
483	while (pcifd > 0) {
484		ioctl(pcifd, PCI_IOC_BUSINFO, &businfo);
485		buses[nbuses].fd = pcifd;
486		buses[nbuses].num = bus = businfo.busno;
487		buses[nbuses].maxdevs = businfo.maxdevs;
488		domain = nbuses;
489		nbuses++;
490		for (dev = 0; dev < businfo.maxdevs; dev++) {
491			nfuncs = pci_nfuncs(domain, bus, dev);
492			for (func = 0; func < nfuncs; func++) {
493				if (pci_read(domain, bus, dev, func, PCI_ID_REG,
494				    &reg) != 0)
495					continue;
496				if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
497				    PCI_VENDOR(reg) == 0)
498					continue;
499
500				ndevs++;
501			}
502		}
503		snprintf(netbsd_devname, 32, "/dev/pci%d", nbuses);
504		pcifd = open(netbsd_devname, O_RDWR);
505	}
506
507	pci_sys->num_devices = ndevs;
508	pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
509	if (pci_sys->devices == NULL) {
510		int i;
511
512		for (i = 0; i < nbuses; i++)
513			close(buses[i].fd);
514		free(pci_sys);
515		return ENOMEM;
516	}
517
518	device = pci_sys->devices;
519	for (domain = 0; domain < nbuses; domain++) {
520		bus = buses[domain].num;
521		for (dev = 0; dev < buses[domain].maxdevs; dev++) {
522			nfuncs = pci_nfuncs(domain, bus, dev);
523			for (func = 0; func < nfuncs; func++) {
524				if (pci_read(domain, bus, dev, func,
525				    PCI_ID_REG, &reg) != 0)
526					continue;
527				if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
528				    PCI_VENDOR(reg) == 0)
529					continue;
530
531				device->base.domain = domain;
532				device->base.bus = bus;
533				device->base.dev = dev;
534				device->base.func = func;
535				device->base.vendor_id = PCI_VENDOR(reg);
536				device->base.device_id = PCI_PRODUCT(reg);
537
538				if (pci_read(domain, bus, dev, func,
539				    PCI_CLASS_REG, &reg) != 0)
540					continue;
541
542				device->base.device_class =
543				    PCI_INTERFACE(reg) | PCI_CLASS(reg) << 16 |
544				    PCI_SUBCLASS(reg) << 8;
545				device->base.revision = PCI_REVISION(reg);
546
547				if (pci_read(domain, bus, dev, func,
548				    PCI_SUBSYS_ID_REG, &reg) != 0)
549					continue;
550
551				device->base.subvendor_id = PCI_VENDOR(reg);
552				device->base.subdevice_id = PCI_PRODUCT(reg);
553
554				device++;
555			}
556		}
557	}
558
559	return 0;
560}
561