diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index d85e1ed7c3e..cf9a75112d0 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -377,7 +377,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, const char *type; u32 class; - dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); + dev = alloc_pci_dev(); if (!dev) return NULL; diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 76faaa8135d..f974fefc3eb 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -14,6 +14,200 @@ #include #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) { diff --git a/arch/sparc64/kernel/pci_fire.c b/arch/sparc64/kernel/pci_fire.c index 2e0eb4ee8f7..9198c1a0f7a 100644 --- a/arch/sparc64/kernel/pci_fire.c +++ b/arch/sparc64/kernel/pci_fire.c @@ -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++; diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index 8e38023868a..f660c2b685e 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -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) */ diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 2edcb1dd13c..598393a2df1 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -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++; diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 4cefe6e83b2..e2377796de8 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -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++; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index e375d72b8ee..ae76898bbe2 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -104,125 +104,6 @@ static void *schizo_pci_config_mkaddr(struct pci_pbm_info *pbm, SCHIZO_CONFIG_ENCODE(bus, devfn, where)); } -/* Just make sure the bus number is in range. */ -static int schizo_out_of_range(struct pci_pbm_info *pbm, - unsigned char bus, - unsigned char devfn) -{ - if (bus < pbm->pci_first_busno || - bus > pbm->pci_last_busno) - return 1; - return 0; -} - -/* SCHIZO PCI configuration space accessors. */ - -static int schizo_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 = schizo_pci_config_mkaddr(pbm, bus, devfn, where); - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (schizo_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 schizo_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 = schizo_pci_config_mkaddr(pbm, bus, devfn, where); - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (schizo_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 schizo_ops = { - .read = schizo_read_pci_cfg, - .write = schizo_write_pci_cfg, -}; - /* SCHIZO error handling support. */ enum schizo_error_type { UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR @@ -1494,7 +1375,8 @@ static void schizo_pbm_init(struct pci_controller_info *p, pci_pbm_root = pbm; pbm->scan_bus = schizo_scan_bus; - pbm->pci_ops = &schizo_ops; + pbm->pci_ops = &sun4u_pci_ops; + pbm->config_space_reg_bits = 8; pbm->index = pci_num_pbms++; diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 0c76a8891a9..34df4047587 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -593,89 +593,6 @@ const struct pci_iommu_ops pci_sun4v_iommu_ops = { .dma_sync_sg_for_cpu = pci_4v_dma_sync_sg_for_cpu, }; -static inline int pci_sun4v_out_of_range(struct pci_pbm_info *pbm, unsigned int bus, unsigned int device, unsigned int func) -{ - if (bus < pbm->pci_first_busno || - bus > pbm->pci_last_busno) - return 1; - return 0; -} - -static int pci_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 (pci_sun4v_out_of_range(pbm, bus, device, func)) { - ret = ~0UL; - } else { - ret = pci_sun4v_config_get(devhandle, - HV_PCI_DEVICE_BUILD(bus, device, func), - where, size); -#if 0 - printk("rcfg: [%x:%x:%x:%d]=[%lx]\n", - devhandle, HV_PCI_DEVICE_BUILD(bus, device, func), - where, size, ret); -#endif - } - 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 pci_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 (pci_sun4v_out_of_range(pbm, bus, device, func)) { - /* Do nothing. */ - } else { - ret = pci_sun4v_config_put(devhandle, - HV_PCI_DEVICE_BUILD(bus, device, func), - where, size, value); -#if 0 - printk("wcfg: [%x:%x:%x:%d] v[%x] == [%lx]\n", - devhandle, HV_PCI_DEVICE_BUILD(bus, device, func), - where, size, value, ret); -#endif - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops pci_sun4v_ops = { - .read = pci_sun4v_read_pci_cfg, - .write = pci_sun4v_write_pci_cfg, -}; - - static void pci_sun4v_scan_bus(struct pci_pbm_info *pbm) { struct property *prop; @@ -1238,7 +1155,8 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node pci_pbm_root = pbm; pbm->scan_bus = pci_sun4v_scan_bus; - pbm->pci_ops = &pci_sun4v_ops; + pbm->pci_ops = &sun4v_pci_ops; + pbm->config_space_reg_bits = 12; pbm->index = pci_num_pbms++; diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index c54d4d8af01..b7976b14d0b 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -1636,10 +1636,21 @@ static struct device_node * __init create_node(phandle node, struct device_node static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp) { + struct device_node *ret = NULL, *prev_sibling = NULL; struct device_node *dp; - dp = create_node(node, parent); - if (dp) { + while (1) { + dp = create_node(node, parent); + if (!dp) + break; + + if (prev_sibling) + prev_sibling->sibling = dp; + + if (!ret) + ret = dp; + prev_sibling = dp; + *(*nextp) = dp; *nextp = &dp->allnext; @@ -1648,10 +1659,10 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl dp->child = build_tree(dp, prom_getchild(node), nextp); - dp->sibling = build_tree(parent, prom_getsibling(node), nextp); + node = prom_getsibling(node); } - return dp; + return ret; } void __init prom_build_devicetree(void) diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index da73205e54c..0985193dc57 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -92,6 +92,8 @@ struct uart_sunzilog_port { #define SUNZILOG_FLAG_REGS_HELD 0x00000040 #define SUNZILOG_FLAG_TX_STOPPED 0x00000080 #define SUNZILOG_FLAG_TX_ACTIVE 0x00000100 +#define SUNZILOG_FLAG_ESCC 0x00000200 +#define SUNZILOG_FLAG_ISR_HANDLER 0x00000400 unsigned int cflag; @@ -174,9 +176,11 @@ static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel) /* This function must only be called when the TX is not busy. The UART * port lock must be held and local interrupts disabled. */ -static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs) +static int __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs) { int i; + int escc; + unsigned char r15; /* Let pending transmits finish. */ for (i = 0; i < 1000; i++) { @@ -229,11 +233,25 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char * write_zsreg(channel, R14, regs[R14]); /* External status interrupt control. */ - write_zsreg(channel, R15, regs[R15]); + write_zsreg(channel, R15, (regs[R15] | WR7pEN) & ~FIFOEN); + + /* ESCC Extension Register */ + r15 = read_zsreg(channel, R15); + if (r15 & 0x01) { + write_zsreg(channel, R7, regs[R7p]); + + /* External status interrupt and FIFO control. */ + write_zsreg(channel, R15, regs[R15] & ~WR7pEN); + escc = 1; + } else { + /* Clear FIFO bit case it is an issue */ + regs[R15] &= ~FIFOEN; + escc = 0; + } /* Reset external status interrupts. */ - write_zsreg(channel, R0, RES_EXT_INT); - write_zsreg(channel, R0, RES_EXT_INT); + write_zsreg(channel, R0, RES_EXT_INT); /* First Latch */ + write_zsreg(channel, R0, RES_EXT_INT); /* Second Latch */ /* Rewrite R3/R5, this time without enables masked. */ write_zsreg(channel, R3, regs[R3]); @@ -241,6 +259,8 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char * /* Rewrite R1, this time without IRQ enabled masked. */ write_zsreg(channel, R1, regs[R1]); + + return escc; } /* Reprogram the Zilog channel HW registers with the copies found in the @@ -731,7 +751,7 @@ static void sunzilog_enable_ms(struct uart_port *port) up->curregs[R15] = new_reg; /* NOTE: Not subject to 'transmitter active' rule. */ - write_zsreg(channel, R15, up->curregs[R15]); + write_zsreg(channel, R15, up->curregs[R15] & ~WR7pEN); } } @@ -861,44 +881,44 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, up->curregs[R14] = BRSRC | BRENAB; /* Character size, stop bits, and parity. */ - up->curregs[3] &= ~RxN_MASK; - up->curregs[5] &= ~TxN_MASK; + up->curregs[R3] &= ~RxN_MASK; + up->curregs[R5] &= ~TxN_MASK; switch (cflag & CSIZE) { case CS5: - up->curregs[3] |= Rx5; - up->curregs[5] |= Tx5; + up->curregs[R3] |= Rx5; + up->curregs[R5] |= Tx5; up->parity_mask = 0x1f; break; case CS6: - up->curregs[3] |= Rx6; - up->curregs[5] |= Tx6; + up->curregs[R3] |= Rx6; + up->curregs[R5] |= Tx6; up->parity_mask = 0x3f; break; case CS7: - up->curregs[3] |= Rx7; - up->curregs[5] |= Tx7; + up->curregs[R3] |= Rx7; + up->curregs[R5] |= Tx7; up->parity_mask = 0x7f; break; case CS8: default: - up->curregs[3] |= Rx8; - up->curregs[5] |= Tx8; + up->curregs[R3] |= Rx8; + up->curregs[R5] |= Tx8; up->parity_mask = 0xff; break; }; - up->curregs[4] &= ~0x0c; + up->curregs[R4] &= ~0x0c; if (cflag & CSTOPB) - up->curregs[4] |= SB2; + up->curregs[R4] |= SB2; else - up->curregs[4] |= SB1; + up->curregs[R4] |= SB1; if (cflag & PARENB) - up->curregs[4] |= PAR_ENAB; + up->curregs[R4] |= PAR_ENAB; else - up->curregs[4] &= ~PAR_ENAB; + up->curregs[R4] &= ~PAR_ENAB; if (!(cflag & PARODD)) - up->curregs[4] |= PAR_EVEN; + up->curregs[R4] |= PAR_EVEN; else - up->curregs[4] &= ~PAR_EVEN; + up->curregs[R4] &= ~PAR_EVEN; up->port.read_status_mask = Rx_OVR; if (iflag & INPCK) @@ -952,7 +972,9 @@ sunzilog_set_termios(struct uart_port *port, struct ktermios *termios, static const char *sunzilog_type(struct uart_port *port) { - return "zs"; + struct uart_sunzilog_port *up = UART_ZILOG(port); + + return (up->flags & SUNZILOG_FLAG_ESCC) ? "zs (ESCC)" : "zs"; } /* We do not request/release mappings of the registers here, this @@ -1170,7 +1192,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options) spin_lock_irqsave(&up->port.lock, flags); - up->curregs[R15] = BRKIE; + up->curregs[R15] |= BRKIE; sunzilog_convert_to_zs(up, con->cflag, 0, brg); sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); @@ -1229,7 +1251,7 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe baud = 4800; } - up->curregs[R15] = BRKIE; + up->curregs[R15] |= BRKIE; brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); sunzilog_convert_to_zs(up, up->cflag, 0, brg); sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); @@ -1283,8 +1305,18 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) if (up->flags & (SUNZILOG_FLAG_CONS_KEYB | SUNZILOG_FLAG_CONS_MOUSE)) { + up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; + up->curregs[R4] = PAR_EVEN | X16CLK | SB1; + up->curregs[R3] = RxENAB | Rx8; + up->curregs[R5] = TxENAB | Tx8; + up->curregs[R6] = 0x00; /* SDLC Address */ + up->curregs[R7] = 0x7E; /* SDLC Flag */ + up->curregs[R9] = NV; + up->curregs[R7p] = 0x00; sunzilog_init_kbdms(up, up->port.line); - up->curregs[R9] |= (NV | MIE); + /* Only enable interrupts if an ISR handler available */ + if (up->flags & SUNZILOG_FLAG_ISR_HANDLER) + up->curregs[R9] |= MIE; write_zsreg(channel, R9, up->curregs[R9]); } else { /* Normal serial TTY. */ @@ -1293,7 +1325,9 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) up->curregs[R4] = PAR_EVEN | X16CLK | SB1; up->curregs[R3] = RxENAB | Rx8; up->curregs[R5] = TxENAB | Tx8; - up->curregs[R9] = NV | MIE; + up->curregs[R6] = 0x00; /* SDLC Address */ + up->curregs[R7] = 0x7E; /* SDLC Flag */ + up->curregs[R9] = NV; up->curregs[R10] = NRZ; up->curregs[R11] = TCBR | RCBR; baud = 9600; @@ -1301,7 +1335,14 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) up->curregs[R12] = (brg & 0xff); up->curregs[R13] = (brg >> 8) & 0xff; up->curregs[R14] = BRSRC | BRENAB; - __load_zsregs(channel, up->curregs); + up->curregs[R15] = FIFOEN; /* Use FIFO if on ESCC */ + up->curregs[R7p] = TxFIFO_LVL | RxFIFO_LVL; + if (__load_zsregs(channel, up->curregs)) { + up->flags |= SUNZILOG_FLAG_ESCC; + } + /* Only enable interrupts if an ISR handler available */ + if (up->flags & SUNZILOG_FLAG_ISR_HANDLER) + up->curregs[R9] |= MIE; write_zsreg(channel, R9, up->curregs[R9]); } @@ -1390,12 +1431,14 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m return err; } } else { - printk(KERN_INFO "%s: Keyboard at MMIO %lx (irq = %d) " - "is a zs\n", - op->dev.bus_id, up[0].port.mapbase, op->irqs[0]); - printk(KERN_INFO "%s: Mouse at MMIO %lx (irq = %d) " - "is a zs\n", - op->dev.bus_id, up[1].port.mapbase, op->irqs[0]); + printk(KERN_INFO "%s: Keyboard at MMIO 0x%lx (irq = %d) " + "is a %s\n", + op->dev.bus_id, up[0].port.mapbase, op->irqs[0], + sunzilog_type (&up[0].port)); + printk(KERN_INFO "%s: Mouse at MMIO 0x%lx (irq = %d) " + "is a %s\n", + op->dev.bus_id, up[1].port.mapbase, op->irqs[0], + sunzilog_type (&up[1].port)); } dev_set_drvdata(&op->dev, &up[0]); @@ -1487,10 +1530,23 @@ static int __init sunzilog_init(void) goto out_unregister_uart; if (zilog_irq != -1) { + struct uart_sunzilog_port *up = sunzilog_irq_chain; err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED, "zs", sunzilog_irq_chain); if (err) goto out_unregister_driver; + + /* Enable Interrupts */ + while (up) { + struct zilog_channel __iomem *channel; + + /* printk (KERN_INFO "Enable IRQ for ZILOG Hardware %p\n", up); */ + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + up->flags |= SUNZILOG_FLAG_ISR_HANDLER; + up->curregs[R9] |= MIE; + write_zsreg(channel, R9, up->curregs[R9]); + up = up->next; + } } out: @@ -1515,6 +1571,20 @@ static void __exit sunzilog_exit(void) of_unregister_driver(&zs_driver); if (zilog_irq != -1) { + struct uart_sunzilog_port *up = sunzilog_irq_chain; + + /* Disable Interrupts */ + while (up) { + struct zilog_channel __iomem *channel; + + /* printk (KERN_INFO "Disable IRQ for ZILOG Hardware %p\n", up); */ + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + up->flags &= ~SUNZILOG_FLAG_ISR_HANDLER; + up->curregs[R9] &= ~MIE; + write_zsreg(channel, R9, up->curregs[R9]); + up = up->next; + } + free_irq(zilog_irq, sunzilog_irq_chain); zilog_irq = -1; } diff --git a/drivers/serial/sunzilog.h b/drivers/serial/sunzilog.h index 7939b6d7127..5dec7b47cc3 100644 --- a/drivers/serial/sunzilog.h +++ b/drivers/serial/sunzilog.h @@ -13,7 +13,8 @@ struct zilog_layout { struct zilog_channel channelA; }; -#define NUM_ZSREGS 16 +#define NUM_ZSREGS 17 +#define R7p 16 /* Written as R7 with P15 bit 0 set */ /* Conversion routines to/from brg time constants from/to bits * per second. @@ -127,6 +128,15 @@ struct zilog_layout { /* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ +/* Write Register 7' (ESCC Only) */ +#define AUTO_TxFLAG 1 /* Automatic Tx SDLC Flag */ +#define AUTO_EOM_RST 2 /* Automatic EOM Reset */ +#define AUTOnRTS 4 /* Automatic /RTS pin deactivation */ +#define RxFIFO_LVL 8 /* Receive FIFO interrupt level */ +#define nDTRnREQ 0x10 /* /DTR/REQ timing */ +#define TxFIFO_LVL 0x20 /* Transmit FIFO interrupt level */ +#define EXT_RD_EN 0x40 /* Extended read register enable */ + /* Write Register 8 (transmit buffer) */ /* Write Register 9 (Master interrupt control) */ @@ -135,6 +145,7 @@ struct zilog_layout { #define DLC 4 /* Disable Lower Chain */ #define MIE 8 /* Master Interrupt Enable */ #define STATHI 0x10 /* Status high */ +#define SWIACK 0x20 /* Software Interrupt Ack (not on NMOS) */ #define NORESET 0 /* No reset on write to R9 */ #define CHRB 0x40 /* Reset channel B */ #define CHRA 0x80 /* Reset channel A */ @@ -187,7 +198,9 @@ struct zilog_layout { #define SNRZI 0xe0 /* Set NRZI mode */ /* Write Register 15 (external/status interrupt control) */ +#define WR7pEN 1 /* WR7' Enable (ESCC only) */ #define ZCIE 2 /* Zero count IE */ +#define FIFOEN 4 /* FIFO Enable (ESCC only) */ #define DCDIE 8 /* DCD IE */ #define SYNCIE 0x10 /* Sync/hunt IE */ #define CTSIE 0x20 /* CTS IE */ @@ -241,6 +254,10 @@ struct zilog_layout { #define CHATxIP 0x10 /* Channel A Tx IP */ #define CHARxIP 0x20 /* Channel A Rx IP */ +/* Read Register 6 (LSB frame byte count [Not on NMOS]) */ + +/* Read Register 7 (MSB frame byte count and FIFO status [Not on NMOS]) */ + /* Read Register 8 (receive data register) */ /* Read Register 10 (misc status bits) */ diff --git a/include/asm-sparc64/openprom.h b/include/asm-sparc64/openprom.h index e01b80559c9..26ec046715c 100644 --- a/include/asm-sparc64/openprom.h +++ b/include/asm-sparc64/openprom.h @@ -177,7 +177,7 @@ struct linux_nodeops { /* More fun PROM structures for device probing. */ #define PROMREG_MAX 24 #define PROMVADDR_MAX 16 -#define PROMINTR_MAX 15 +#define PROMINTR_MAX 32 struct linux_prom_registers { unsigned which_io; /* hi part of physical address */