pci_subr.c revision 261523
1191005Sdelphij/*-
231899Ssef * Copyright (c) 2011 Advanced Computing Technologies LLC
331899Ssef * Written by: John H. Baldwin <jhb@FreeBSD.org>
431899Ssef * All rights reserved.
531899Ssef *
631899Ssef * Redistribution and use in source and binary forms, with or without
731899Ssef * modification, are permitted provided that the following conditions
831899Ssef * are met:
931899Ssef * 1. Redistributions of source code must retain the above copyright
1031899Ssef *    notice, this list of conditions and the following disclaimer.
1131899Ssef * 2. Redistributions in binary form must reproduce the above copyright
1231899Ssef *    notice, this list of conditions and the following disclaimer in the
1331899Ssef *    documentation and/or other materials provided with the distribution.
1431899Ssef *
1531899Ssef * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1631899Ssef * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1731899Ssef * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1831899Ssef * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1931899Ssef * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2031899Ssef * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2131899Ssef * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2231899Ssef * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2331899Ssef * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2431899Ssef * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2531899Ssef * SUCH DAMAGE.
2631899Ssef */
2731899Ssef
2831899Ssef#include <sys/cdefs.h>
2931899Ssef__FBSDID("$FreeBSD: head/sys/dev/pci/pci_subr.c 261523 2014-02-05 19:23:05Z jhb $");
3031899Ssef
3131899Ssef/*
32119852Scharnier * Support APIs for Host to PCI bridge drivers and drivers that
33119852Scharnier * provide PCI domains.
3432275Scharnier */
3531899Ssef
3631567Ssef#include <sys/param.h>
3731567Ssef#include <sys/bus.h>
3831567Ssef#include <sys/rman.h>
3931567Ssef#include <sys/systm.h>
4031567Ssef
4185301Sdes#include <dev/pci/pcireg.h>
42123916Scracauer#include <dev/pci/pcivar.h>
43104581Smike#include <dev/pci/pcib_private.h>
44123916Scracauer
45168569Sdelphij/*
46191005Sdelphij * Try to read the bus number of a host-PCI bridge using appropriate config
4785301Sdes * registers.
48132306Salfred */
4932275Scharnierint
5032275Scharnierhost_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func,
5132275Scharnier    uint8_t *busnum)
5232275Scharnier{
5331567Ssef	uint32_t id;
5431567Ssef
5531567Ssef	id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4);
56101423Smdodd	if (id == 0xffffffff)
5731579Speter		return (0);
5831567Ssef
59101282Smdodd	switch (id) {
6087703Smarkm	case 0x12258086:
6131567Ssef		/* Intel 824?? */
62171645Smarcel		/* XXX This is a guess */
6331567Ssef		/* *busnum = read_config(bus, slot, func, 0x41, 1); */
64144177Salfred		*busnum = bus;
6532275Scharnier		break;
6632275Scharnier	case 0x84c48086:
67144177Salfred		/* Intel 82454KX/GX (Orion) */
68153963Sbrian		*busnum = read_config(bus, slot, func, 0x4a, 1);
69153963Sbrian		break;
70144177Salfred	case 0x84ca8086:
7131567Ssef		/*
7231567Ssef		 * For the 450nx chipset, there is a whole bundle of
7338897Ssef		 * things pretending to be host bridges. The MIOC will
7438897Ssef		 * be seen first and isn't really a pci bridge (the
7538897Ssef		 * actual busses are attached to the PXB's). We need to
7638897Ssef		 * read the registers of the MIOC to figure out the
7731567Ssef		 * bus numbers for the PXB channels.
78144177Salfred		 *
79144177Salfred		 * Since the MIOC doesn't have a pci bus attached, we
80144177Salfred		 * pretend it wasn't there.
8131567Ssef		 */
82130394Sdwmalone		return (0);
83144177Salfred	case 0x84cb8086:
84179051Sjhb		switch (slot) {
85179051Sjhb		case 0x12:
86130394Sdwmalone			/* Intel 82454NX PXB#0, Bus#A */
8739908Ssef			*busnum = read_config(bus, 0x10, func, 0xd0, 1);
88144177Salfred			break;
89144177Salfred		case 0x13:
90144177Salfred			/* Intel 82454NX PXB#0, Bus#B */
91144177Salfred			*busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1;
9239908Ssef			break;
93106716Smarcel		case 0x14:
94144177Salfred			/* Intel 82454NX PXB#1, Bus#A */
95106716Smarcel			*busnum = read_config(bus, 0x10, func, 0xd3, 1);
96154047Sgrehan			break;
97154047Sgrehan		case 0x15:
98154047Sgrehan			/* Intel 82454NX PXB#1, Bus#B */
99154047Sgrehan			*busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1;
100101320Sjake			break;
101144177Salfred		}
102101320Sjake		break;
103188628Simp
104188628Simp		/* ServerWorks -- vendor 0x1166 */
105188628Simp	case 0x00051166:
106188628Simp	case 0x00061166:
107188628Simp	case 0x00081166:
108144177Salfred	case 0x00091166:
10931567Ssef	case 0x00101166:
11031567Ssef	case 0x00111166:
11131567Ssef	case 0x00171166:
11231567Ssef	case 0x01011166:
113168569Sdelphij	case 0x010f1014:
11431567Ssef	case 0x01101166:
11531567Ssef	case 0x02011166:
11631567Ssef	case 0x02251166:
117144177Salfred	case 0x03021014:
118144177Salfred		*busnum = read_config(bus, slot, func, 0x44, 1);
119144177Salfred		break;
120144177Salfred
121168569Sdelphij		/* Compaq/HP -- vendor 0x0e11 */
122168569Sdelphij	case 0x60100e11:
123168569Sdelphij		*busnum = read_config(bus, slot, func, 0xc8, 1);
124168569Sdelphij		break;
12531567Ssef	default:
126168569Sdelphij		/* Don't know how to read bus number. */
127168569Sdelphij		return 0;
128168569Sdelphij	}
129168569Sdelphij
130168569Sdelphij	return 1;
131168569Sdelphij}
132168569Sdelphij
13331567Ssef#ifdef NEW_PCIB
134144177Salfred/*
135144177Salfred * Return a pointer to a pretty name for a PCI device.  If the device
136144177Salfred * has a driver attached, the device's name is used, otherwise a name
13731567Ssef * is generated from the device's PCI address.
138144177Salfred */
139144177Salfredconst char *
140144177Salfredpcib_child_name(device_t child)
141144177Salfred{
142144177Salfred	static char buf[64];
143144177Salfred
14431567Ssef	if (device_get_nameunit(child) != NULL)
14531567Ssef		return (device_get_nameunit(child));
146132306Salfred	snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", pci_get_domain(child),
147132306Salfred	    pci_get_bus(child), pci_get_slot(child), pci_get_function(child));
148132306Salfred	return (buf);
149132306Salfred}
150132306Salfred
151132306Salfred/*
152132306Salfred * Some Host-PCI bridge drivers know which resource ranges they can
153132306Salfred * decode and should only allocate subranges to child PCI devices.
154132306Salfred * This API provides a way to manage this.  The bridge driver should
155132306Salfred * initialize this structure during attach and call
156132306Salfred * pcib_host_res_decodes() on each resource range it decodes.  It can
157132306Salfred * then use pcib_host_res_alloc() and pcib_host_res_adjust() as helper
158132306Salfred * routines for BUS_ALLOC_RESOURCE() and BUS_ADJUST_RESOURCE().  This
159132306Salfred * API assumes that resources for any decoded ranges can be safely
160132306Salfred * allocated from the parent via bus_generic_alloc_resource().
161132306Salfred */
162132306Salfredint
16332275Scharnierpcib_host_res_init(device_t pcib, struct pcib_host_resources *hr)
164144177Salfred{
165144177Salfred
166144177Salfred	hr->hr_pcib = pcib;
167144177Salfred	resource_list_init(&hr->hr_rl);
168191005Sdelphij	return (0);
169191005Sdelphij}
170144177Salfred
171144177Salfredint
172171055Sdelphijpcib_host_res_free(device_t pcib, struct pcib_host_resources *hr)
173144178Salfred{
174144177Salfred
175144177Salfred	resource_list_free(&hr->hr_rl);
17631567Ssef	return (0);
177144178Salfred}
178144178Salfred
179144178Salfredint
180144177Salfredpcib_host_res_decodes(struct pcib_host_resources *hr, int type, u_long start,
181144177Salfred    u_long end, u_int flags)
182144177Salfred{
183144177Salfred	struct resource_list_entry *rle;
184144177Salfred	int rid;
185168569Sdelphij
186144177Salfred	if (bootverbose)
187153963Sbrian		device_printf(hr->hr_pcib, "decoding %d %srange %#lx-%#lx\n",
188168569Sdelphij		    type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start,
189168569Sdelphij		    end);
190168569Sdelphij	rid = resource_list_add_next(&hr->hr_rl, type, start, end,
191153963Sbrian	    end - start + 1);
192144177Salfred	if (flags & RF_PREFETCHABLE) {
193144177Salfred		KASSERT(type == SYS_RES_MEMORY,
194144177Salfred		    ("only memory is prefetchable"));
195171055Sdelphij		rle = resource_list_find(&hr->hr_rl, type, rid);
196171055Sdelphij		rle->flags = RLE_PREFETCH;
197171055Sdelphij	}
198171055Sdelphij	return (0);
199171055Sdelphij}
200144177Salfred
201144177Salfredstruct resource *
202144177Salfredpcib_host_res_alloc(struct pcib_host_resources *hr, device_t dev, int type,
203144177Salfred    int *rid, u_long start, u_long end, u_long count, u_int flags)
204144177Salfred{
205144177Salfred	struct resource_list_entry *rle;
206144177Salfred	struct resource *r;
207144177Salfred	u_long new_start, new_end;
208144177Salfred
209144177Salfred	if (flags & RF_PREFETCHABLE)
210144177Salfred		KASSERT(type == SYS_RES_MEMORY,
211144177Salfred		    ("only memory is prefetchable"));
212144177Salfred
213144177Salfred	rle = resource_list_find(&hr->hr_rl, type, 0);
214144177Salfred	if (rle == NULL) {
215144177Salfred		/*
216144177Salfred		 * No decoding ranges for this resource type, just pass
217144177Salfred		 * the request up to the parent.
218144177Salfred		 */
219153963Sbrian		return (bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid,
220153963Sbrian		    start, end, count, flags));
221153963Sbrian	}
222144177Salfred
223144177Salfredrestart:
224144177Salfred	/* Try to allocate from each decoded range. */
225144177Salfred	for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) {
226144177Salfred		if (rle->type != type)
227144177Salfred			continue;
228144177Salfred		if (((flags & RF_PREFETCHABLE) != 0) !=
22931567Ssef		    ((rle->flags & RLE_PREFETCH) != 0))
230144177Salfred			continue;
231144177Salfred		new_start = ulmax(start, rle->start);
232144177Salfred		new_end = ulmin(end, rle->end);
233144177Salfred		if (new_start > new_end ||
23431567Ssef		    new_start + count - 1 > new_end ||
235144177Salfred		    new_start + count < new_start)
236144177Salfred			continue;
237144177Salfred		r = bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid,
238144177Salfred		    new_start, new_end, count, flags);
23932275Scharnier		if (r != NULL) {
240144177Salfred			if (bootverbose)
241144177Salfred				device_printf(hr->hr_pcib,
242144177Salfred			    "allocated type %d (%#lx-%#lx) for rid %x of %s\n",
243144177Salfred				    type, rman_get_start(r), rman_get_end(r),
244144177Salfred				    *rid, pcib_child_name(dev));
245144177Salfred			return (r);
24631567Ssef		}
247144177Salfred	}
248144177Salfred
249144177Salfred	/*
250144177Salfred	 * If we failed to find a prefetch range for a memory
251144177Salfred	 * resource, try again without prefetch.
252144177Salfred	 */
253144177Salfred	if (flags & RF_PREFETCHABLE) {
254168569Sdelphij		flags &= ~RF_PREFETCHABLE;
255144177Salfred		rle = resource_list_find(&hr->hr_rl, type, 0);
256144177Salfred		goto restart;
257144177Salfred	}
258144177Salfred	return (NULL);
25931567Ssef}
26031567Ssef
261144177Salfredint
262144177Salfredpcib_host_res_adjust(struct pcib_host_resources *hr, device_t dev, int type,
263144177Salfred    struct resource *r, u_long start, u_long end)
264144177Salfred{
26531567Ssef	struct resource_list_entry *rle;
266101283Smdodd
267168569Sdelphij	rle = resource_list_find(&hr->hr_rl, type, 0);
268168569Sdelphij	if (rle == NULL) {
269144178Salfred		/*
270144177Salfred		 * No decoding ranges for this resource type, just pass
271144177Salfred		 * the request up to the parent.
272144177Salfred		 */
273144177Salfred		return (bus_generic_adjust_resource(hr->hr_pcib, dev, type, r,
274144177Salfred		    start, end));
27531567Ssef	}
276144177Salfred
277101285Smdodd	/* Only allow adjustments that stay within a decoded range. */
278144177Salfred	for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) {
279158630Spav		if (rle->start <= start && rle->end >= end)
280168569Sdelphij			return (bus_generic_adjust_resource(hr->hr_pcib, dev,
28131567Ssef			    type, r, start, end));
282168569Sdelphij	}
283168569Sdelphij	return (ERANGE);
284168569Sdelphij}
285168569Sdelphij#endif /* NEW_PCIB */
286168569Sdelphij