184124Sdfr/*-
2203106Smarcel * Copyright (c) 2010 Marcel Moolenaar
384124Sdfr * Copyright (c) 2001 Doug Rabson
484124Sdfr * All rights reserved.
584124Sdfr *
684124Sdfr * Redistribution and use in source and binary forms, with or without
784124Sdfr * modification, are permitted provided that the following conditions
884124Sdfr * are met:
984124Sdfr * 1. Redistributions of source code must retain the above copyright
1084124Sdfr *    notice, this list of conditions and the following disclaimer.
1184124Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1284124Sdfr *    notice, this list of conditions and the following disclaimer in the
1384124Sdfr *    documentation and/or other materials provided with the distribution.
1484124Sdfr *
1584124Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1684124Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1784124Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1884124Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1984124Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2084124Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2184124Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2284124Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2384124Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2484124Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2584124Sdfr * SUCH DAMAGE.
2684124Sdfr *
2784124Sdfr * $FreeBSD$
2884124Sdfr */
2984124Sdfr
3084124Sdfr#include <sys/param.h>
31205432Smarcel#include <machine/cpufunc.h>
3284124Sdfr#include <machine/pci_cfgreg.h>
3384124Sdfr#include <machine/sal.h>
3484124Sdfr
35203106Smarcelstatic u_long
36203106Smarcelpci_sal_address(int dom, int bus, int slot, int func, int reg)
37203106Smarcel{
38203106Smarcel	u_long addr;
3984124Sdfr
40203106Smarcel	addr = ~0ul;
41203106Smarcel	if (dom >= 0 && dom <= 255 && bus >= 0 && bus <= 255 &&
42203106Smarcel	    slot >= 0 && slot <= 31 && func >= 0 && func <= 7 &&
43203106Smarcel	    reg >= 0 && reg <= 255) {
44203106Smarcel		addr = ((u_long)dom << 24) | ((u_long)bus << 16) |
45203106Smarcel		    ((u_long)slot << 11) | ((u_long)func << 8) | (u_long)reg;
46203106Smarcel	}
47203106Smarcel	return (addr);
48203106Smarcel}
49203106Smarcel
50203106Smarcelstatic int
51203106Smarcelpci_valid_access(int reg, int len)
52203106Smarcel{
53203106Smarcel	int ok;
54203106Smarcel
55203106Smarcel	ok = ((len == 1 || len == 2 || len == 4) && (reg & (len - 1)) == 0)
56203106Smarcel	    ? 1 : 0;
57203106Smarcel	return (ok);
58203106Smarcel}
59203106Smarcel
6084124Sdfrint
6184124Sdfrpci_cfgregopen(void)
6284124Sdfr{
63203106Smarcel	return (1);
6484124Sdfr}
6584124Sdfr
66203106Smarceluint32_t
67203106Smarcelpci_cfgregread(int bus, int slot, int func, int reg, int len)
6884124Sdfr{
6984124Sdfr	struct ia64_sal_result res;
70205432Smarcel	register_t is;
71203106Smarcel	u_long addr;
7284124Sdfr
73253560Smarcel	addr = pci_sal_address(bus >> 8, bus & 0xff, slot, func, reg);
74203106Smarcel	if (addr == ~0ul)
75203106Smarcel		return (~0);
76203106Smarcel
77203106Smarcel	if (!pci_valid_access(reg, len))
78203106Smarcel		return (~0);
79203106Smarcel
80205432Smarcel	is = intr_disable();
81203106Smarcel	res = ia64_sal_entry(SAL_PCI_CONFIG_READ, addr, len, 0, 0, 0, 0, 0);
82205432Smarcel	intr_restore(is);
83203106Smarcel
84205432Smarcel	return ((res.sal_status < 0) ? ~0 : res.sal_result[0]);
8584412Sdfr}
8684124Sdfr
8784124Sdfrvoid
88203106Smarcelpci_cfgregwrite(int bus, int slot, int func, int reg, uint32_t data, int len)
8984124Sdfr{
9084124Sdfr	struct ia64_sal_result res;
91205432Smarcel	register_t is;
92203106Smarcel	u_long addr;
9384124Sdfr
94253560Smarcel	addr = pci_sal_address(bus >> 8, bus & 0xff, slot, func, reg);
95203106Smarcel	if (addr == ~0ul)
96203106Smarcel		return;
97203106Smarcel
98203106Smarcel	if (!pci_valid_access(reg, len))
99203106Smarcel		return;
100203106Smarcel
101205432Smarcel	is = intr_disable();
102203106Smarcel	res = ia64_sal_entry(SAL_PCI_CONFIG_WRITE, addr, len, data, 0, 0, 0, 0);
103205432Smarcel	intr_restore(is);
10484124Sdfr}
105