xref: /freebsd/sys/dev/pci/pci_subr.c (revision 34ff71eecd9320d511d491ea54a86f0725a409f3)
10dbe859dSJohn Baldwin /*-
20dbe859dSJohn Baldwin  * Copyright (c) 2011 Advanced Computing Technologies LLC
30dbe859dSJohn Baldwin  * Written by: John H. Baldwin <jhb@FreeBSD.org>
40dbe859dSJohn Baldwin  * All rights reserved.
50dbe859dSJohn Baldwin  *
60dbe859dSJohn Baldwin  * Redistribution and use in source and binary forms, with or without
70dbe859dSJohn Baldwin  * modification, are permitted provided that the following conditions
80dbe859dSJohn Baldwin  * are met:
90dbe859dSJohn Baldwin  * 1. Redistributions of source code must retain the above copyright
100dbe859dSJohn Baldwin  *    notice, this list of conditions and the following disclaimer.
110dbe859dSJohn Baldwin  * 2. Redistributions in binary form must reproduce the above copyright
120dbe859dSJohn Baldwin  *    notice, this list of conditions and the following disclaimer in the
130dbe859dSJohn Baldwin  *    documentation and/or other materials provided with the distribution.
140dbe859dSJohn Baldwin  *
150dbe859dSJohn Baldwin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
160dbe859dSJohn Baldwin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
170dbe859dSJohn Baldwin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
180dbe859dSJohn Baldwin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
190dbe859dSJohn Baldwin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
200dbe859dSJohn Baldwin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
210dbe859dSJohn Baldwin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
220dbe859dSJohn Baldwin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
230dbe859dSJohn Baldwin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
240dbe859dSJohn Baldwin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
250dbe859dSJohn Baldwin  * SUCH DAMAGE.
260dbe859dSJohn Baldwin  */
270dbe859dSJohn Baldwin 
280dbe859dSJohn Baldwin #include <sys/cdefs.h>
290dbe859dSJohn Baldwin __FBSDID("$FreeBSD$");
300dbe859dSJohn Baldwin 
310dbe859dSJohn Baldwin /*
320dbe859dSJohn Baldwin  * Support APIs for Host to PCI bridge drivers and drivers that
330dbe859dSJohn Baldwin  * provide PCI domains.
340dbe859dSJohn Baldwin  */
350dbe859dSJohn Baldwin 
36*34ff71eeSJohn Baldwin #include <sys/param.h>
370dbe859dSJohn Baldwin #include <sys/bus.h>
380dbe859dSJohn Baldwin #include <sys/rman.h>
39*34ff71eeSJohn Baldwin #include <sys/systm.h>
400dbe859dSJohn Baldwin 
410dbe859dSJohn Baldwin #include <dev/pci/pcireg.h>
420dbe859dSJohn Baldwin #include <dev/pci/pcivar.h>
430dbe859dSJohn Baldwin #include <dev/pci/pcib_private.h>
440dbe859dSJohn Baldwin 
450dbe859dSJohn Baldwin /*
460dbe859dSJohn Baldwin  * Try to read the bus number of a host-PCI bridge using appropriate config
470dbe859dSJohn Baldwin  * registers.
480dbe859dSJohn Baldwin  */
490dbe859dSJohn Baldwin int
500dbe859dSJohn Baldwin host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func,
510dbe859dSJohn Baldwin     uint8_t *busnum)
520dbe859dSJohn Baldwin {
530dbe859dSJohn Baldwin 	uint32_t id;
540dbe859dSJohn Baldwin 
550dbe859dSJohn Baldwin 	id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4);
560dbe859dSJohn Baldwin 	if (id == 0xffffffff)
570dbe859dSJohn Baldwin 		return (0);
580dbe859dSJohn Baldwin 
590dbe859dSJohn Baldwin 	switch (id) {
600dbe859dSJohn Baldwin 	case 0x12258086:
610dbe859dSJohn Baldwin 		/* Intel 824?? */
620dbe859dSJohn Baldwin 		/* XXX This is a guess */
630dbe859dSJohn Baldwin 		/* *busnum = read_config(bus, slot, func, 0x41, 1); */
640dbe859dSJohn Baldwin 		*busnum = bus;
650dbe859dSJohn Baldwin 		break;
660dbe859dSJohn Baldwin 	case 0x84c48086:
670dbe859dSJohn Baldwin 		/* Intel 82454KX/GX (Orion) */
680dbe859dSJohn Baldwin 		*busnum = read_config(bus, slot, func, 0x4a, 1);
690dbe859dSJohn Baldwin 		break;
700dbe859dSJohn Baldwin 	case 0x84ca8086:
710dbe859dSJohn Baldwin 		/*
720dbe859dSJohn Baldwin 		 * For the 450nx chipset, there is a whole bundle of
730dbe859dSJohn Baldwin 		 * things pretending to be host bridges. The MIOC will
740dbe859dSJohn Baldwin 		 * be seen first and isn't really a pci bridge (the
750dbe859dSJohn Baldwin 		 * actual busses are attached to the PXB's). We need to
760dbe859dSJohn Baldwin 		 * read the registers of the MIOC to figure out the
770dbe859dSJohn Baldwin 		 * bus numbers for the PXB channels.
780dbe859dSJohn Baldwin 		 *
790dbe859dSJohn Baldwin 		 * Since the MIOC doesn't have a pci bus attached, we
800dbe859dSJohn Baldwin 		 * pretend it wasn't there.
810dbe859dSJohn Baldwin 		 */
820dbe859dSJohn Baldwin 		return (0);
830dbe859dSJohn Baldwin 	case 0x84cb8086:
840dbe859dSJohn Baldwin 		switch (slot) {
850dbe859dSJohn Baldwin 		case 0x12:
860dbe859dSJohn Baldwin 			/* Intel 82454NX PXB#0, Bus#A */
870dbe859dSJohn Baldwin 			*busnum = read_config(bus, 0x10, func, 0xd0, 1);
880dbe859dSJohn Baldwin 			break;
890dbe859dSJohn Baldwin 		case 0x13:
900dbe859dSJohn Baldwin 			/* Intel 82454NX PXB#0, Bus#B */
910dbe859dSJohn Baldwin 			*busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1;
920dbe859dSJohn Baldwin 			break;
930dbe859dSJohn Baldwin 		case 0x14:
940dbe859dSJohn Baldwin 			/* Intel 82454NX PXB#1, Bus#A */
950dbe859dSJohn Baldwin 			*busnum = read_config(bus, 0x10, func, 0xd3, 1);
960dbe859dSJohn Baldwin 			break;
970dbe859dSJohn Baldwin 		case 0x15:
980dbe859dSJohn Baldwin 			/* Intel 82454NX PXB#1, Bus#B */
990dbe859dSJohn Baldwin 			*busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1;
1000dbe859dSJohn Baldwin 			break;
1010dbe859dSJohn Baldwin 		}
1020dbe859dSJohn Baldwin 		break;
1030dbe859dSJohn Baldwin 
1040dbe859dSJohn Baldwin 		/* ServerWorks -- vendor 0x1166 */
1050dbe859dSJohn Baldwin 	case 0x00051166:
1060dbe859dSJohn Baldwin 	case 0x00061166:
1070dbe859dSJohn Baldwin 	case 0x00081166:
1080dbe859dSJohn Baldwin 	case 0x00091166:
1090dbe859dSJohn Baldwin 	case 0x00101166:
1100dbe859dSJohn Baldwin 	case 0x00111166:
1110dbe859dSJohn Baldwin 	case 0x00171166:
1120dbe859dSJohn Baldwin 	case 0x01011166:
1130dbe859dSJohn Baldwin 	case 0x010f1014:
1140dbe859dSJohn Baldwin 	case 0x01101166:
1150dbe859dSJohn Baldwin 	case 0x02011166:
1160dbe859dSJohn Baldwin 	case 0x02251166:
1170dbe859dSJohn Baldwin 	case 0x03021014:
1180dbe859dSJohn Baldwin 		*busnum = read_config(bus, slot, func, 0x44, 1);
1190dbe859dSJohn Baldwin 		break;
1200dbe859dSJohn Baldwin 
1210dbe859dSJohn Baldwin 		/* Compaq/HP -- vendor 0x0e11 */
1220dbe859dSJohn Baldwin 	case 0x60100e11:
1230dbe859dSJohn Baldwin 		*busnum = read_config(bus, slot, func, 0xc8, 1);
1240dbe859dSJohn Baldwin 		break;
1250dbe859dSJohn Baldwin 	default:
1260dbe859dSJohn Baldwin 		/* Don't know how to read bus number. */
1270dbe859dSJohn Baldwin 		return 0;
1280dbe859dSJohn Baldwin 	}
1290dbe859dSJohn Baldwin 
1300dbe859dSJohn Baldwin 	return 1;
1310dbe859dSJohn Baldwin }
132*34ff71eeSJohn Baldwin 
133*34ff71eeSJohn Baldwin #ifdef NEW_PCIB
134*34ff71eeSJohn Baldwin /*
135*34ff71eeSJohn Baldwin  * Return a pointer to a pretty name for a PCI device.  If the device
136*34ff71eeSJohn Baldwin  * has a driver attached, the device's name is used, otherwise a name
137*34ff71eeSJohn Baldwin  * is generated from the device's PCI address.
138*34ff71eeSJohn Baldwin  */
139*34ff71eeSJohn Baldwin const char *
140*34ff71eeSJohn Baldwin pcib_child_name(device_t child)
141*34ff71eeSJohn Baldwin {
142*34ff71eeSJohn Baldwin 	static char buf[64];
143*34ff71eeSJohn Baldwin 
144*34ff71eeSJohn Baldwin 	if (device_get_nameunit(child) != NULL)
145*34ff71eeSJohn Baldwin 		return (device_get_nameunit(child));
146*34ff71eeSJohn Baldwin 	snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", pci_get_domain(child),
147*34ff71eeSJohn Baldwin 	    pci_get_bus(child), pci_get_slot(child), pci_get_function(child));
148*34ff71eeSJohn Baldwin 	return (buf);
149*34ff71eeSJohn Baldwin }
150*34ff71eeSJohn Baldwin 
151*34ff71eeSJohn Baldwin /*
152*34ff71eeSJohn Baldwin  * Some Host-PCI bridge drivers know which resource ranges they can
153*34ff71eeSJohn Baldwin  * decode and should only allocate subranges to child PCI devices.
154*34ff71eeSJohn Baldwin  * This API provides a way to manage this.  The bridge drive should
155*34ff71eeSJohn Baldwin  * initialize this structure during attach and call
156*34ff71eeSJohn Baldwin  * pcib_host_res_decodes() on each resource range it decodes.  It can
157*34ff71eeSJohn Baldwin  * then use pcib_host_res_alloc() and pcib_host_res_adjust() as helper
158*34ff71eeSJohn Baldwin  * routines for BUS_ALLOC_RESOURCE() and BUS_ADJUST_RESOURCE().  This
159*34ff71eeSJohn Baldwin  * API assumes that resources for any decoded ranges can be safely
160*34ff71eeSJohn Baldwin  * allocated from the parent via bus_generic_alloc_resource().
161*34ff71eeSJohn Baldwin  */
162*34ff71eeSJohn Baldwin int
163*34ff71eeSJohn Baldwin pcib_host_res_init(device_t pcib, struct pcib_host_resources *hr)
164*34ff71eeSJohn Baldwin {
165*34ff71eeSJohn Baldwin 
166*34ff71eeSJohn Baldwin 	hr->hr_pcib = pcib;
167*34ff71eeSJohn Baldwin 	resource_list_init(&hr->hr_rl);
168*34ff71eeSJohn Baldwin 	return (0);
169*34ff71eeSJohn Baldwin }
170*34ff71eeSJohn Baldwin 
171*34ff71eeSJohn Baldwin int
172*34ff71eeSJohn Baldwin pcib_host_res_free(device_t pcib, struct pcib_host_resources *hr)
173*34ff71eeSJohn Baldwin {
174*34ff71eeSJohn Baldwin 
175*34ff71eeSJohn Baldwin 	resource_list_free(&hr->hr_rl);
176*34ff71eeSJohn Baldwin 	return (0);
177*34ff71eeSJohn Baldwin }
178*34ff71eeSJohn Baldwin 
179*34ff71eeSJohn Baldwin int
180*34ff71eeSJohn Baldwin pcib_host_res_decodes(struct pcib_host_resources *hr, int type, u_long start,
181*34ff71eeSJohn Baldwin     u_long end, u_int flags)
182*34ff71eeSJohn Baldwin {
183*34ff71eeSJohn Baldwin 	struct resource_list_entry *rle;
184*34ff71eeSJohn Baldwin 	int rid;
185*34ff71eeSJohn Baldwin 
186*34ff71eeSJohn Baldwin 	if (bootverbose)
187*34ff71eeSJohn Baldwin 		device_printf(hr->hr_pcib, "decoding %d %srange %#lx-%#lx\n",
188*34ff71eeSJohn Baldwin 		    type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start,
189*34ff71eeSJohn Baldwin 		    end);
190*34ff71eeSJohn Baldwin 	rid = resource_list_add_next(&hr->hr_rl, type, start, end,
191*34ff71eeSJohn Baldwin 	    end - start + 1);
192*34ff71eeSJohn Baldwin 	if (flags & RF_PREFETCHABLE) {
193*34ff71eeSJohn Baldwin 		KASSERT(type == SYS_RES_MEMORY,
194*34ff71eeSJohn Baldwin 		    ("only memory is prefetchable"));
195*34ff71eeSJohn Baldwin 		rle = resource_list_find(&hr->hr_rl, type, rid);
196*34ff71eeSJohn Baldwin 		rle->flags = RLE_PREFETCH;
197*34ff71eeSJohn Baldwin 	}
198*34ff71eeSJohn Baldwin 	return (0);
199*34ff71eeSJohn Baldwin }
200*34ff71eeSJohn Baldwin 
201*34ff71eeSJohn Baldwin struct resource *
202*34ff71eeSJohn Baldwin pcib_host_res_alloc(struct pcib_host_resources *hr, device_t dev, int type,
203*34ff71eeSJohn Baldwin     int *rid, u_long start, u_long end, u_long count, u_int flags)
204*34ff71eeSJohn Baldwin {
205*34ff71eeSJohn Baldwin 	struct resource_list_entry *rle;
206*34ff71eeSJohn Baldwin 	struct resource *r;
207*34ff71eeSJohn Baldwin 	u_long new_start, new_end;
208*34ff71eeSJohn Baldwin 
209*34ff71eeSJohn Baldwin 	if (flags & RF_PREFETCHABLE)
210*34ff71eeSJohn Baldwin 		KASSERT(type == SYS_RES_MEMORY,
211*34ff71eeSJohn Baldwin 		    ("only memory is prefetchable"));
212*34ff71eeSJohn Baldwin 
213*34ff71eeSJohn Baldwin 	rle = resource_list_find(&hr->hr_rl, type, 0);
214*34ff71eeSJohn Baldwin 	if (rle == NULL) {
215*34ff71eeSJohn Baldwin 		/*
216*34ff71eeSJohn Baldwin 		 * No decoding ranges for this resource type, just pass
217*34ff71eeSJohn Baldwin 		 * the request up to the parent.
218*34ff71eeSJohn Baldwin 		 */
219*34ff71eeSJohn Baldwin 		return (bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid,
220*34ff71eeSJohn Baldwin 		    start, end, count, flags));
221*34ff71eeSJohn Baldwin 	}
222*34ff71eeSJohn Baldwin 
223*34ff71eeSJohn Baldwin restart:
224*34ff71eeSJohn Baldwin 	/* Try to allocate from each decoded range. */
225*34ff71eeSJohn Baldwin 	for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) {
226*34ff71eeSJohn Baldwin 		if (rle->type != type)
227*34ff71eeSJohn Baldwin 			continue;
228*34ff71eeSJohn Baldwin 		if (((flags & RF_PREFETCHABLE) != 0) !=
229*34ff71eeSJohn Baldwin 		    ((rle->flags & RLE_PREFETCH) != 0))
230*34ff71eeSJohn Baldwin 			continue;
231*34ff71eeSJohn Baldwin 		new_start = ulmax(start, rle->start);
232*34ff71eeSJohn Baldwin 		new_end = ulmin(end, rle->end);
233*34ff71eeSJohn Baldwin 		if (new_start > new_end ||
234*34ff71eeSJohn Baldwin 		    new_start + count - 1 > new_end ||
235*34ff71eeSJohn Baldwin 		    new_start + count < new_start)
236*34ff71eeSJohn Baldwin 			continue;
237*34ff71eeSJohn Baldwin 		r = bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid,
238*34ff71eeSJohn Baldwin 		    new_start, new_end, count, flags);
239*34ff71eeSJohn Baldwin 		if (r != NULL) {
240*34ff71eeSJohn Baldwin 			if (bootverbose)
241*34ff71eeSJohn Baldwin 				device_printf(hr->hr_pcib,
242*34ff71eeSJohn Baldwin 			    "allocated type %d (%#lx-%#lx) for rid %x of %s\n",
243*34ff71eeSJohn Baldwin 				    type, rman_get_start(r), rman_get_end(r),
244*34ff71eeSJohn Baldwin 				    *rid, pcib_child_name(dev));
245*34ff71eeSJohn Baldwin 			return (r);
246*34ff71eeSJohn Baldwin 		}
247*34ff71eeSJohn Baldwin 	}
248*34ff71eeSJohn Baldwin 
249*34ff71eeSJohn Baldwin 	/*
250*34ff71eeSJohn Baldwin 	 * If we failed to find a prefetch range for a memory
251*34ff71eeSJohn Baldwin 	 * resource, try again without prefetch.
252*34ff71eeSJohn Baldwin 	 */
253*34ff71eeSJohn Baldwin 	if (flags & RF_PREFETCHABLE) {
254*34ff71eeSJohn Baldwin 		flags &= ~RF_PREFETCHABLE;
255*34ff71eeSJohn Baldwin 		rle = resource_list_find(&hr->hr_rl, type, 0);
256*34ff71eeSJohn Baldwin 		goto restart;
257*34ff71eeSJohn Baldwin 	}
258*34ff71eeSJohn Baldwin 	return (NULL);
259*34ff71eeSJohn Baldwin }
260*34ff71eeSJohn Baldwin 
261*34ff71eeSJohn Baldwin int
262*34ff71eeSJohn Baldwin pcib_host_res_adjust(struct pcib_host_resources *hr, device_t dev, int type,
263*34ff71eeSJohn Baldwin     struct resource *r, u_long start, u_long end)
264*34ff71eeSJohn Baldwin {
265*34ff71eeSJohn Baldwin 	struct resource_list_entry *rle;
266*34ff71eeSJohn Baldwin 
267*34ff71eeSJohn Baldwin 	rle = resource_list_find(&hr->hr_rl, type, 0);
268*34ff71eeSJohn Baldwin 	if (rle == NULL) {
269*34ff71eeSJohn Baldwin 		/*
270*34ff71eeSJohn Baldwin 		 * No decoding ranges for this resource type, just pass
271*34ff71eeSJohn Baldwin 		 * the request up to the parent.
272*34ff71eeSJohn Baldwin 		 */
273*34ff71eeSJohn Baldwin 		return (bus_generic_adjust_resource(hr->hr_pcib, dev, type, r,
274*34ff71eeSJohn Baldwin 		    start, end));
275*34ff71eeSJohn Baldwin 	}
276*34ff71eeSJohn Baldwin 
277*34ff71eeSJohn Baldwin 	/* Only allow adjustments that stay within a decoded range. */
278*34ff71eeSJohn Baldwin 	for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) {
279*34ff71eeSJohn Baldwin 		if (rle->start <= start && rle->end >= end)
280*34ff71eeSJohn Baldwin 			return (bus_generic_adjust_resource(hr->hr_pcib, dev,
281*34ff71eeSJohn Baldwin 			    type, r, start, end));
282*34ff71eeSJohn Baldwin 	}
283*34ff71eeSJohn Baldwin 	return (ERANGE);
284*34ff71eeSJohn Baldwin }
285*34ff71eeSJohn Baldwin #endif /* NEW_PCIB */
286