Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca3dd88e authored by David S. Miller's avatar David S. Miller
Browse files

[SPARC64] PCI: Consolidate PCI access code into pci_common.c



All the sun4u controllers do the same thing to compute the physical
I/O address to poke, and we can move the sun4v code into this common
location too.

This one needs a bit of testing, in particular the Sabre code had some
funny stuff that would break up u16 and/or u32 accesses into pieces
and I didn't think that was needed any more.  If it is we need to find
out why and add back code to do it again.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent de372ecd
Loading
Loading
Loading
Loading
+194 −0
Original line number Diff line number Diff line
@@ -14,6 +14,200 @@
#include <asm/oplib.h>

#include "pci_impl.h"
#include "pci_sun4v.h"

static int config_out_of_range(struct pci_pbm_info *pbm,
			       unsigned long bus,
			       unsigned long devfn,
			       unsigned long reg)
{
	if (bus < pbm->pci_first_busno ||
	    bus > pbm->pci_last_busno)
		return 1;
	return 0;
}

static void *sun4u_config_mkaddr(struct pci_pbm_info *pbm,
				 unsigned long bus,
				 unsigned long devfn,
				 unsigned long reg)
{
	unsigned long rbits = pbm->config_space_reg_bits;

	if (config_out_of_range(pbm, bus, devfn, reg))
		return NULL;

	reg = (reg & ((1 << rbits) - 1));
	devfn <<= rbits;
	bus <<= rbits + 8;

	return (void *)	(pbm->config_space | bus | devfn | reg);
}

