netbsd_pci.c revision 74c741d0
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	/* Probe expansion ROM if present */
358	err = pci_read(domain, bus, dev, func, PCI_MAPREG_ROM, &reg);
359	if (err)
360		return err;
361	if (reg != 0) {
362		err = pci_write(domain, bus, dev, func, PCI_MAPREG_ROM,
363		    (uint32_t)(~PCI_MAPREG_ROM_ENABLE));
364		if (err)
365			return err;
366		pci_read(domain, bus, dev, func, PCI_MAPREG_ROM, &size);
367		pci_write(domain, bus, dev, func, PCI_MAPREG_ROM, reg);
368		if ((reg & PCI_MAPREG_MEM_ADDR_MASK) != 0) {
369			priv->rom_base = reg & PCI_MAPREG_MEM_ADDR_MASK;
370			device->rom_size = -(size & PCI_MAPREG_MEM_ADDR_MASK);
371		}
372	}
373
374	return 0;
375}
376
377/**
378 * Read a VGA rom using the 0xc0000 mapping.
379 *
380 * This function should be extended to handle access through PCI resources,
381 * which should be more reliable when available.
382 */
383static int
384pci_device_netbsd_read_rom(struct pci_device *dev, void *buffer)
385{
386    struct pci_device_private *priv = (struct pci_device_private *)(void *)dev;
387    void *bios;
388    pciaddr_t rom_base;
389    size_t rom_size;
390    uint32_t bios_val, command_val;
391    int pci_rom;
392
393    if (((priv->base.device_class >> 16) & 0xff) != PCI_CLASS_DISPLAY ||
394	((priv->base.device_class >> 8) & 0xff) != PCI_SUBCLASS_DISPLAY_VGA)
395	return ENOSYS;
396
397    if (priv->rom_base == 0) {
398#if defined(__amd64__) || defined(__i386__)
399	/*
400	 * We need a way to detect when this isn't the console and reject
401	 * this request outright.
402	 */
403	rom_base = 0xc0000;
404	rom_size = 0x10000;
405	pci_rom = 0;
406#else
407	return ENOSYS;
408#endif
409    } else {
410	rom_base = priv->rom_base;
411	rom_size = dev->rom_size;
412	pci_rom = 1;
413	if ((pcibus_conf_read(buses[dev->domain].fd, (unsigned int)dev->bus,
414	    (unsigned int)dev->dev, (unsigned int)dev->func,
415	    PCI_COMMAND_STATUS_REG, &command_val)) == -1)
416	    return errno;
417	if ((command_val & PCI_COMMAND_MEM_ENABLE) == 0) {
418	    if ((pcibus_conf_write(buses[dev->domain].fd,
419	        (unsigned int)dev->bus, (unsigned int)dev->dev,
420		(unsigned int)dev->func, PCI_COMMAND_STATUS_REG,
421		command_val | PCI_COMMAND_MEM_ENABLE)) == -1)
422		return errno;
423	}
424	if ((pcibus_conf_read(buses[dev->domain].fd, (unsigned int)dev->bus,
425	    (unsigned int)dev->dev, (unsigned int)dev->func,
426	    PCI_MAPREG_ROM, &bios_val)) == -1)
427	    return errno;
428	if ((bios_val & PCI_MAPREG_ROM_ENABLE) == 0) {
429	    if ((pcibus_conf_write(buses[dev->domain].fd,
430	        (unsigned int)dev->bus,
431		(unsigned int)dev->dev, (unsigned int)dev->func,
432		PCI_MAPREG_ROM, bios_val | PCI_MAPREG_ROM_ENABLE)) == -1)
433		return errno;
434	}
435    }
436
437    fprintf(stderr, "Using rom_base = 0x%lx 0x%lx (pci_rom=%d)\n",
438        (long)rom_base, (long)rom_size, pci_rom);
439
440    bios = mmap(NULL, rom_size, PROT_READ, MAP_SHARED, buses[dev->domain].fd,
441        (off_t)rom_base);
442    if (bios == MAP_FAILED) {
443	int serrno = errno;
444	return serrno;
445    }
446
447    memcpy(buffer, bios, rom_size);
448
449    munmap(bios, rom_size);
450
451    if (pci_rom) {
452	if ((command_val & PCI_COMMAND_MEM_ENABLE) == 0) {
453	    if ((pcibus_conf_write(buses[dev->domain].fd,
454	        (unsigned int)dev->bus,
455		(unsigned int)dev->dev, (unsigned int)dev->func,
456		PCI_COMMAND_STATUS_REG, command_val)) == -1)
457		return errno;
458	}
459	if ((bios_val & PCI_MAPREG_ROM_ENABLE) == 0) {
460	    if ((pcibus_conf_write(buses[dev->domain].fd,
461	        (unsigned int)dev->bus,
462		(unsigned int)dev->dev, (unsigned int)dev->func,
463		PCI_MAPREG_ROM, bios_val)) == -1)
464		return errno;
465	}
466    }
467
468    return 0;
469}
470
471static const struct pci_system_methods netbsd_pci_methods = {
472	.destroy = pci_system_netbsd_destroy,
473	.destroy_device = NULL,
474	.read_rom = pci_device_netbsd_read_rom,
475	.probe = pci_device_netbsd_probe,
476	.map_range = pci_device_netbsd_map_range,
477	.unmap_range = pci_device_netbsd_unmap_range,
478	.read = pci_device_netbsd_read,
479	.write = pci_device_netbsd_write,
480	.fill_capabilities = pci_fill_capabilities_generic
481};
482
483int
484pci_system_netbsd_create(void)
485{
486	struct pci_device_private *device;
487	int bus, dev, func, ndevs, nfuncs, domain, pcifd;
488	uint32_t reg;
489	char netbsd_devname[32];
490	struct pciio_businfo businfo;
491
492	pci_sys = calloc(1, sizeof(struct pci_system));
493
494	pci_sys->methods = &netbsd_pci_methods;
495
496	ndevs = 0;
497	nbuses = 0;
498	snprintf(netbsd_devname, 32, "/dev/pci%d", nbuses);
499	pcifd = open(netbsd_devname, O_RDWR);
500	while (pcifd > 0) {
501		ioctl(pcifd, PCI_IOC_BUSINFO, &businfo);
502		buses[nbuses].fd = pcifd;
503		buses[nbuses].num = bus = businfo.busno;
504		buses[nbuses].maxdevs = businfo.maxdevs;
505		domain = nbuses;
506		nbuses++;
507		for (dev = 0; dev < businfo.maxdevs; dev++) {
508			nfuncs = pci_nfuncs(domain, bus, dev);
509			for (func = 0; func < nfuncs; func++) {
510				if (pci_read(domain, bus, dev, func, PCI_ID_REG,
511				    &reg) != 0)
512					continue;
513				if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
514				    PCI_VENDOR(reg) == 0)
515					continue;
516
517				ndevs++;
518			}
519		}
520		snprintf(netbsd_devname, 32, "/dev/pci%d", nbuses);
521		pcifd = open(netbsd_devname, O_RDWR);
522	}
523
524	pci_sys->num_devices = ndevs;
525	pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
526	if (pci_sys->devices == NULL) {
527		int i;
528
529		for (i = 0; i < nbuses; i++)
530			close(buses[i].fd);
531		free(pci_sys);
532		return ENOMEM;
533	}
534
535	device = pci_sys->devices;
536	for (domain = 0; domain < nbuses; domain++) {
537		bus = buses[domain].num;
538		for (dev = 0; dev < buses[domain].maxdevs; dev++) {
539			nfuncs = pci_nfuncs(domain, bus, dev);
540			for (func = 0; func < nfuncs; func++) {
541				if (pci_read(domain, bus, dev, func,
542				    PCI_ID_REG, &reg) != 0)
543					continue;
544				if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
545				    PCI_VENDOR(reg) == 0)
546					continue;
547
548				device->base.domain = domain;
549				device->base.bus = bus;
550				device->base.dev = dev;
551				device->base.func = func;
552				device->base.vendor_id = PCI_VENDOR(reg);
553				device->base.device_id = PCI_PRODUCT(reg);
554
555				if (pci_read(domain, bus, dev, func,
556				    PCI_CLASS_REG, &reg) != 0)
557					continue;
558
559				device->base.device_class =
560				    PCI_INTERFACE(reg) | PCI_CLASS(reg) << 16 |
561				    PCI_SUBCLASS(reg) << 8;
562				device->base.revision = PCI_REVISION(reg);
563
564				if (pci_read(domain, bus, dev, func,
565				    PCI_SUBSYS_ID_REG, &reg) != 0)
566					continue;
567
568				device->base.subvendor_id = PCI_VENDOR(reg);
569				device->base.subdevice_id = PCI_PRODUCT(reg);
570
571				device++;
572			}
573		}
574	}
575
576	return 0;
577}
578