netbsd_pci.c revision 4f5e7dd7
1/*
2 * Copyright (c) 2008 Juan Romero Pardines
3 * Copyright (c) 2008 Mark Kettenis
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <sys/param.h>
19#include <sys/ioctl.h>
20#include <sys/mman.h>
21#include <sys/types.h>
22
23#include <machine/sysarch.h>
24#include <machine/mtrr.h>
25
26#include <dev/pci/pciio.h>
27#include <dev/pci/pcireg.h>
28#include <dev/pci/pcidevs.h>
29
30#include <errno.h>
31#include <fcntl.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36
37
38#include "pciaccess.h"
39#include "pciaccess_private.h"
40
41static int pcifd;
42
43static int
44pci_read(int bus, int dev, int func, uint32_t reg, uint32_t *val)
45{
46	struct pciio_bdf_cfgreg io;
47	int err;
48
49	bzero(&io, sizeof(io));
50	io.bus = bus;
51	io.device = dev;
52	io.function = func;
53	io.cfgreg.reg = reg;
54
55	err = ioctl(pcifd, PCI_IOC_BDF_CFGREAD, &io);
56	if (err)
57		return (err);
58
59	*val = io.cfgreg.val;
60
61	return 0;
62}
63
64static int
65pci_write(int bus, int dev, int func, uint32_t reg, uint32_t val)
66{
67	struct pciio_bdf_cfgreg io;
68
69	bzero(&io, sizeof(io));
70	io.bus = bus;
71	io.device = dev;
72	io.function = func;
73	io.cfgreg.reg = reg;
74	io.cfgreg.val = val;
75
76	return ioctl(pcifd, PCI_IOC_BDF_CFGWRITE, &io);
77}
78
79static int
80pci_nfuncs(int bus, int dev)
81{
82	uint32_t hdr;
83
84	if (pci_read(bus, dev, 0, PCI_BHLC_REG, &hdr) != 0)
85		return -1;
86
87	return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1);
88}
89
90static int
91pci_device_netbsd_map_range(struct pci_device *dev,
92    struct pci_device_mapping *map)
93{
94	struct mtrr mtrr;
95	int fd, error, nmtrr, prot = PROT_READ;
96
97	if ((fd = open("/dev/mem", O_RDWR)) == -1)
98		return errno;
99
100	if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
101		prot |= PROT_WRITE;
102
103	map->memory = mmap(NULL, map->size, prot, MAP_SHARED,
104	    fd, map->base);
105	if (map->memory == MAP_FAILED)
106		return errno;
107
108	/* No need to set an MTRR if it's the default mode. */
109	if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
110	    (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
111		mtrr.base = map->base;
112		mtrr.len = map->size;
113		mtrr.flags = MTRR_VALID;
114
115		if (map->flags & PCI_DEV_MAP_FLAG_CACHABLE)
116			mtrr.type = MTRR_TYPE_WB;
117		if (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)
118			mtrr.type = MTRR_TYPE_WC;
119#ifdef __i386__
120		error = i386_set_mtrr(&mtrr, &nmtrr);
121#endif
122#ifdef __amd64__
123		error = x86_64_set_mtrr(&mtrr, &nmtrr);
124#endif
125		if (error) {
126			close(fd);
127			return errno;
128		}
129	}
130
131	close(fd);
132
133	return 0;
134}
135
136static int
137pci_device_netbsd_unmap_range(struct pci_device *dev,
138    struct pci_device_mapping *map)
139{
140	struct mtrr mtrr;
141	int nmtrr, error;
142
143	if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
144	    (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
145		mtrr.base = map->base;
146		mtrr.len = map->size;
147		mtrr.type = MTRR_TYPE_UC;
148		mtrr.flags = 0; /* clear/set MTRR */
149#ifdef __i386__
150		error = i386_set_mtrr(&mtrr, &nmtrr);
151#endif
152#ifdef __amd64__
153		error = x86_64_set_mtrr(&mtrr, &nmtrr);
154#endif
155		if (error)
156			return errno;
157	}
158
159	return pci_device_generic_unmap_range(dev, map);
160}
161
162static int
163pci_device_netbsd_read(struct pci_device *dev, void *data,
164    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
165{
166	struct pciio_bdf_cfgreg io;
167
168	io.bus = dev->bus;
169	io.device = dev->dev;
170	io.function = dev->func;
171
172	*bytes_read = 0;
173	while (size > 0) {
174		int toread = MIN(size, 4 - (offset & 0x3));
175
176		io.cfgreg.reg = (offset & ~0x3);
177
178		if (ioctl(pcifd, PCI_IOC_BDF_CFGREAD, &io) == -1)
179			return errno;
180
181		io.cfgreg.val = htole32(io.cfgreg.val);
182		io.cfgreg.val >>= ((offset & 0x3) * 8);
183
184		memcpy(data, &io.cfgreg.val, toread);
185
186		offset += toread;
187		data = (char *)data + toread;
188		size -= toread;
189		*bytes_read += toread;
190	}
191
192	return 0;
193}
194
195static int
196pci_device_netbsd_write(struct pci_device *dev, const void *data,
197    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
198{
199	struct pciio_bdf_cfgreg io;
200
201	if ((offset % 4) != 0 || (size % 4) != 0)
202		return EINVAL;
203
204	io.bus = dev->bus;
205	io.device = dev->dev;
206	io.function = dev->func;
207
208	*bytes_written = 0;
209	while (size > 0) {
210		io.cfgreg.reg = offset;
211		memcpy(&io.cfgreg.val, data, 4);
212
213		if (ioctl(pcifd, PCI_IOC_BDF_CFGWRITE, &io) == -1)
214			return errno;
215
216		offset += 4;
217		data = (char *)data + 4;
218		size -= 4;
219		*bytes_written += 4;
220	}
221
222	return 0;
223}
224
225static void
226pci_system_netbsd_destroy(void)
227{
228	close(pcifd);
229	free(pci_sys);
230	pci_sys = NULL;
231}
232
233static int
234pci_device_netbsd_probe(struct pci_device *device)
235{
236	struct pci_device_private *priv = (struct pci_device_private *)device;
237	struct pci_mem_region *region;
238	uint64_t reg64, size64;
239	uint32_t bar, reg, size;
240	int bus, dev, func, err;
241
242	bus = device->bus;
243	dev = device->dev;
244	func = device->func;
245
246	err = pci_read(bus, dev, func, PCI_BHLC_REG, &reg);
247	if (err)
248		return err;
249
250	priv->header_type = PCI_HDRTYPE_TYPE(reg);
251	if (priv->header_type != 0)
252		return 0;
253
254	region = device->regions;
255	for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
256	     bar += sizeof(uint32_t), region++) {
257		err = pci_read(bus, dev, func, bar, &reg);
258		if (err)
259			return err;
260
261		/* Probe the size of the region. */
262		err = pci_write(bus, dev, func, bar, ~0);
263		if (err)
264			return err;
265		pci_read(bus, dev, func, bar, &size);
266		pci_write(bus, dev, func, bar, reg);
267
268		if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
269			region->is_IO = 1;
270			region->base_addr = PCI_MAPREG_IO_ADDR(reg);
271			region->size = PCI_MAPREG_IO_SIZE(size);
272		} else {
273			if (PCI_MAPREG_MEM_PREFETCHABLE(reg))
274				region->is_prefetchable = 1;
275			switch(PCI_MAPREG_MEM_TYPE(reg)) {
276			case PCI_MAPREG_MEM_TYPE_32BIT:
277			case PCI_MAPREG_MEM_TYPE_32BIT_1M:
278				region->base_addr = PCI_MAPREG_MEM_ADDR(reg);
279				region->size = PCI_MAPREG_MEM_SIZE(size);
280				break;
281			case PCI_MAPREG_MEM_TYPE_64BIT:
282				region->is_64 = 1;
283
284				reg64 = reg;
285				size64 = size;
286
287				bar += sizeof(uint32_t);
288
289				err = pci_read(bus, dev, func, bar, &reg);
290				if (err)
291					return err;
292				reg64 |= (uint64_t)reg << 32;
293
294				err = pci_write(bus, dev, func, bar, ~0);
295				if (err)
296					return err;
297				pci_read(bus, dev, func, bar, &size);
298				pci_write(bus, dev, func, bar, reg64 >> 32);
299				size64 |= (uint64_t)size << 32;
300
301				region->base_addr = PCI_MAPREG_MEM64_ADDR(reg64);
302				region->size = PCI_MAPREG_MEM64_SIZE(size64);
303				region++;
304				break;
305			}
306		}
307	}
308
309	return 0;
310}
311
312static const struct pci_system_methods netbsd_pci_methods = {
313	pci_system_netbsd_destroy,
314	NULL,
315	NULL,
316	pci_device_netbsd_probe,
317	pci_device_netbsd_map_range,
318	pci_device_netbsd_unmap_range,
319	pci_device_netbsd_read,
320	pci_device_netbsd_write,
321	pci_fill_capabilities_generic
322};
323
324int
325pci_system_netbsd_create(void)
326{
327	struct pci_device_private *device;
328	int bus, dev, func, ndevs, nfuncs;
329	uint32_t reg;
330
331	pcifd = open("/dev/pci0", O_RDWR);
332	if (pcifd == -1)
333		return ENXIO;
334
335	pci_sys = calloc(1, sizeof(struct pci_system));
336	if (pci_sys == NULL) {
337		close(pcifd);
338		return ENOMEM;
339	}
340
341	pci_sys->methods = &netbsd_pci_methods;
342
343	ndevs = 0;
344	for (bus = 0; bus < 256; bus++) {
345		for (dev = 0; dev < 32; dev++) {
346			nfuncs = pci_nfuncs(bus, dev);
347			for (func = 0; func < nfuncs; func++) {
348				if (pci_read(bus, dev, func, PCI_ID_REG,
349				    &reg) != 0)
350					continue;
351				if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
352				    PCI_VENDOR(reg) == 0)
353					continue;
354
355				ndevs++;
356			}
357		}
358	}
359
360	pci_sys->num_devices = ndevs;
361	pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
362	if (pci_sys->devices == NULL) {
363		free(pci_sys);
364		close(pcifd);
365		return ENOMEM;
366	}
367
368	device = pci_sys->devices;
369	for (bus = 0; bus < 256; bus++) {
370		for (dev = 0; dev < 32; dev++) {
371			nfuncs = pci_nfuncs(bus, dev);
372			for (func = 0; func < nfuncs; func++) {
373				if (pci_read(bus, dev, func, PCI_ID_REG,
374				    &reg) != 0)
375					continue;
376				if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
377				    PCI_VENDOR(reg) == 0)
378					continue;
379
380				device->base.domain = 0;
381				device->base.bus = bus;
382				device->base.dev = dev;
383				device->base.func = func;
384				device->base.vendor_id = PCI_VENDOR(reg);
385				device->base.device_id = PCI_PRODUCT(reg);
386
387				if (pci_read(bus, dev, func, PCI_CLASS_REG,
388				    &reg) != 0)
389					continue;
390
391				device->base.device_class =
392				    PCI_INTERFACE(reg) | PCI_CLASS(reg) << 16 |
393				    PCI_SUBCLASS(reg) << 8;
394				device->base.revision = PCI_REVISION(reg);
395
396				if (pci_read(bus, dev, func, PCI_SUBSYS_ID_REG,
397				    &reg) != 0)
398					continue;
399
400				device->base.subvendor_id = PCI_VENDOR(reg);
401				device->base.subdevice_id = PCI_PRODUCT(reg);
402
403				device++;
404			}
405		}
406	}
407
408	return 0;
409}
410