static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
			      int where, int size, u32 *value)
{
	struct pci_pbm_info *pbm = bus_dev->sysdata;
	unsigned char bus = bus_dev->number;
	u32 *addr;
	u16 tmp16;
	u8 tmp8;

	if (bus_dev == pbm->pci_bus && devfn == 0x00)
		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
						    size, value);

	switch (size) {
	case 1:
		*value = 0xff;
		break;
	case 2:
		*value = 0xffff;
		break;
	case 4:
		*value = 0xffffffff;
		break;
	}

	addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
	if (!addr)
		return PCIBIOS_SUCCESSFUL;

	switch (size) {
	case 1:
		pci_config_read8((u8 *)addr, &tmp8);
		*value = (u32) tmp8;
		break;

	case 2:
		if (where & 0x01) {
			printk("pci_read_config_word: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}
		pci_config_read16((u16 *)addr, &tmp16);
		*value = (u32) tmp16;
		break;

	case 4:
		if (where & 0x03) {
			printk("pci_read_config_dword: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}
		pci_config_read32(addr, value);
		break;
	}
	return PCIBIOS_SUCCESSFUL;
}

static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
			       int where, int size, u32 value)
{
	struct pci_pbm_info *pbm = bus_dev->sysdata;
	unsigned char bus = bus_dev->number;
	u32 *addr;

	if (bus_dev == pbm->pci_bus && devfn == 0x00)
		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
						     size, value);
	addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
	if (!addr)
		return PCIBIOS_SUCCESSFUL;

	switch (size) {
	case 1:
		pci_config_write8((u8 *)addr, value);
		break;

	case 2:
		if (where & 0x01) {
			printk("pci_write_config_word: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}
		pci_config_write16((u16 *)addr, value);
		break;

	case 4:
		if (where & 0x03) {
			printk("pci_write_config_dword: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}
		pci_config_write32(addr, value);
	}
	return PCIBIOS_SUCCESSFUL;
}

struct pci_ops sun4u_pci_ops = {
	.read =		sun4u_read_pci_cfg,
	.write =	sun4u_write_pci_cfg,
};

static int sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
			      int where, int size, u32 *value)
{
	struct pci_pbm_info *pbm = bus_dev->sysdata;
	u32 devhandle = pbm->devhandle;
	unsigned int bus = bus_dev->number;
	unsigned int device = PCI_SLOT(devfn);
	unsigned int func = PCI_FUNC(devfn);
	unsigned long ret;

	if (bus_dev == pbm->pci_bus && devfn == 0x00)
		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
						    size, value);
	if (config_out_of_range(pbm, bus, devfn, where)) {
		ret = ~0UL;
	} else {
		ret = pci_sun4v_config_get(devhandle,
				HV_PCI_DEVICE_BUILD(bus, device, func),
				where, size);
	}
	switch (size) {
	case 1:
		*value = ret & 0xff;
		break;
	case 2:
		*value = ret & 0xffff;
		break;
	case 4:
		*value = ret & 0xffffffff;
		break;
	};


	return PCIBIOS_SUCCESSFUL;
}

static int sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
			       int where, int size, u32 value)
{
	struct pci_pbm_info *pbm = bus_dev->sysdata;
	u32 devhandle = pbm->devhandle;
	unsigned int bus = bus_dev->number;
	unsigned int device = PCI_SLOT(devfn);
	unsigned int func = PCI_FUNC(devfn);
	unsigned long ret;

	if (bus_dev == pbm->pci_bus && devfn == 0x00)
		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
						     size, value);
	if (config_out_of_range(pbm, bus, devfn, where)) {
		/* Do nothing. */
	} else {
		ret = pci_sun4v_config_put(devhandle,
				HV_PCI_DEVICE_BUILD(bus, device, func),
				where, size, value);
	}
	return PCIBIOS_SUCCESSFUL;
}

struct pci_ops sun4v_pci_ops = {
	.read =		sun4v_read_pci_cfg,
	.write =	sun4v_write_pci_cfg,
};

void pci_get_pbm_props(struct pci_pbm_info *pbm)
{
+2 −133
Original line number Diff line number Diff line
@@ -27,138 +27,6 @@
			       "i" (ASI_PHYS_BYPASS_EC_E) \
			     : "memory")

/* Fire config space address format is nearly identical to
 * that of SCHIZO and PSYCHO, except that in order to accomodate
 * PCI-E extended config space the encoding can handle 12 bits
 * of register address:
 *
 *  32     28 27 20 19    15 14      12 11  2  1 0
 * -------------------------------------------------
 * |0 0 0 0 0| bus | device | function | reg | 0 0 |
 * -------------------------------------------------
 */
#define FIRE_CONFIG_BASE(PBM)	((PBM)->config_space)
#define FIRE_CONFIG_ENCODE(BUS, DEVFN, REG)	\
	(((unsigned long)(BUS)   << 20) |	\
	 ((unsigned long)(DEVFN) << 12)  |	\
	 ((unsigned long)(REG)))

static void *fire_pci_config_mkaddr(struct pci_pbm_info *pbm,
				      unsigned char bus,
				      unsigned int devfn,
				      int where)
{
	if (!pbm)
		return NULL;
	return (void *)
		(FIRE_CONFIG_BASE(pbm) |
		 FIRE_CONFIG_ENCODE(bus, devfn, where));
}

/* FIRE PCI configuration space accessors. */

static int fire_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
			     int where, int size, u32 *value)
{
	struct pci_pbm_info *pbm = bus_dev->sysdata;
	unsigned char bus = bus_dev->number;
	u32 *addr;
	u16 tmp16;
	u8 tmp8;

	if (bus_dev == pbm->pci_bus && devfn == 0x00)
		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
						    size, value);
	switch (size) {
	case 1:
		*value = 0xff;
		break;
	case 2:
		*value = 0xffff;
		break;
	case 4:
		*value = 0xffffffff;
		break;
	}

	addr = fire_pci_config_mkaddr(pbm, bus, devfn, where);
	if (!addr)
		return PCIBIOS_SUCCESSFUL;

	switch (size) {
	case 1:
		pci_config_read8((u8 *)addr, &tmp8);
		*value = tmp8;
		break;

	case 2:
		if (where & 0x01) {
			printk("pci_read_config_word: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}
		pci_config_read16((u16 *)addr, &tmp16);
		*value = tmp16;
		break;

	case 4:
		if (where & 0x03) {
			printk("pci_read_config_dword: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}

		pci_config_read32(addr, value);
		break;
	}
	return PCIBIOS_SUCCESSFUL;
}

static int fire_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
			      int where, int size, u32 value)
{
	struct pci_pbm_info *pbm = bus_dev->sysdata;
	unsigned char bus = bus_dev->number;
	u32 *addr;

	if (bus_dev == pbm->pci_bus && devfn == 0x00)
		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
						     size, value);
	addr = fire_pci_config_mkaddr(pbm, bus, devfn, where);
	if (!addr)
		return PCIBIOS_SUCCESSFUL;

	switch (size) {
	case 1:
		pci_config_write8((u8 *)addr, value);
		break;

	case 2:
		if (where & 0x01) {
			printk("pci_write_config_word: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}
		pci_config_write16((u16 *)addr, value);
		break;

	case 4:
		if (where & 0x03) {
			printk("pci_write_config_dword: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}

		pci_config_write32(addr, value);
	}
	return PCIBIOS_SUCCESSFUL;
}

static struct pci_ops pci_fire_ops = {
	.read	=	fire_read_pci_cfg,
	.write	=	fire_write_pci_cfg,
};

static void pci_fire_scan_bus(struct pci_pbm_info *pbm)
{
	pbm->pci_bus = pci_scan_one_pbm(pbm);
@@ -314,7 +182,8 @@ static void pci_fire_pbm_init(struct pci_controller_info *p,
	pci_pbm_root = pbm;

	pbm->scan_bus = pci_fire_scan_bus;
	pbm->pci_ops = &pci_fire_ops;
	pbm->pci_ops = &sun4u_pci_ops;
	pbm->config_space_reg_bits = 12;

	pbm->index = pci_num_pbms++;

+6 −0
Original line number Diff line number Diff line
@@ -77,6 +77,9 @@ struct pci_pbm_info {
	/* Base of PCI Config space, can be per-PBM or shared. */
	unsigned long			config_space;

	/* This will be 12 on PCI-E controllers, 8 elsewhere.  */
	unsigned long			config_space_reg_bits;

	/* State of 66MHz capabilities on this PBM. */
	int				is_66mhz_capable;
	int				all_devs_66mhz;
@@ -156,4 +159,7 @@ extern void pci_config_write8(u8 *addr, u8 val);
extern void pci_config_write16(u16 *addr, u16 val);
extern void pci_config_write32(u32 *addr, u32 val);

extern struct pci_ops sun4u_pci_ops;
extern struct pci_ops sun4v_pci_ops;

#endif /* !(PCI_IMPL_H) */
+2 −117
Original line number Diff line number Diff line
@@ -94,122 +94,6 @@ static void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm,
		 PSYCHO_CONFIG_ENCODE(bus, devfn, where));
}

static int psycho_out_of_range(struct pci_pbm_info *pbm,
			       unsigned char bus,
			       unsigned char devfn)
{
	return ((bus == pbm->pci_first_busno) &&
		PCI_SLOT(devfn) > 8);
}

/* PSYCHO PCI configuration space accessors. */

static int psycho_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
			       int where, int size, u32 *value)
{
	struct pci_pbm_info *pbm = bus_dev->sysdata;
	unsigned char bus = bus_dev->number;
	u32 *addr;
	u16 tmp16;
	u8 tmp8;

	if (bus_dev == pbm->pci_bus && devfn == 0x00)
		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
						    size, value);

	switch (size) {
	case 1:
		*value = 0xff;
		break;
	case 2:
		*value = 0xffff;
		break;
	case 4:
		*value = 0xffffffff;
		break;
	}

	addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
	if (!addr)
		return PCIBIOS_SUCCESSFUL;

	if (psycho_out_of_range(pbm, bus, devfn))
		return PCIBIOS_SUCCESSFUL;
	switch (size) {
	case 1:
		pci_config_read8((u8 *)addr, &tmp8);
		*value = (u32) tmp8;
		break;

	case 2:
		if (where & 0x01) {
			printk("pci_read_config_word: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}
		pci_config_read16((u16 *)addr, &tmp16);
		*value = (u32) tmp16;
		break;

	case 4:
		if (where & 0x03) {
			printk("pci_read_config_dword: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}
		pci_config_read32(addr, value);
		break;
	}
	return PCIBIOS_SUCCESSFUL;
}

static int psycho_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
				int where, int size, u32 value)
{
	struct pci_pbm_info *pbm = bus_dev->sysdata;
	unsigned char bus = bus_dev->number;
	u32 *addr;

	if (bus_dev == pbm->pci_bus && devfn == 0x00)
		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
						     size, value);
	addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
	if (!addr)
		return PCIBIOS_SUCCESSFUL;

	if (psycho_out_of_range(pbm, bus, devfn))
		return PCIBIOS_SUCCESSFUL;

	switch (size) {
	case 1:
		pci_config_write8((u8 *)addr, value);
		break;

	case 2:
		if (where & 0x01) {
			printk("pci_write_config_word: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}
		pci_config_write16((u16 *)addr, value);
		break;

	case 4:
		if (where & 0x03) {
			printk("pci_write_config_dword: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}
		pci_config_write32(addr, value);
	}
	return PCIBIOS_SUCCESSFUL;
}

static struct pci_ops psycho_ops = {
	.read =		psycho_read_pci_cfg,
	.write =	psycho_write_pci_cfg,
};

/* PSYCHO error handling support. */
enum psycho_error_type {
	UE_ERR, CE_ERR, PCI_ERR
@@ -1089,7 +973,8 @@ static void psycho_pbm_init(struct pci_controller_info *p,
	pci_pbm_root = pbm;

	pbm->scan_bus = psycho_scan_bus;
	pbm->pci_ops = &psycho_ops;
	pbm->pci_ops = &sun4u_pci_ops;
	pbm->config_space_reg_bits = 8;

	pbm->index = pci_num_pbms++;

+2 −286
Original line number Diff line number Diff line
@@ -205,294 +205,9 @@
#define SABRE_MEMSPACE		0x100000000UL
#define SABRE_MEMSPACE_SIZE	0x07fffffffUL

/* UltraSparc-IIi Programmer's Manual, page 325, PCI
 * configuration space address format:
 * 
 *  32             24 23 16 15    11 10       8 7   2  1 0
 * ---------------------------------------------------------
 * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 |
 * ---------------------------------------------------------
 */
#define SABRE_CONFIG_BASE(PBM)	\
	((PBM)->config_space | (1UL << 24))
#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG)	\
	(((unsigned long)(BUS)   << 16) |	\
	 ((unsigned long)(DEVFN) << 8)  |	\
	 ((unsigned long)(REG)))

static int hummingbird_p;
static struct pci_bus *sabre_root_bus;

static void *sabre_pci_config_mkaddr(struct pci_pbm_info *pbm,
				     unsigned char bus,
				     unsigned int devfn,
				     int where)
{
	if (!pbm)
		return NULL;
	return (void *)
		(SABRE_CONFIG_BASE(pbm) |
		 SABRE_CONFIG_ENCODE(bus, devfn, where));
}

static int sabre_out_of_range(unsigned char devfn)
{
	if (hummingbird_p)
		return 0;

	return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) ||
		((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) ||
		(PCI_SLOT(devfn) > 1));
}

static int __sabre_out_of_range(struct pci_pbm_info *pbm,
				unsigned char bus,
				unsigned char devfn)
{
	if (hummingbird_p)
		return 0;

	return ((pbm->parent == 0) ||
		((pbm == &pbm->parent->pbm_A) &&
		 (bus == pbm->pci_first_busno) &&
		 PCI_SLOT(devfn) > 8));
}

static int __sabre_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
				int where, int size, u32 *value)
{
	struct pci_pbm_info *pbm = bus_dev->sysdata;
	unsigned char bus = bus_dev->number;
	u32 *addr;
	u16 tmp16;
	u8 tmp8;

	switch (size) {
	case 1:
		*value = 0xff;
		break;
	case 2:
		*value = 0xffff;
		break;
	case 4:
		*value = 0xffffffff;
		break;
	}

	addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where);
	if (!addr)
		return PCIBIOS_SUCCESSFUL;

	if (__sabre_out_of_range(pbm, bus, devfn))
		return PCIBIOS_SUCCESSFUL;

	switch (size) {
	case 1:
		pci_config_read8((u8 *) addr, &tmp8);
		*value = tmp8;
		break;

	case 2:
		if (where & 0x01) {
			printk("pci_read_config_word: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}
		pci_config_read16((u16 *) addr, &tmp16);
		*value = tmp16;
		break;

	case 4:
		if (where & 0x03) {
			printk("pci_read_config_dword: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}
		pci_config_read32(addr, value);
		break;
	}

	return PCIBIOS_SUCCESSFUL;
}

static int sabre_read_pci_cfg(struct pci_bus *bus, unsigned int devfn,
			      int where, int size, u32 *value)
{
	struct pci_pbm_info *pbm = bus->sysdata;

	if (bus == pbm->pci_bus && devfn == 0x00)
		return pci_host_bridge_read_pci_cfg(bus, devfn, where,
						    size, value);

	if (!bus->number && sabre_out_of_range(devfn)) {
		switch (size) {
		case 1:
			*value = 0xff;
			break;
		case 2:
			*value = 0xffff;
			break;
		case 4:
			*value = 0xffffffff;
			break;
		}
		return PCIBIOS_SUCCESSFUL;
	}

	if (bus->number || PCI_SLOT(devfn))
		return __sabre_read_pci_cfg(bus, devfn, where, size, value);

	/* When accessing PCI config space of the PCI controller itself (bus
	 * 0, device slot 0, function 0) there are restrictions.  Each
	 * register must be accessed as it's natural size.  Thus, for example
	 * the Vendor ID must be accessed as a 16-bit quantity.
	 */

	switch (size) {
	case 1:
		if (where < 8) {
			u32 tmp32;
			u16 tmp16;

			__sabre_read_pci_cfg(bus, devfn, where & ~1, 2, &tmp32);
			tmp16 = (u16) tmp32;
			if (where & 1)
				*value = tmp16 >> 8;
			else
				*value = tmp16 & 0xff;
		} else
			return __sabre_read_pci_cfg(bus, devfn, where, 1, value);
		break;

	case 2:
		if (where < 8)
			return __sabre_read_pci_cfg(bus, devfn, where, 2, value);
		else {
			u32 tmp32;
			u8 tmp8;

			__sabre_read_pci_cfg(bus, devfn, where, 1, &tmp32);
			tmp8 = (u8) tmp32;
			*value = tmp8;
			__sabre_read_pci_cfg(bus, devfn, where + 1, 1, &tmp32);
			tmp8 = (u8) tmp32;
			*value |= tmp8 << 8;
		}
		break;

	case 4: {
		u32 tmp32;
		u16 tmp16;

		sabre_read_pci_cfg(bus, devfn, where, 2, &tmp32);
		tmp16 = (u16) tmp32;
		*value = tmp16;
		sabre_read_pci_cfg(bus, devfn, where + 2, 2, &tmp32);
		tmp16 = (u16) tmp32;
		*value |= tmp16 << 16;
		break;
	}
	}
	return PCIBIOS_SUCCESSFUL;
}

static int __sabre_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
				 int where, int size, u32 value)
{
	struct pci_pbm_info *pbm = bus_dev->sysdata;
	unsigned char bus = bus_dev->number;
	u32 *addr;

	addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where);
	if (!addr)
		return PCIBIOS_SUCCESSFUL;

	if (__sabre_out_of_range(pbm, bus, devfn))
		return PCIBIOS_SUCCESSFUL;

	switch (size) {
	case 1:
		pci_config_write8((u8 *) addr, value);
		break;

	case 2:
		if (where & 0x01) {
			printk("pci_write_config_word: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}
		pci_config_write16((u16 *) addr, value);
		break;

	case 4:
		if (where & 0x03) {
			printk("pci_write_config_dword: misaligned reg [%x]\n",
			       where);
			return PCIBIOS_SUCCESSFUL;
		}
		pci_config_write32(addr, value);
		break;
	}

	return PCIBIOS_SUCCESSFUL;
}

static int sabre_write_pci_cfg(struct pci_bus *bus, unsigned int devfn,
			       int where, int size, u32 value)
{
	struct pci_pbm_info *pbm = bus->sysdata;

	if (bus == pbm->pci_bus && devfn == 0x00)
		return pci_host_bridge_write_pci_cfg(bus, devfn, where,
						     size, value);

	if (bus->number)
		return __sabre_write_pci_cfg(bus, devfn, where, size, value);

	if (sabre_out_of_range(devfn))
		return PCIBIOS_SUCCESSFUL;

	switch (size) {
	case 1:
		if (where < 8) {
			u32 tmp32;
			u16 tmp16;

			__sabre_read_pci_cfg(bus, devfn, where & ~1, 2, &tmp32);
			tmp16 = (u16) tmp32;
			if (where & 1) {
				value &= 0x00ff;
				value |= tmp16 << 8;
			} else {
				value &= 0xff00;
				value |= tmp16;
			}
			tmp32 = (u32) tmp16;
			return __sabre_write_pci_cfg(bus, devfn, where & ~1, 2, tmp32);
		} else
			return __sabre_write_pci_cfg(bus, devfn, where, 1, value);
		break;
	case 2:
		if (where < 8)
			return __sabre_write_pci_cfg(bus, devfn, where, 2, value);
		else {
			__sabre_write_pci_cfg(bus, devfn, where, 1, value & 0xff);
			__sabre_write_pci_cfg(bus, devfn, where + 1, 1, value >> 8);
		}
		break;
	case 4:
		sabre_write_pci_cfg(bus, devfn, where, 2, value & 0xffff);
		sabre_write_pci_cfg(bus, devfn, where + 2, 2, value >> 16);
		break;
	}
	return PCIBIOS_SUCCESSFUL;
}

static struct pci_ops sabre_ops = {
	.read =		sabre_read_pci_cfg,
	.write =	sabre_write_pci_cfg,
};

/* SABRE error handling support. */
static void sabre_check_iommu_error(struct pci_pbm_info *pbm,
				    unsigned long afsr,
@@ -1010,7 +725,8 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct pci_pbm_info *p
	printk("%s: SABRE PCI Bus Module\n", pbm->name);

	pbm->scan_bus = sabre_scan_bus;
	pbm->pci_ops = &sabre_ops;
	pbm->pci_ops = &sun4u_pci_ops;
	pbm->config_space_reg_bits = 8;

	pbm->index = pci_num_pbms++;

Loading