Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc

* git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (36 commits)
  [POWERPC] Generic BUG for powerpc
  [PPC] Fix compile failure do to introduction of PHY_POLL
  [POWERPC] Only export __mtdcr/__mfdcr if CONFIG_PPC_DCR is set
  [POWERPC] Remove old dcr.S
  [POWERPC] Fix SPU coredump code for max_fdset removal
  [POWERPC] Fix irq routing on some 32-bit PowerMacs
  [POWERPC] ps3: Add vuart support
  [POWERPC] Support ibm,dynamic-reconfiguration-memory nodes
  [POWERPC] dont allow pSeries_probe to succeed without initialising MMU
  [POWERPC] micro optimise pSeries_probe
  [POWERPC] Add SPURR SPR to sysfs
  [POWERPC] Add DSCR SPR to sysfs
  [POWERPC] Fix 440SPe CPU table entry
  [POWERPC] Add support for FP emulation for the e300c2 core
  [POWERPC] of_device_register: propagate device_create_file return code
  [POWERPC] Fix mmap of PCI resource with hack for X
  [POWERPC] iSeries: head_64.o needs to depend on lparmap.s
  [POWERPC] cbe_thermal: Fix initialization of sysfs attribute_group
  [POWERPC] Remove QE header files from lite5200.c
  [POWERPC] of_platform_make_bus_id(): make `magic' int
  ...
This commit is contained in:
Linus Torvalds 2006-12-11 18:24:58 -08:00
commit 13d7d84e07
56 changed files with 1884 additions and 631 deletions

View File

@ -107,6 +107,11 @@ config AUDIT_ARCH
bool
default y
config GENERIC_BUG
bool
default y
depends on BUG
config DEFAULT_UIMAGE
bool
help
@ -478,6 +483,7 @@ config PPC_MAPLE
select PPC_UDBG_16550
select PPC_970_NAP
select PPC_NATIVE
select PPC_RTAS
default n
help
This option enables support for the Maple 970FX Evaluation Board.
@ -714,7 +720,7 @@ config FORCE_MAX_ZONEORDER
config MATH_EMULATION
bool "Math emulation"
depends on 4xx || 8xx || E200 || E500
depends on 4xx || 8xx || E200 || PPC_83xx || E500
---help---
Some PowerPC chips designed for embedded applications do not have
a floating-point unit and therefore do not implement the

View File

@ -157,6 +157,7 @@ CONFIG_SPU_BASE=y
CONFIG_PS3_HTAB_SIZE=20
CONFIG_PS3_DYNAMIC_DMA=y
CONFIG_PS3_USE_LPAR_ADDR=y
CONFIG_PS3_VUART=y
#
# Kernel options

View File

@ -77,6 +77,7 @@ endif
ifeq ($(CONFIG_PPC_ISERIES),y)
extra-y += lparmap.s
$(obj)/head_64.o: $(obj)/lparmap.s
AFLAGS_head_64.o += -I$(obj)
endif

View File

@ -833,7 +833,7 @@ static struct cpu_spec cpu_specs[] = {
.pvr_mask = 0x7fff0000,
.pvr_value = 0x00840000,
.cpu_name = "e300c2",
.cpu_features = CPU_FTRS_E300,
.cpu_features = CPU_FTRS_E300C2,
.cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
.icache_bsize = 32,
.dcache_bsize = 32,
@ -1136,8 +1136,7 @@ static struct cpu_spec cpu_specs[] = {
.pvr_mask = 0xff000fff,
.pvr_value = 0x53000890,
.cpu_name = "440SPe Rev. A",
.cpu_features = CPU_FTR_SPLIT_ID_CACHE |
CPU_FTR_USE_TB,
.cpu_features = CPU_FTRS_44X,
.cpu_user_features = COMMON_USER_BOOKE,
.icache_bsize = 32,
.dcache_bsize = 32,

View File

@ -437,6 +437,13 @@ Alignment:
/* Floating-point unavailable */
. = 0x800
FPUnavailable:
BEGIN_FTR_SECTION
/*
* Certain Freescale cores don't have a FPU and treat fp instructions
* as a FP Unavailable exception. Redirect to illegal/emulation handling.
*/
b ProgramCheck
END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE)
EXCEPTION_PROLOG
bne load_up_fpu /* if from user, just load it up */
addi r3,r1,STACK_FRAME_OVERHEAD

View File

@ -23,6 +23,7 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/cache.h>
#include <linux/bug.h>
#include "setup.h"
@ -290,23 +291,11 @@ int module_finalize(const Elf_Ehdr *hdr,
struct module *me)
{
const Elf_Shdr *sect;
int err;
me->arch.bug_table = NULL;
me->arch.num_bugs = 0;
/* Find the __bug_table section, if present */
sect = find_section(hdr, sechdrs, "__bug_table");
if (sect != NULL) {
me->arch.bug_table = (void *) sect->sh_addr;
me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry);
}
/*
* Strictly speaking this should have a spinlock to protect against
* traversals, but since we only traverse on BUG()s, a spinlock
* could potentially lead to deadlock and thus be counter-productive.
*/
list_add(&me->arch.bug_list, &module_bug_list);
err = module_bug_finalize(hdr, sechdrs, me);
if (err) /* never true, currently */
return err;
/* Apply feature fixups */
sect = find_section(hdr, sechdrs, "__ftr_fixup");
@ -320,7 +309,7 @@ int module_finalize(const Elf_Ehdr *hdr,
void module_arch_cleanup(struct module *mod)
{
list_del(&mod->arch.bug_list);
module_bug_cleanup(mod);
}
struct bug_entry *module_find_bug(unsigned long bugaddr)

View File

@ -20,6 +20,7 @@
#include <linux/moduleloader.h>
#include <linux/err.h>
#include <linux/vmalloc.h>
#include <linux/bug.h>
#include <asm/module.h>
#include <asm/uaccess.h>
#include <asm/firmware.h>
@ -439,23 +440,11 @@ int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs, struct module *me)
{
const Elf_Shdr *sect;
int err;
me->arch.bug_table = NULL;
me->arch.num_bugs = 0;
/* Find the __bug_table section, if present */
sect = find_section(hdr, sechdrs, "__bug_table");
if (sect != NULL) {
me->arch.bug_table = (void *) sect->sh_addr;
me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry);
}
/*
* Strictly speaking this should have a spinlock to protect against
* traversals, but since we only traverse on BUG()s, a spinlock
* could potentially lead to deadlock and thus be counter-productive.
*/
list_add(&me->arch.bug_list, &module_bug_list);
err = module_bug_finalize(hdr, sechdrs, me);
if (err)
return err;
/* Apply feature fixups */
sect = find_section(hdr, sechdrs, "__ftr_fixup");
@ -475,7 +464,7 @@ int module_finalize(const Elf_Ehdr *hdr,
void module_arch_cleanup(struct module *mod)
{
list_del(&mod->arch.bug_list);
module_bug_cleanup(mod);
}
struct bug_entry *module_find_bug(unsigned long bugaddr)

View File

@ -109,9 +109,7 @@ int of_device_register(struct of_device *ofdev)
if (rc)
return rc;
device_create_file(&ofdev->dev, &dev_attr_devspec);
return 0;
return device_create_file(&ofdev->dev, &dev_attr_devspec);
}
void of_device_unregister(struct of_device *ofdev)

View File

@ -169,7 +169,7 @@ static void of_platform_make_bus_id(struct of_device *dev)
char *name = dev->dev.bus_id;
const u32 *reg;
u64 addr;
long magic;
int magic;
/*
* If it's a DCR based device, use 'd' for native DCRs

View File

@ -736,25 +736,51 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void*
return NULL;
}
static int
scan_OF_pci_childs_iterator(struct device_node* node, void* data)
static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,
unsigned int devfn)
{
const unsigned int *reg;
u8* fdata = (u8*)data;
reg = get_property(node, "reg", NULL);
if (reg && ((reg[0] >> 8) & 0xff) == fdata[1]
&& ((reg[0] >> 16) & 0xff) == fdata[0])
return 1;
return 0;
struct device_node *np = NULL;
const u32 *reg;
unsigned int psize;
while ((np = of_get_next_child(parent, np)) != NULL) {
reg = get_property(np, "reg", &psize);
if (reg == NULL || psize < 4)
continue;
if (((reg[0] >> 8) & 0xff) == devfn)
return np;
}
return NULL;
}
static struct device_node*
scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn)
{
u8 filter_data[2] = {bus, dev_fn};
return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data);
static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus)
{
struct device_node *parent, *np;
/* Are we a root bus ? */
if (bus->self == NULL || bus->parent == NULL) {
struct pci_controller *hose = pci_bus_to_hose(bus->number);
if (hose == NULL)
return NULL;
return of_node_get(hose->arch_data);
}
/* not a root bus, we need to get our parent */
parent = scan_OF_for_pci_bus(bus->parent);
if (parent == NULL)
return NULL;
/* now iterate for children for a match */
np = scan_OF_for_pci_dev(parent, bus->self->devfn);
of_node_put(parent);
/* sanity check */
if (strcmp(np->type, "pci") != 0)
printk(KERN_WARNING "pci: wrong type \"%s\" for bridge %s\n",
np->type, np->full_name);
return np;
}
/*
@ -763,43 +789,25 @@ scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn)
struct device_node *
pci_busdev_to_OF_node(struct pci_bus *bus, int devfn)
{
struct pci_controller *hose;
struct device_node *node;
int busnr;
struct device_node *parent, *np;
if (!have_of)
return NULL;
/* Lookup the hose */
busnr = bus->number;
hose = pci_bus_to_hose(busnr);
if (!hose)
return NULL;
/* Check it has an OF node associated */
node = (struct device_node *) hose->arch_data;
if (!node)
DBG("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn);
parent = scan_OF_for_pci_bus(bus);
if (parent == NULL)
return NULL;
DBG(" parent is %s\n", parent ? parent->full_name : "<NULL>");
np = scan_OF_for_pci_dev(parent, devfn);
of_node_put(parent);
DBG(" result is %s\n", np ? np->full_name : "<NULL>");
/* Fixup bus number according to what OF think it is. */
#ifdef CONFIG_PPC_PMAC
/* The G5 need a special case here. Basically, we don't remap all
* busses on it so we don't create the pci-OF-map. However, we do
* remap the AGP bus and so have to deal with it. A future better
* fix has to be done by making the remapping per-host and always
* filling the pci_to_OF map. --BenH
/* XXX most callers don't release the returned node
* mostly because ppc64 doesn't increase the refcount,
* we need to fix that.
*/
if (machine_is(powermac) && busnr >= 0xf0)
busnr -= 0xf0;
else
#endif
if (pci_to_OF_bus_map)
busnr = pci_to_OF_bus_map[busnr];
if (busnr == 0xff)
return NULL;
/* Now, lookup childs of the hose */
return scan_OF_childs_for_device(node->child, busnr, devfn);
return np;
}
EXPORT_SYMBOL(pci_busdev_to_OF_node);
@ -1544,7 +1552,7 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res)
static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
unsigned long *offset,
resource_size_t *offset,
enum pci_mmap_state mmap_state)
{
struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
@ -1556,7 +1564,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
/* If memory, add on the PCI bridge address offset */
if (mmap_state == pci_mmap_mem) {
#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
*offset += hose->pci_mem_offset;
#endif
res_bit = IORESOURCE_MEM;
} else {
io_offset = hose->io_base_virt - (void __iomem *)_IO_BASE;
@ -1624,9 +1634,6 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
else
prot |= _PAGE_GUARDED;
printk("PCI map for %s:%llx, prot: %lx\n", pci_name(dev),
(unsigned long long)rp->start, prot);
return __pgprot(prot);
}
@ -1695,7 +1702,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state,
int write_combine)
{
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
struct resource *rp;
int ret;
@ -1808,22 +1815,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
resource_size_t *start, resource_size_t *end)
{
struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
unsigned long offset = 0;
resource_size_t offset = 0;
if (hose == NULL)
return;
if (rsrc->flags & IORESOURCE_IO)
offset = (void __iomem *)_IO_BASE - hose->io_base_virt
+ hose->io_base_phys;
offset = (unsigned long)hose->io_base_virt - _IO_BASE;
*start = rsrc->start + offset;
*end = rsrc->end + offset;
/* We pass a fully fixed up address to userland for MMIO instead of
* a BAR value because X is lame and expects to be able to use that
* to pass to /dev/mem !
*
* That means that we'll have potentially 64 bits values where some
* userland apps only expect 32 (like X itself since it thinks only
* Sparc has 64 bits MMIO) but if we don't do that, we break it on
* 32 bits CHRPs :-(
*
* Hopefully, the sysfs insterface is immune to that gunk. Once X
* has been fixed (and the fix spread enough), we can re-enable the
* 2 lines below and pass down a BAR value to userland. In that case
* we'll also have to re-enable the matching code in
* __pci_mmap_make_offset().
*
* BenH.
*/
#if 0
else if (rsrc->flags & IORESOURCE_MEM)
offset = hose->pci_mem_offset;
#endif
*start = rsrc->start - offset;
*end = rsrc->end - offset;
}
void __init
pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
int flags, char *name)
void __init pci_init_resource(struct resource *res, resource_size_t start,
resource_size_t end, int flags, char *name)
{
res->start = start;
res->end = end;

View File

@ -682,7 +682,7 @@ int pci_proc_domain(struct pci_bus *bus)
* Returns negative error code on failure, zero on success.
*/
static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
unsigned long *offset,
resource_size_t *offset,
enum pci_mmap_state mmap_state)
{
struct pci_controller *hose = pci_bus_to_host(dev->bus);
@ -694,7 +694,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
/* If memory, add on the PCI bridge address offset */
if (mmap_state == pci_mmap_mem) {
#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
*offset += hose->pci_mem_offset;
#endif
res_bit = IORESOURCE_MEM;
} else {
io_offset = (unsigned long)hose->io_base_virt - pci_io_base;
@ -762,9 +764,6 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
else
prot |= _PAGE_GUARDED;
printk(KERN_DEBUG "PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
prot);
return __pgprot(prot);
}
@ -832,7 +831,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
struct resource *rp;
int ret;
@ -1333,20 +1332,41 @@ EXPORT_SYMBOL(pci_read_irq_line);
void pci_resource_to_user(const struct pci_dev *dev, int bar,
const struct resource *rsrc,
u64 *start, u64 *end)
resource_size_t *start, resource_size_t *end)
{
struct pci_controller *hose = pci_bus_to_host(dev->bus);
unsigned long offset = 0;
resource_size_t offset = 0;
if (hose == NULL)
return;
if (rsrc->flags & IORESOURCE_IO)
offset = pci_io_base - (unsigned long)hose->io_base_virt +
hose->io_base_phys;
offset = (unsigned long)hose->io_base_virt - pci_io_base;
*start = rsrc->start + offset;
*end = rsrc->end + offset;
/* We pass a fully fixed up address to userland for MMIO instead of
* a BAR value because X is lame and expects to be able to use that
* to pass to /dev/mem !
*
* That means that we'll have potentially 64 bits values where some
* userland apps only expect 32 (like X itself since it thinks only
* Sparc has 64 bits MMIO) but if we don't do that, we break it on
* 32 bits CHRPs :-(
*
* Hopefully, the sysfs insterface is immune to that gunk. Once X
* has been fixed (and the fix spread enough), we can re-enable the
* 2 lines below and pass down a BAR value to userland. In that case
* we'll also have to re-enable the matching code in
* __pci_mmap_make_offset().
*
* BenH.
*/
#if 0
else if (rsrc->flags & IORESOURCE_MEM)
offset = hose->pci_mem_offset;
#endif
*start = rsrc->start - offset;
*end = rsrc->end - offset;
}
struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)

View File

@ -208,7 +208,7 @@ EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */
extern long *intercept_table;
EXPORT_SYMBOL(intercept_table);
#endif /* CONFIG_PPC_STD_MMU_32 */
#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
#ifdef CONFIG_PPC_DCR_NATIVE
EXPORT_SYMBOL(__mtdcr);
EXPORT_SYMBOL(__mfdcr);
#endif

View File

@ -804,6 +804,56 @@ static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp)
return of_read_ulong(p, s);
}
#ifdef CONFIG_PPC_PSERIES
/*
* Interpret the ibm,dynamic-memory property in the
* /ibm,dynamic-reconfiguration-memory node.
* This contains a list of memory blocks along with NUMA affinity
* information.
*/
static int __init early_init_dt_scan_drconf_memory(unsigned long node)
{
cell_t *dm, *ls;
unsigned long l, n;
unsigned long base, size, lmb_size, flags;
ls = (cell_t *)of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t))
return 0;
lmb_size = dt_mem_next_cell(dt_root_size_cells, &ls);
dm = (cell_t *)of_get_flat_dt_prop(node, "ibm,dynamic-memory", &l);
if (dm == NULL || l < sizeof(cell_t))
return 0;
n = *dm++; /* number of entries */
if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t))
return 0;
for (; n != 0; --n) {
base = dt_mem_next_cell(dt_root_addr_cells, &dm);
flags = dm[3];
/* skip DRC index, pad, assoc. list index, flags */
dm += 4;
/* skip this block if the reserved bit is set in flags (0x80)
or if the block is not assigned to this partition (0x8) */
if ((flags & 0x80) || !(flags & 0x8))
continue;
size = lmb_size;
if (iommu_is_off) {
if (base >= 0x80000000ul)
continue;
if ((base + size) > 0x80000000ul)
size = 0x80000000ul - base;
}
lmb_add(base, size);
}
lmb_dump_all();
return 0;
}
#else
#define early_init_dt_scan_drconf_memory(node) 0
#endif /* CONFIG_PPC_PSERIES */
static int __init early_init_dt_scan_memory(unsigned long node,
const char *uname, int depth, void *data)
@ -812,6 +862,11 @@ static int __init early_init_dt_scan_memory(unsigned long node,
cell_t *reg, *endp;
unsigned long l;
/* Look for the ibm,dynamic-reconfiguration-memory node */
if (depth == 1 &&
strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0)
return early_init_dt_scan_drconf_memory(node);
/* We are scanning "memory" nodes only */
if (type == NULL) {
/*

View File

@ -679,7 +679,7 @@ static unsigned char ibm_architecture_vec[] = {
/* option vector 5: PAPR/OF options */
3 - 2, /* length */
0, /* don't ignore, don't halt */
OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES,
OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY,
};
/* Old method - ELF header with PT_NOTE sections */

View File

@ -303,6 +303,12 @@ int rtas_token(const char *service)
}
EXPORT_SYMBOL(rtas_token);
int rtas_service_present(const char *service)
{
return rtas_token(service) != RTAS_UNKNOWN_SERVICE;
}
EXPORT_SYMBOL(rtas_service_present);
#ifdef CONFIG_RTAS_ERROR_LOGGING
/*
* Return the firmware-specified size of the error log buffer
@ -810,32 +816,6 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
return 0;
}
#ifdef CONFIG_HOTPLUG_CPU
/* This version can't take the spinlock, because it never returns */
static struct rtas_args rtas_stop_self_args = {
/* The token is initialized for real in setup_system() */
.token = RTAS_UNKNOWN_SERVICE,
.nargs = 0,
.nret = 1,
.rets = &rtas_stop_self_args.args[0],
};
void rtas_stop_self(void)
{
struct rtas_args *rtas_args = &rtas_stop_self_args;
local_irq_disable();
BUG_ON(rtas_args->token == RTAS_UNKNOWN_SERVICE);
printk("cpu %u (hwid %u) Ready to die...\n",
smp_processor_id(), hard_smp_processor_id());
enter_rtas(__pa(rtas_args));
panic("Alas, I survived.\n");
}
#endif
/*
* Call early during boot, before mem init or bootmem, to retrieve the RTAS
* informations from the device-tree and allocate the RMO buffer for userland
@ -880,9 +860,6 @@ void __init rtas_initialize(void)
#endif
rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region);
#ifdef CONFIG_HOTPLUG_CPU
rtas_stop_self_args.token = rtas_token("stop-self");
#endif /* CONFIG_HOTPLUG_CPU */
#ifdef CONFIG_RTAS_ERROR_LOGGING
rtas_last_error_token = rtas_token("rtas-last-error");
#endif

View File

@ -181,6 +181,8 @@ SYSFS_PMCSETUP(pmc6, SPRN_PMC6);
SYSFS_PMCSETUP(pmc7, SPRN_PMC7);
SYSFS_PMCSETUP(pmc8, SPRN_PMC8);
SYSFS_PMCSETUP(purr, SPRN_PURR);
SYSFS_PMCSETUP(spurr, SPRN_SPURR);
SYSFS_PMCSETUP(dscr, SPRN_DSCR);
static SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0);
static SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1);
@ -194,6 +196,8 @@ static SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6);
static SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7);
static SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8);
static SYSDEV_ATTR(purr, 0600, show_purr, NULL);
static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL);
static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr);
static void register_cpu_online(unsigned int cpu)
{
@ -231,6 +235,12 @@ static void register_cpu_online(unsigned int cpu)
if (cpu_has_feature(CPU_FTR_PURR))
sysdev_create_file(s, &attr_purr);
if (cpu_has_feature(CPU_FTR_SPURR))
sysdev_create_file(s, &attr_spurr);
if (cpu_has_feature(CPU_FTR_DSCR))
sysdev_create_file(s, &attr_dscr);
}
#ifdef CONFIG_HOTPLUG_CPU
@ -272,6 +282,12 @@ static void unregister_cpu_online(unsigned int cpu)
if (cpu_has_feature(CPU_FTR_PURR))
sysdev_remove_file(s, &attr_purr);
if (cpu_has_feature(CPU_FTR_SPURR))
sysdev_remove_file(s, &attr_spurr);
if (cpu_has_feature(CPU_FTR_DSCR))
sysdev_remove_file(s, &attr_dscr);
}
#endif /* CONFIG_HOTPLUG_CPU */

View File

@ -32,6 +32,7 @@
#include <linux/kprobes.h>
#include <linux/kexec.h>
#include <linux/backlight.h>
#include <linux/bug.h>
#include <asm/kdebug.h>
#include <asm/pgtable.h>
@ -727,54 +728,9 @@ static int emulate_instruction(struct pt_regs *regs)
return -EINVAL;
}
/*
* Look through the list of trap instructions that are used for BUG(),
* BUG_ON() and WARN_ON() and see if we hit one. At this point we know
* that the exception was caused by a trap instruction of some kind.
* Returns 1 if we should continue (i.e. it was a WARN_ON) or 0
* otherwise.
*/
extern struct bug_entry __start___bug_table[], __stop___bug_table[];
#ifndef CONFIG_MODULES
#define module_find_bug(x) NULL
#endif
struct bug_entry *find_bug(unsigned long bugaddr)
int is_valid_bugaddr(unsigned long addr)
{
struct bug_entry *bug;
for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
if (bugaddr == bug->bug_addr)
return bug;
return module_find_bug(bugaddr);
}
static int check_bug_trap(struct pt_regs *regs)
{
struct bug_entry *bug;
unsigned long addr;
if (regs->msr & MSR_PR)
return 0; /* not in kernel */
addr = regs->nip; /* address of trap instruction */
if (addr < PAGE_OFFSET)
return 0;
bug = find_bug(regs->nip);
if (bug == NULL)
return 0;
if (bug->line & BUG_WARNING_TRAP) {
/* this is a WARN_ON rather than BUG/BUG_ON */
printk(KERN_ERR "Badness in %s at %s:%ld\n",
bug->function, bug->file,
bug->line & ~BUG_WARNING_TRAP);
dump_stack();
return 1;
}
printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n",
bug->function, bug->file, bug->line);
return 0;
return is_kernel_addr(addr);
}
void __kprobes program_check_exception(struct pt_regs *regs)
@ -782,6 +738,8 @@ void __kprobes program_check_exception(struct pt_regs *regs)
unsigned int reason = get_reason(regs);
extern int do_mathemu(struct pt_regs *regs);
/* We can now get here via a FP Unavailable exception if the core
* has no FPU, in that case no reason flags will be set */
#ifdef CONFIG_MATH_EMULATION
/* (reason & REASON_ILLEGAL) would be the obvious thing here,
* but there seems to be a hardware bug on the 405GP (RevD)
@ -808,7 +766,9 @@ void __kprobes program_check_exception(struct pt_regs *regs)
return;
if (debugger_bpt(regs))
return;
if (check_bug_trap(regs)) {
if (!(regs->msr & MSR_PR) && /* not user-mode */
report_bug(regs->nip) == BUG_TRAP_TYPE_WARN) {
regs->nip += 4;
return;
}

View File

@ -62,11 +62,7 @@ SECTIONS
__stop___ex_table = .;
}
__bug_table : {
__start___bug_table = .;
*(__bug_table)
__stop___bug_table = .;
}
BUG_TABLE
/*
* Init sections discarded at runtime

View File

@ -295,6 +295,63 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start,
return lmb_end_of_DRAM() - start;
}
/*
* Extract NUMA information from the ibm,dynamic-reconfiguration-memory
* node. This assumes n_mem_{addr,size}_cells have been set.
*/
static void __init parse_drconf_memory(struct device_node *memory)
{
const unsigned int *lm, *dm, *aa;
unsigned int ls, ld, la;
unsigned int n, aam, aalen;
unsigned long lmb_size, size;
int nid, default_nid = 0;
unsigned int start, ai, flags;
lm = get_property(memory, "ibm,lmb-size", &ls);
dm = get_property(memory, "ibm,dynamic-memory", &ld);
aa = get_property(memory, "ibm,associativity-lookup-arrays", &la);
if (!lm || !dm || !aa ||
ls < sizeof(unsigned int) || ld < sizeof(unsigned int) ||
la < 2 * sizeof(unsigned int))
return;
lmb_size = read_n_cells(n_mem_size_cells, &lm);
n = *dm++; /* number of LMBs */
aam = *aa++; /* number of associativity lists */
aalen = *aa++; /* length of each associativity list */
if (ld < (n * (n_mem_addr_cells + 4) + 1) * sizeof(unsigned int) ||
la < (aam * aalen + 2) * sizeof(unsigned int))
return;
for (; n != 0; --n) {
start = read_n_cells(n_mem_addr_cells, &dm);
ai = dm[2];
flags = dm[3];
dm += 4;
/* 0x80 == reserved, 0x8 = assigned to us */
if ((flags & 0x80) || !(flags & 0x8))
continue;
nid = default_nid;
/* flags & 0x40 means associativity index is invalid */
if (min_common_depth > 0 && min_common_depth <= aalen &&
(flags & 0x40) == 0 && ai < aam) {
/* this is like of_node_to_nid_single */
nid = aa[ai * aalen + min_common_depth - 1];
if (nid == 0xffff || nid >= MAX_NUMNODES)
nid = default_nid;
}
node_set_online(nid);
size = numa_enforce_memory_limit(start, lmb_size);
if (!size)
continue;
add_active_range(nid, start >> PAGE_SHIFT,
(start >> PAGE_SHIFT) + (size >> PAGE_SHIFT));
}
}
static int __init parse_numa_properties(void)
{
struct device_node *cpu = NULL;
@ -385,6 +442,14 @@ new_range:
goto new_range;
}
/*
* Now do the same thing for each LMB listed in the ibm,dynamic-memory
* property in the ibm,dynamic-reconfiguration-memory node.
*/
memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
if (memory)
parse_drconf_memory(memory);
return 0;
}

View File

@ -40,8 +40,6 @@
#include <asm/prom.h>
#include <asm/udbg.h>
#include <sysdev/fsl_soc.h>
#include <asm/qe.h>
#include <asm/qe_ic.h>
#include <asm/of_platform.h>
#include <asm/mpc52xx.h>

View File

@ -115,6 +115,7 @@ static struct sysdev_attribute attr_spu_temperature = {
static struct attribute *spu_attributes[] = {
&attr_spu_temperature.attr,
NULL,
};
static struct attribute_group spu_attribute_group = {
@ -135,6 +136,7 @@ static struct sysdev_attribute attr_ppe_temperature1 = {
static struct attribute *ppe_attributes[] = {
&attr_ppe_temperature0.attr,
&attr_ppe_temperature1.attr,
NULL,
};
static struct attribute_group ppe_attribute_group = {

View File

@ -382,11 +382,14 @@ static irqreturn_t cbe_pm_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
int __init cbe_init_pm_irq(void)
static int __init cbe_init_pm_irq(void)
{
unsigned int irq;
int rc, node;
if (!machine_is(cell))
return 0;
for_each_node(node) {
irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI |
(node << IIC_IRQ_NODE_SHIFT));

View File

@ -147,7 +147,7 @@ static int spufs_arch_notes_size(void)
struct fdtable *fdt = files_fdtable(current->files);
int size = 0, fd;
for (fd = 0; fd < fdt->max_fdset && fd < fdt->max_fds; fd++) {
for (fd = 0; fd < fdt->max_fds; fd++) {
if (FD_ISSET(fd, fdt->open_fds)) {
struct file *file = fcheck(fd);

View File

@ -562,7 +562,7 @@ void __init maple_pci_init(void)
for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
if (np->name == NULL)
continue;
if (strcmp(np->name, "pci") == 0) {
if (!strcmp(np->name, "pci") || !strcmp(np->name, "pcie")) {
if (add_bridge(np) == 0)
of_node_get(np);
}

View File

@ -60,6 +60,7 @@
#include <asm/of_device.h>
#include <asm/lmb.h>
#include <asm/mpic.h>
#include <asm/rtas.h>
#include <asm/udbg.h>
#include "maple.h"
@ -166,6 +167,16 @@ struct smp_ops_t maple_smp_ops = {
};
#endif /* CONFIG_SMP */
static void __init maple_use_rtas_reboot_and_halt_if_present(void)
{
if (rtas_service_present("system-reboot") &&
rtas_service_present("power-off")) {
ppc_md.restart = rtas_restart;
ppc_md.power_off = rtas_power_off;
ppc_md.halt = rtas_halt;
}
}
void __init maple_setup_arch(void)
{
/* init to some ~sane value until calibrate_delay() runs */
@ -181,6 +192,7 @@ void __init maple_setup_arch(void)
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
maple_use_rtas_reboot_and_halt_if_present();
printk(KERN_DEBUG "Using native/NAP idle loop\n");
}

View File

@ -40,4 +40,15 @@ config PS3_USE_LPAR_ADDR
If you have any doubt, choose the default y.
config PS3_VUART
depends on PPC_PS3
bool "PS3 Virtual UART support"
default y
help
Include support for the PS3 Virtual UART.
This support is required for several system services
including the System Manager and AV Settings. In
general, all users will say Y.
endmenu

View File

@ -10,6 +10,8 @@ obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_SCANLOG) += scanlog.o
obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o
obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
obj-$(CONFIG_HVCS) += hvcserver.o
obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o

View File

@ -337,6 +337,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
printk (KERN_ERR "EEH: Device driver ignored %d bad reads, panicing\n",
pdn->eeh_check_count);
dump_stack();
msleep(5000);
/* re-read the slot reset state */
if (read_slot_reset_state(pdn, rets) != 0)

View File

@ -170,14 +170,19 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
static void eeh_report_resume(struct pci_dev *dev, void *userdata)
{
struct pci_driver *driver = dev->driver;
struct device_node *dn = pci_device_to_OF_node(dev);
dev->error_state = pci_channel_io_normal;
if (!driver)
return;
if (!driver->err_handler)
return;
if (!driver->err_handler->resume)
if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
enable_irq(dev->irq);
}
if (!driver->err_handler ||
!driver->err_handler->resume)
return;
driver->err_handler->resume(dev);
@ -407,6 +412,8 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
if (rc)
result = PCI_ERS_RESULT_NEED_RESET;
else
result = PCI_ERS_RESULT_RECOVERED;
}
/* If any device has a hard failure, then shut off everything. */

View File

@ -0,0 +1,275 @@
/*
* pseries CPU Hotplug infrastructure.
*
* Split out from arch/powerpc/platforms/pseries/setup.c
* arch/powerpc/kernel/rtas.c, and arch/powerpc/platforms/pseries/smp.c
*
* Peter Bergner, IBM March 2001.
* Copyright (C) 2001 IBM.
* Dave Engebretsen, Peter Bergner, and
* Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
* Plus various changes from other IBM teams...
*
* Copyright (C) 2006 Michael Ellerman, IBM Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/cpu.h>
#include <asm/system.h>
#include <asm/prom.h>
#include <asm/rtas.h>
#include <asm/firmware.h>
#include <asm/machdep.h>
#include <asm/vdso_datapage.h>
#include <asm/pSeries_reconfig.h>
#include "xics.h"
/* This version can't take the spinlock, because it never returns */
static struct rtas_args rtas_stop_self_args = {
.token = RTAS_UNKNOWN_SERVICE,
.nargs = 0,
.nret = 1,
.rets = &rtas_stop_self_args.args[0],
};
static void rtas_stop_self(void)
{
struct rtas_args *args = &rtas_stop_self_args;
local_irq_disable();
BUG_ON(args->token == RTAS_UNKNOWN_SERVICE);
printk("cpu %u (hwid %u) Ready to die...\n",
smp_processor_id(), hard_smp_processor_id());
enter_rtas(__pa(args));
panic("Alas, I survived.\n");
}
static void pseries_mach_cpu_die(void)
{
local_irq_disable();
idle_task_exit();
xics_teardown_cpu(0);
rtas_stop_self();
/* Should never get here... */
BUG();
for(;;);
}
static int qcss_tok; /* query-cpu-stopped-state token */
/* Get state of physical CPU.
* Return codes:
* 0 - The processor is in the RTAS stopped state
* 1 - stop-self is in progress
* 2 - The processor is not in the RTAS stopped state
* -1 - Hardware Error
* -2 - Hardware Busy, Try again later.
*/
static int query_cpu_stopped(unsigned int pcpu)
{
int cpu_status, status;
status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu);
if (status != 0) {
printk(KERN_ERR
"RTAS query-cpu-stopped-state failed: %i\n", status);
return status;
}
return cpu_status;
}
static int pseries_cpu_disable(void)
{
int cpu = smp_processor_id();
cpu_clear(cpu, cpu_online_map);
vdso_data->processorCount--;
/*fix boot_cpuid here*/
if (cpu == boot_cpuid)
boot_cpuid = any_online_cpu(cpu_online_map);
/* FIXME: abstract this to not be platform specific later on */
xics_migrate_irqs_away();
return 0;
}
static void pseries_cpu_die(unsigned int cpu)
{
int tries;
int cpu_status;
unsigned int pcpu = get_hard_smp_processor_id(cpu);
for (tries = 0; tries < 25; tries++) {
cpu_status = query_cpu_stopped(pcpu);
if (cpu_status == 0 || cpu_status == -1)
break;
msleep(200);
}
if (cpu_status != 0) {
printk("Querying DEAD? cpu %i (%i) shows %i\n",
cpu, pcpu, cpu_status);
}
/* Isolation and deallocation are definatly done by
* drslot_chrp_cpu. If they were not they would be
* done here. Change isolate state to Isolate and
* change allocation-state to Unusable.
*/
paca[cpu].cpu_start = 0;
}
/*
* Update cpu_present_map and paca(s) for a new cpu node. The wrinkle
* here is that a cpu device node may represent up to two logical cpus
* in the SMT case. We must honor the assumption in other code that
* the logical ids for sibling SMT threads x and y are adjacent, such
* that x^1 == y and y^1 == x.
*/
static int pseries_add_processor(struct device_node *np)
{
unsigned int cpu;
cpumask_t candidate_map, tmp = CPU_MASK_NONE;
int err = -ENOSPC, len, nthreads, i;
const u32 *intserv;
intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
if (!intserv)
return 0;
nthreads = len / sizeof(u32);
for (i = 0; i < nthreads; i++)
cpu_set(i, tmp);
lock_cpu_hotplug();
BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
/* Get a bitmap of unoccupied slots. */
cpus_xor(candidate_map, cpu_possible_map, cpu_present_map);
if (cpus_empty(candidate_map)) {
/* If we get here, it most likely means that NR_CPUS is
* less than the partition's max processors setting.
*/
printk(KERN_ERR "Cannot add cpu %s; this system configuration"
" supports %d logical cpus.\n", np->full_name,
cpus_weight(cpu_possible_map));
goto out_unlock;
}
while (!cpus_empty(tmp))
if (cpus_subset(tmp, candidate_map))
/* Found a range where we can insert the new cpu(s) */
break;
else
cpus_shift_left(tmp, tmp, nthreads);
if (cpus_empty(tmp)) {
printk(KERN_ERR "Unable to find space in cpu_present_map for"
" processor %s with %d thread(s)\n", np->name,
nthreads);
goto out_unlock;
}
for_each_cpu_mask(cpu, tmp) {
BUG_ON(cpu_isset(cpu, cpu_present_map));
cpu_set(cpu, cpu_present_map);
set_hard_smp_processor_id(cpu, *intserv++);
}
err = 0;
out_unlock:
unlock_cpu_hotplug();
return err;
}
/*
* Update the present map for a cpu node which is going away, and set
* the hard id in the paca(s) to -1 to be consistent with boot time
* convention for non-present cpus.
*/
static void pseries_remove_processor(struct device_node *np)
{
unsigned int cpu;
int len, nthreads, i;
const u32 *intserv;
intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
if (!intserv)
return;
nthreads = len / sizeof(u32);
lock_cpu_hotplug();
for (i = 0; i < nthreads; i++) {
for_each_present_cpu(cpu) {
if (get_hard_smp_processor_id(cpu) != intserv[i])
continue;
BUG_ON(cpu_online(cpu));
cpu_clear(cpu, cpu_present_map);
set_hard_smp_processor_id(cpu, -1);
break;
}
if (cpu == NR_CPUS)
printk(KERN_WARNING "Could not find cpu to remove "
"with physical id 0x%x\n", intserv[i]);
}
unlock_cpu_hotplug();
}
static int pseries_smp_notifier(struct notifier_block *nb,
unsigned long action, void *node)
{
int err = NOTIFY_OK;
switch (action) {
case PSERIES_RECONFIG_ADD:
if (pseries_add_processor(node))
err = NOTIFY_BAD;
break;
case PSERIES_RECONFIG_REMOVE:
pseries_remove_processor(node);
break;
default:
err = NOTIFY_DONE;
break;
}
return err;
}
static struct notifier_block pseries_smp_nb = {
.notifier_call = pseries_smp_notifier,
};
static int __init pseries_cpu_hotplug_init(void)
{
rtas_stop_self_args.token = rtas_token("stop-self");
qcss_tok = rtas_token("query-cpu-stopped-state");
if (rtas_stop_self_args.token == RTAS_UNKNOWN_SERVICE ||
qcss_tok == RTAS_UNKNOWN_SERVICE) {
printk(KERN_INFO "CPU Hotplug not supported by firmware "
"- disabling.\n");
return 0;
}
ppc_md.cpu_die = pseries_mach_cpu_die;
smp_ops->cpu_disable = pseries_cpu_disable;
smp_ops->cpu_die = pseries_cpu_die;
/* Processors can be added/removed only on LPAR */
if (firmware_has_feature(FW_FEATURE_LPAR))
pSeries_reconfig_notifier_register(&pseries_smp_nb);
return 0;
}
arch_initcall(pseries_cpu_hotplug_init);

View File

@ -347,21 +347,6 @@ static int __init pSeries_init_panel(void)
}
arch_initcall(pSeries_init_panel);
#ifdef CONFIG_HOTPLUG_CPU
static void pSeries_mach_cpu_die(void)
{
local_irq_disable();
idle_task_exit();
xics_teardown_cpu(0);
rtas_stop_self();
/* Should never get here... */
BUG();
for(;;);
}
#else
#define pSeries_mach_cpu_die NULL
#endif
static int pseries_set_dabr(unsigned long dabr)
{
return plpar_hcall_norets(H_SET_DABR, dabr);
@ -437,19 +422,14 @@ static int __init pSeries_probe_hypertas(unsigned long node,
if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL)
powerpc_firmware_features |= FW_FEATURE_LPAR;
if (firmware_has_feature(FW_FEATURE_LPAR))
hpte_init_lpar();
else
hpte_init_native();
return 1;
}
static int __init pSeries_probe(void)
{
unsigned long root = of_get_flat_dt_root();
char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(),
"device_type", NULL);
char *dtype = of_get_flat_dt_prop(root, "device_type", NULL);
if (dtype == NULL)
return 0;
if (strcmp(dtype, "chrp"))
@ -467,6 +447,11 @@ static int __init pSeries_probe(void)
/* Now try to figure out if we are running on LPAR */
of_scan_flat_dt(pSeries_probe_hypertas, NULL);
if (firmware_has_feature(FW_FEATURE_LPAR))
hpte_init_lpar();
else
hpte_init_native();
DBG("Machine is%s LPAR !\n",
(powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not");
@ -561,7 +546,6 @@ define_machine(pseries) {
.power_off = rtas_power_off,
.halt = rtas_halt,
.panic = rtas_os_term,
.cpu_die = pSeries_mach_cpu_die,
.get_boot_time = rtas_get_boot_time,
.get_rtc_time = rtas_get_rtc_time,
.set_rtc_time = rtas_set_rtc_time,

View File

@ -64,197 +64,6 @@ static cpumask_t of_spin_map;
extern void generic_secondary_smp_init(unsigned long);
#ifdef CONFIG_HOTPLUG_CPU
/* Get state of physical CPU.
* Return codes:
* 0 - The processor is in the RTAS stopped state
* 1 - stop-self is in progress
* 2 - The processor is not in the RTAS stopped state
* -1 - Hardware Error
* -2 - Hardware Busy, Try again later.
*/
static int query_cpu_stopped(unsigned int pcpu)
{
int cpu_status;
int status, qcss_tok;
qcss_tok = rtas_token("query-cpu-stopped-state");
if (qcss_tok == RTAS_UNKNOWN_SERVICE)
return -1;
status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu);
if (status != 0) {
printk(KERN_ERR
"RTAS query-cpu-stopped-state failed: %i\n", status);
return status;
}
return cpu_status;
}
static int pSeries_cpu_disable(void)
{
int cpu = smp_processor_id();
cpu_clear(cpu, cpu_online_map);
vdso_data->processorCount--;
/*fix boot_cpuid here*/
if (cpu == boot_cpuid)
boot_cpuid = any_online_cpu(cpu_online_map);
/* FIXME: abstract this to not be platform specific later on */
xics_migrate_irqs_away();
return 0;
}
static void pSeries_cpu_die(unsigned int cpu)
{
int tries;
int cpu_status;
unsigned int pcpu = get_hard_smp_processor_id(cpu);
for (tries = 0; tries < 25; tries++) {
cpu_status = query_cpu_stopped(pcpu);
if (cpu_status == 0 || cpu_status == -1)
break;
msleep(200);
}
if (cpu_status != 0) {
printk("Querying DEAD? cpu %i (%i) shows %i\n",
cpu, pcpu, cpu_status);
}
/* Isolation and deallocation are definatly done by
* drslot_chrp_cpu. If they were not they would be
* done here. Change isolate state to Isolate and
* change allocation-state to Unusable.
*/
paca[cpu].cpu_start = 0;
}
/*
* Update cpu_present_map and paca(s) for a new cpu node. The wrinkle
* here is that a cpu device node may represent up to two logical cpus
* in the SMT case. We must honor the assumption in other code that
* the logical ids for sibling SMT threads x and y are adjacent, such
* that x^1 == y and y^1 == x.
*/
static int pSeries_add_processor(struct device_node *np)
{
unsigned int cpu;
cpumask_t candidate_map, tmp = CPU_MASK_NONE;
int err = -ENOSPC, len, nthreads, i;
const u32 *intserv;
intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
if (!intserv)
return 0;
nthreads = len / sizeof(u32);
for (i = 0; i < nthreads; i++)
cpu_set(i, tmp);
lock_cpu_hotplug();
BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
/* Get a bitmap of unoccupied slots. */
cpus_xor(candidate_map, cpu_possible_map, cpu_present_map);
if (cpus_empty(candidate_map)) {
/* If we get here, it most likely means that NR_CPUS is
* less than the partition's max processors setting.
*/
printk(KERN_ERR "Cannot add cpu %s; this system configuration"
" supports %d logical cpus.\n", np->full_name,
cpus_weight(cpu_possible_map));
goto out_unlock;
}
while (!cpus_empty(tmp))
if (cpus_subset(tmp, candidate_map))
/* Found a range where we can insert the new cpu(s) */
break;
else
cpus_shift_left(tmp, tmp, nthreads);
if (cpus_empty(tmp)) {
printk(KERN_ERR "Unable to find space in cpu_present_map for"
" processor %s with %d thread(s)\n", np->name,
nthreads);
goto out_unlock;
}
for_each_cpu_mask(cpu, tmp) {
BUG_ON(cpu_isset(cpu, cpu_present_map));
cpu_set(cpu, cpu_present_map);
set_hard_smp_processor_id(cpu, *intserv++);
}
err = 0;
out_unlock:
unlock_cpu_hotplug();
return err;
}
/*
* Update the present map for a cpu node which is going away, and set
* the hard id in the paca(s) to -1 to be consistent with boot time
* convention for non-present cpus.
*/
static void pSeries_remove_processor(struct device_node *np)
{
unsigned int cpu;
int len, nthreads, i;
const u32 *intserv;
intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
if (!intserv)
return;
nthreads = len / sizeof(u32);
lock_cpu_hotplug();
for (i = 0; i < nthreads; i++) {
for_each_present_cpu(cpu) {
if (get_hard_smp_processor_id(cpu) != intserv[i])
continue;
BUG_ON(cpu_online(cpu));
cpu_clear(cpu, cpu_present_map);
set_hard_smp_processor_id(cpu, -1);
break;
}
if (cpu == NR_CPUS)
printk(KERN_WARNING "Could not find cpu to remove "
"with physical id 0x%x\n", intserv[i]);
}
unlock_cpu_hotplug();
}
static int pSeries_smp_notifier(struct notifier_block *nb, unsigned long action, void *node)
{
int err = NOTIFY_OK;
switch (action) {
case PSERIES_RECONFIG_ADD:
if (pSeries_add_processor(node))
err = NOTIFY_BAD;
break;
case PSERIES_RECONFIG_REMOVE:
pSeries_remove_processor(node);
break;
default:
err = NOTIFY_DONE;
break;
}
return err;
}
static struct notifier_block pSeries_smp_nb = {
.notifier_call = pSeries_smp_notifier,
};
#endif /* CONFIG_HOTPLUG_CPU */
/**
* smp_startup_cpu() - start the given cpu
*
@ -422,15 +231,6 @@ static void __init smp_init_pseries(void)
DBG(" -> smp_init_pSeries()\n");
#ifdef CONFIG_HOTPLUG_CPU
smp_ops->cpu_disable = pSeries_cpu_disable;
smp_ops->cpu_die = pSeries_cpu_die;
/* Processors can be added/removed only on LPAR */
if (firmware_has_feature(FW_FEATURE_LPAR))
pSeries_reconfig_notifier_register(&pSeries_smp_nb);
#endif
/* Mark threads which are still spinning in hold loops. */
if (cpu_has_feature(CPU_FTR_SMT)) {
for_each_present_cpu(i) {

View File

@ -5,7 +5,8 @@ endif
obj-$(CONFIG_MPIC) += mpic.o
obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o
obj-$(CONFIG_PPC_MPC106) += grackle.o
obj-$(CONFIG_PPC_DCR) += dcr.o dcr-low.o
obj-$(CONFIG_PPC_DCR) += dcr.o
obj-$(CONFIG_PPC_DCR_NATIVE) += dcr-low.o
obj-$(CONFIG_U3_DART) += dart_iommu.o
obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
obj-$(CONFIG_FSL_SOC) += fsl_soc.o

View File

@ -1,39 +0,0 @@
/*
* "Indirect" DCR access
*
* Copyright (c) 2004 Eugene Surovegin <ebs@ebshome.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <asm/ppc_asm.h>
#include <asm/processor.h>
#define DCR_ACCESS_PROLOG(table) \
rlwinm r3,r3,4,18,27; \
lis r5,table@h; \
ori r5,r5,table@l; \
add r3,r3,r5; \
mtctr r3; \
bctr
_GLOBAL(__mfdcr)
DCR_ACCESS_PROLOG(__mfdcr_table)
_GLOBAL(__mtdcr)
DCR_ACCESS_PROLOG(__mtdcr_table)
__mfdcr_table:
mfdcr r3,0; blr
__mtdcr_table:
mtdcr 0,r4; blr
dcr = 1
.rept 1023
mfdcr r3,dcr; blr
mtdcr dcr,r4; blr
dcr = dcr + 1
.endr

View File

@ -223,23 +223,15 @@ static void qe_ic_mask_irq(unsigned int virq)
qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
temp & ~qe_ic_info[src].mask);
spin_unlock_irqrestore(&qe_ic_lock, flags);
}
static void qe_ic_mask_irq_and_ack(unsigned int virq)
{
struct qe_ic *qe_ic = qe_ic_from_irq(virq);
unsigned int src = virq_to_hw(virq);
unsigned long flags;
u32 temp;
spin_lock_irqsave(&qe_ic_lock, flags);
temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
temp & ~qe_ic_info[src].mask);
/* There is nothing to do for ack here, ack is handled in ISR */
/* Flush the above write before enabling interrupts; otherwise,
* spurious interrupts will sometimes happen. To be 100% sure
* that the write has reached the device before interrupts are
* enabled, the mask register would have to be read back; however,
* this is not required for correctness, only to avoid wasting
* time on a large number of spurious interrupts. In testing,
* a sync reduced the observed spurious interrupts to zero.
*/
mb();
spin_unlock_irqrestore(&qe_ic_lock, flags);
}
@ -248,7 +240,7 @@ static struct irq_chip qe_ic_irq_chip = {
.typename = " QEIC ",
.unmask = qe_ic_unmask_irq,
.mask = qe_ic_mask_irq,
.mask_ack = qe_ic_mask_irq_and_ack,
.mask_ack = qe_ic_mask_irq,
};
static int qe_ic_host_match(struct irq_host *h, struct device_node *node)
@ -331,34 +323,22 @@ unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
return irq_linear_revmap(qe_ic->irqhost, irq);
}
/* FIXME: We mask all the QE Low interrupts while handling. We should
* let other interrupt come in, but BAD interrupts are generated */
void fastcall qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc)
{
struct qe_ic *qe_ic = desc->handler_data;
struct irq_chip *chip = irq_desc[irq].chip;
unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
chip->mask_ack(irq);
if (cascade_irq != NO_IRQ)
generic_handle_irq(cascade_irq);
chip->unmask(irq);
}
/* FIXME: We mask all the QE High interrupts while handling. We should
* let other interrupt come in, but BAD interrupts are generated */
void fastcall qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc)
{
struct qe_ic *qe_ic = desc->handler_data;
struct irq_chip *chip = irq_desc[irq].chip;
unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
chip->mask_ack(irq);
if (cascade_irq != NO_IRQ)
generic_handle_irq(cascade_irq);
chip->unmask(irq);
}
void __init qe_ic_init(struct device_node *node, unsigned int flags)

View File

@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <asm/of_device.h>
#include <asm/of_platform.h>
static int __init powerpc_flash_init(void)
{

View File

@ -22,6 +22,7 @@
#include <linux/sysrq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/bug.h>
#include <asm/ptrace.h>
#include <asm/string.h>
@ -35,7 +36,6 @@
#include <asm/cputable.h>
#include <asm/rtas.h>
#include <asm/sstep.h>
#include <asm/bug.h>
#include <asm/irq_regs.h>
#include <asm/spu.h>
#include <asm/spu_priv1.h>
@ -1346,7 +1346,7 @@ static void backtrace(struct pt_regs *excp)
static void print_bug_trap(struct pt_regs *regs)
{
struct bug_entry *bug;
const struct bug_entry *bug;
unsigned long addr;
if (regs->msr & MSR_PR)
@ -1357,11 +1357,11 @@ static void print_bug_trap(struct pt_regs *regs)
bug = find_bug(regs->nip);
if (bug == NULL)
return;
if (bug->line & BUG_WARNING_TRAP)
if (is_warning_bug(bug))
return;
printf("kernel BUG in %s at %s:%d!\n",
bug->function, bug->file, (unsigned int)bug->line);
printf("kernel BUG at %s:%u!\n",
bug->file, bug->line);
}
void excprint(struct pt_regs *fp)

View File

@ -879,7 +879,7 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res)
static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
unsigned long *offset,
resource_size_t *offset,
enum pci_mmap_state mmap_state)
{
struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
@ -891,7 +891,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
/* If memory, add on the PCI bridge address offset */
if (mmap_state == pci_mmap_mem) {
#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
*offset += hose->pci_mem_offset;
#endif
res_bit = IORESOURCE_MEM;
} else {
io_offset = hose->io_base_virt - ___IO_BASE;
@ -1030,7 +1032,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state,
int write_combine)
{
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
struct resource *rp;
int ret;
@ -1132,21 +1134,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
resource_size_t *start, resource_size_t *end)
{
struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
unsigned long offset = 0;
resource_size_t offset = 0;
if (hose == NULL)
return;
if (rsrc->flags & IORESOURCE_IO)
offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys;
offset = (unsigned long)hose->io_base_virt - _IO_BASE;
*start = rsrc->start + offset;
*end = rsrc->end + offset;
/* We pass a fully fixed up address to userland for MMIO instead of
* a BAR value because X is lame and expects to be able to use that
* to pass to /dev/mem !
*
* That means that we'll have potentially 64 bits values where some
* userland apps only expect 32 (like X itself since it thinks only
* Sparc has 64 bits MMIO) but if we don't do that, we break it on
* 32 bits CHRPs :-(
*
* Hopefully, the sysfs insterface is immune to that gunk. Once X
* has been fixed (and the fix spread enough), we can re-enable the
* 2 lines below and pass down a BAR value to userland. In that case
* we'll also have to re-enable the matching code in
* __pci_mmap_make_offset().
*
* BenH.
*/
#if 0
else if (rsrc->flags & IORESOURCE_MEM)
offset = hose->pci_mem_offset;
#endif
*start = rsrc->start - offset;
*end = rsrc->end - offset;
}
void __init
pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
int flags, char *name)
void __init pci_init_resource(struct resource *res, resource_size_t start,
resource_size_t end, int flags, char *name)
{
res->start = start;
res->end = end;

View File

@ -1 +1,2 @@
obj-y += system-bus.o
obj-$(CONFIG_PS3_VUART) += vuart.o

965
drivers/ps3/vuart.c Normal file
View File

@ -0,0 +1,965 @@
/*
* PS3 virtual uart
*
* Copyright (C) 2006 Sony Computer Entertainment Inc.
* Copyright 2006 Sony Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <asm/ps3.h>
#include <asm/lv1call.h>
#include <asm/bitops.h>
#include "vuart.h"
MODULE_AUTHOR("Sony Corporation");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("ps3 vuart");
/**
* vuart - An inter-partition data link service.
* port 0: PS3 AV Settings.
* port 2: PS3 System Manager.
*
* The vuart provides a bi-directional byte stream data link between logical
* partitions. Its primary role is as a communications link between the guest
* OS and the system policy module. The current HV does not support any
* connections other than those listed.
*/
enum {PORT_COUNT = 3,};
enum vuart_param {
PARAM_TX_TRIGGER = 0,
PARAM_RX_TRIGGER = 1,
PARAM_INTERRUPT_MASK = 2,
PARAM_RX_BUF_SIZE = 3, /* read only */
PARAM_RX_BYTES = 4, /* read only */
PARAM_TX_BUF_SIZE = 5, /* read only */
PARAM_TX_BYTES = 6, /* read only */
PARAM_INTERRUPT_STATUS = 7, /* read only */
};
enum vuart_interrupt_bit {
INTERRUPT_BIT_TX = 0,
INTERRUPT_BIT_RX = 1,
INTERRUPT_BIT_DISCONNECT = 2,
};
enum vuart_interrupt_mask {
INTERRUPT_MASK_TX = 1,
INTERRUPT_MASK_RX = 2,
INTERRUPT_MASK_DISCONNECT = 4,
};
/**
* struct ports_bmp - bitmap indicating ports needing service.
*
* A 256 bit read only bitmap indicating ports needing service. Do not write
* to these bits. Must not cross a page boundary.
*/
struct ports_bmp {
u64 status;
u64 unused[3];
} __attribute__ ((aligned (32)));
/* redefine dev_dbg to do a syntax check */
#if !defined(DEBUG)
#undef dev_dbg
static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
const struct device *_dev, const char *fmt, ...) {return 0;}
#endif
#define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
static void __attribute__ ((unused)) _dump_ports_bmp(
const struct ports_bmp* bmp, const char* func, int line)
{
pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status);
}
static int ps3_vuart_match_id_to_port(enum ps3_match_id match_id,
unsigned int *port_number)
{
switch(match_id) {
case PS3_MATCH_ID_AV_SETTINGS:
*port_number = 0;
return 0;
case PS3_MATCH_ID_SYSTEM_MANAGER:
*port_number = 2;
return 0;
default:
WARN_ON(1);
*port_number = UINT_MAX;
return -EINVAL;
};
}
#define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__)
static void __attribute__ ((unused)) _dump_port_params(unsigned int port_number,
const char* func, int line)
{
#if defined(DEBUG)
static const char *strings[] = {
"tx_trigger ",
"rx_trigger ",
"interrupt_mask ",
"rx_buf_size ",
"rx_bytes ",
"tx_buf_size ",
"tx_bytes ",
"interrupt_status",
};
int result;
unsigned int i;
u64 value;
for (i = 0; i < ARRAY_SIZE(strings); i++) {
result = lv1_get_virtual_uart_param(port_number, i, &value);
if (result) {
pr_debug("%s:%d: port_%u: %s failed: %s\n", func, line,
port_number, strings[i], ps3_result(result));
continue;
}
pr_debug("%s:%d: port_%u: %s = %lxh\n",
func, line, port_number, strings[i], value);
}
#endif
}
struct vuart_triggers {
unsigned long rx;
unsigned long tx;
};
int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev,
struct vuart_triggers *trig)
{
int result;
unsigned long size;
unsigned long val;
result = lv1_get_virtual_uart_param(dev->port_number,
PARAM_TX_TRIGGER, &trig->tx);
if (result) {
dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n",
__func__, __LINE__, ps3_result(result));
return result;
}
result = lv1_get_virtual_uart_param(dev->port_number,
PARAM_RX_BUF_SIZE, &size);
if (result) {
dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n",
__func__, __LINE__, ps3_result(result));
return result;
}
result = lv1_get_virtual_uart_param(dev->port_number,
PARAM_RX_TRIGGER, &val);
if (result) {
dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n",
__func__, __LINE__, ps3_result(result));
return result;
}
trig->rx = size - val;
dev_dbg(&dev->core, "%s:%d: tx %lxh, rx %lxh\n", __func__, __LINE__,
trig->tx, trig->rx);
return result;
}
int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx,
unsigned int rx)
{
int result;
unsigned long size;
result = lv1_set_virtual_uart_param(dev->port_number,
PARAM_TX_TRIGGER, tx);
if (result) {
dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n",
__func__, __LINE__, ps3_result(result));
return result;
}
result = lv1_get_virtual_uart_param(dev->port_number,
PARAM_RX_BUF_SIZE, &size);
if (result) {
dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n",
__func__, __LINE__, ps3_result(result));
return result;
}
result = lv1_set_virtual_uart_param(dev->port_number,
PARAM_RX_TRIGGER, size - rx);
if (result) {
dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n",
__func__, __LINE__, ps3_result(result));
return result;
}
dev_dbg(&dev->core, "%s:%d: tx %xh, rx %xh\n", __func__, __LINE__,
tx, rx);
return result;
}
static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev,
unsigned long *bytes_waiting)
{
int result = lv1_get_virtual_uart_param(dev->port_number,
PARAM_RX_BYTES, bytes_waiting);
if (result)
dev_dbg(&dev->core, "%s:%d: rx_bytes failed: %s\n",
__func__, __LINE__, ps3_result(result));
dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__,
*bytes_waiting);
return result;
}
static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev,
unsigned long mask)
{
int result;
dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask);
dev->interrupt_mask = mask;
result = lv1_set_virtual_uart_param(dev->port_number,
PARAM_INTERRUPT_MASK, dev->interrupt_mask);
if (result)
dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n",
__func__, __LINE__, ps3_result(result));
return result;
}
static int ps3_vuart_get_interrupt_mask(struct ps3_vuart_port_device *dev,
unsigned long *status)
{
int result = lv1_get_virtual_uart_param(dev->port_number,
PARAM_INTERRUPT_STATUS, status);
if (result)
dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n",
__func__, __LINE__, ps3_result(result));
dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n",
__func__, __LINE__, dev->interrupt_mask, *status,
dev->interrupt_mask & *status);
return result;
}
int ps3_vuart_enable_interrupt_tx(struct ps3_vuart_port_device *dev)
{
return (dev->interrupt_mask & INTERRUPT_MASK_TX) ? 0
: ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
| INTERRUPT_MASK_TX);
}
int ps3_vuart_enable_interrupt_rx(struct ps3_vuart_port_device *dev)
{
return (dev->interrupt_mask & INTERRUPT_MASK_RX) ? 0
: ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
| INTERRUPT_MASK_RX);
}
int ps3_vuart_enable_interrupt_disconnect(struct ps3_vuart_port_device *dev)
{
return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0
: ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
| INTERRUPT_MASK_DISCONNECT);
}
int ps3_vuart_disable_interrupt_tx(struct ps3_vuart_port_device *dev)
{
return (dev->interrupt_mask & INTERRUPT_MASK_TX)
? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
& ~INTERRUPT_MASK_TX) : 0;
}
int ps3_vuart_disable_interrupt_rx(struct ps3_vuart_port_device *dev)
{
return (dev->interrupt_mask & INTERRUPT_MASK_RX)
? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
& ~INTERRUPT_MASK_RX) : 0;
}
int ps3_vuart_disable_interrupt_disconnect(struct ps3_vuart_port_device *dev)
{
return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT)
? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
& ~INTERRUPT_MASK_DISCONNECT) : 0;
}
/**
* ps3_vuart_raw_write - Low level write helper.
*
* Do not call ps3_vuart_raw_write directly, use ps3_vuart_write.
*/
static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev,
const void* buf, unsigned int bytes, unsigned long *bytes_written)
{
int result;
dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes);
result = lv1_write_virtual_uart(dev->port_number,
ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written);
if (result) {
dev_dbg(&dev->core, "%s:%d: lv1_write_virtual_uart failed: "
"%s\n", __func__, __LINE__, ps3_result(result));
return result;
}
dev->stats.bytes_written += *bytes_written;
dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__,
__LINE__, *bytes_written, bytes, dev->stats.bytes_written);
return result;
}
/**
* ps3_vuart_raw_read - Low level read helper.
*
* Do not call ps3_vuart_raw_read directly, use ps3_vuart_read.
*/
static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf,
unsigned int bytes, unsigned long *bytes_read)
{
int result;
dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes);
result = lv1_read_virtual_uart(dev->port_number,
ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read);
if (result) {
dev_dbg(&dev->core, "%s:%d: lv1_read_virtual_uart failed: %s\n",
__func__, __LINE__, ps3_result(result));
return result;
}
dev->stats.bytes_read += *bytes_read;
dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__,
*bytes_read, bytes, dev->stats.bytes_read);
return result;
}
/**
* struct list_buffer - An element for a port device fifo buffer list.
*/
struct list_buffer {
struct list_head link;
const unsigned char *head;
const unsigned char *tail;
unsigned long dbg_number;
unsigned char data[];
};
/**
* ps3_vuart_write - the entry point for writing data to a port
*
* If the port is idle on entry as much of the incoming data is written to
* the port as the port will accept. Otherwise a list buffer is created
* and any remaning incoming data is copied to that buffer. The buffer is
* then enqueued for transmision via the transmit interrupt.
*/
int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
unsigned int bytes)
{
static unsigned long dbg_number;
int result;
unsigned long flags;
struct list_buffer *lb;
dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
bytes, bytes);
spin_lock_irqsave(&dev->tx_list.lock, flags);
if (list_empty(&dev->tx_list.head)) {
unsigned long bytes_written;
result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written);
spin_unlock_irqrestore(&dev->tx_list.lock, flags);
if (result) {
dev_dbg(&dev->core,
"%s:%d: ps3_vuart_raw_write failed\n",
__func__, __LINE__);
return result;
}
if (bytes_written == bytes) {
dev_dbg(&dev->core, "%s:%d: wrote %xh bytes\n",
__func__, __LINE__, bytes);
return 0;
}
bytes -= bytes_written;
buf += bytes_written;
} else
spin_unlock_irqrestore(&dev->tx_list.lock, flags);
lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL);
if (!lb) {
return -ENOMEM;
}
memcpy(lb->data, buf, bytes);
lb->head = lb->data;
lb->tail = lb->data + bytes;
lb->dbg_number = ++dbg_number;
spin_lock_irqsave(&dev->tx_list.lock, flags);
list_add_tail(&lb->link, &dev->tx_list.head);
ps3_vuart_enable_interrupt_tx(dev);
spin_unlock_irqrestore(&dev->tx_list.lock, flags);
dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n",
__func__, __LINE__, lb->dbg_number, bytes);
return 0;
}
/**
* ps3_vuart_read - the entry point for reading data from a port
*
* If enough bytes to satisfy the request are held in the buffer list those
* bytes are dequeued and copied to the caller's buffer. Emptied list buffers
* are retiered. If the request cannot be statified by bytes held in the list
* buffers -EAGAIN is returned.
*/
int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
unsigned int bytes)
{
unsigned long flags;
struct list_buffer *lb, *n;
unsigned long bytes_read;
dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
bytes, bytes);
spin_lock_irqsave(&dev->rx_list.lock, flags);
if (dev->rx_list.bytes_held < bytes) {
spin_unlock_irqrestore(&dev->rx_list.lock, flags);
dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n",
__func__, __LINE__, bytes - dev->rx_list.bytes_held);
return -EAGAIN;
}
list_for_each_entry_safe(lb, n, &dev->rx_list.head, link) {
bytes_read = min((unsigned int)(lb->tail - lb->head), bytes);
memcpy(buf, lb->head, bytes_read);
buf += bytes_read;
bytes -= bytes_read;
dev->rx_list.bytes_held -= bytes_read;
if (bytes_read < lb->tail - lb->head) {
lb->head += bytes_read;
spin_unlock_irqrestore(&dev->rx_list.lock, flags);
dev_dbg(&dev->core,
"%s:%d: dequeued buf_%lu, %lxh bytes\n",
__func__, __LINE__, lb->dbg_number, bytes_read);
return 0;
}
dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__,
lb->dbg_number);
list_del(&lb->link);
kfree(lb);
}
spin_unlock_irqrestore(&dev->rx_list.lock, flags);
dev_dbg(&dev->core, "%s:%d: dequeued buf_%lu, %xh bytes\n",
__func__, __LINE__, lb->dbg_number, bytes);
return 0;
}
/**
* ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler
*
* Services the transmit interrupt for the port. Writes as much data from the
* buffer list as the port will accept. Retires any emptied list buffers and
* adjusts the final list buffer state for a partial write.
*/
static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev)
{
int result = 0;
unsigned long flags;
struct list_buffer *lb, *n;
unsigned long bytes_total = 0;
dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
spin_lock_irqsave(&dev->tx_list.lock, flags);
list_for_each_entry_safe(lb, n, &dev->tx_list.head, link) {
unsigned long bytes_written;
result = ps3_vuart_raw_write(dev, lb->head, lb->tail - lb->head,
&bytes_written);
if (result) {
dev_dbg(&dev->core,
"%s:%d: ps3_vuart_raw_write failed\n",
__func__, __LINE__);
break;
}
bytes_total += bytes_written;
if (bytes_written < lb->tail - lb->head) {
lb->head += bytes_written;
dev_dbg(&dev->core,
"%s:%d cleared buf_%lu, %lxh bytes\n",
__func__, __LINE__, lb->dbg_number,
bytes_written);
goto port_full;
}
dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__,
lb->dbg_number);
list_del(&lb->link);
kfree(lb);
}
ps3_vuart_disable_interrupt_tx(dev);
port_full:
spin_unlock_irqrestore(&dev->tx_list.lock, flags);
dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n",
__func__, __LINE__, bytes_total);
return result;
}
/**
* ps3_vuart_handle_interrupt_rx - third stage receive interrupt handler
*
* Services the receive interrupt for the port. Creates a list buffer and
* copies all waiting port data to that buffer and enqueues the buffer in the
* buffer list. Buffer list data is dequeued via ps3_vuart_read.
*/
static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev)
{
static unsigned long dbg_number;
int result = 0;
unsigned long flags;
struct list_buffer *lb;
unsigned long bytes;
dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes);
if (result)
return -EIO;
BUG_ON(!bytes);
/* add some extra space for recently arrived data */
bytes += 128;
lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_ATOMIC);
if (!lb)
return -ENOMEM;
ps3_vuart_raw_read(dev, lb->data, bytes, &bytes);
lb->head = lb->data;
lb->tail = lb->data + bytes;
lb->dbg_number = ++dbg_number;
spin_lock_irqsave(&dev->rx_list.lock, flags);
list_add_tail(&lb->link, &dev->rx_list.head);
dev->rx_list.bytes_held += bytes;
spin_unlock_irqrestore(&dev->rx_list.lock, flags);
dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %lxh bytes\n",
__func__, __LINE__, lb->dbg_number, bytes);
return 0;
}
static int ps3_vuart_handle_interrupt_disconnect(
struct ps3_vuart_port_device *dev)
{
dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
BUG_ON("no support");
return -1;
}
/**
* ps3_vuart_handle_port_interrupt - second stage interrupt handler
*
* Services any pending interrupt types for the port. Passes control to the
* third stage type specific interrupt handler. Returns control to the first
* stage handler after one iteration.
*/
static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev)
{
int result;
unsigned long status;
result = ps3_vuart_get_interrupt_mask(dev, &status);
if (result)
return result;
dev_dbg(&dev->core, "%s:%d: status: %lxh\n", __func__, __LINE__,
status);
if (status & INTERRUPT_MASK_DISCONNECT) {
dev->stats.disconnect_interrupts++;
result = ps3_vuart_handle_interrupt_disconnect(dev);
if (result)
ps3_vuart_disable_interrupt_disconnect(dev);
}
if (status & INTERRUPT_MASK_TX) {
dev->stats.tx_interrupts++;
result = ps3_vuart_handle_interrupt_tx(dev);
if (result)
ps3_vuart_disable_interrupt_tx(dev);
}
if (status & INTERRUPT_MASK_RX) {
dev->stats.rx_interrupts++;
result = ps3_vuart_handle_interrupt_rx(dev);
if (result)
ps3_vuart_disable_interrupt_rx(dev);
}
return 0;
}
struct vuart_private {
unsigned int in_use;
unsigned int virq;
struct ps3_vuart_port_device *devices[PORT_COUNT];
const struct ports_bmp bmp;
};
/**
* ps3_vuart_irq_handler - first stage interrupt handler
*
* Loops finding any interrupting port and its associated instance data.
* Passes control to the second stage port specific interrupt handler. Loops
* until all outstanding interrupts are serviced.
*/
static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private)
{
struct vuart_private *private;
BUG_ON(!_private);
private = (struct vuart_private *)_private;
while (1) {
unsigned int port;
dump_ports_bmp(&private->bmp);
port = (BITS_PER_LONG - 1) - __ilog2(private->bmp.status);
if (port == BITS_PER_LONG)
break;
BUG_ON(port >= PORT_COUNT);
BUG_ON(!private->devices[port]);
ps3_vuart_handle_port_interrupt(private->devices[port]);
}
return IRQ_HANDLED;
}
static int ps3_vuart_match(struct device *_dev, struct device_driver *_drv)
{
int result;
struct ps3_vuart_port_driver *drv = to_ps3_vuart_port_driver(_drv);
struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
result = dev->match_id == drv->match_id;
dev_info(&dev->core, "%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__,
__LINE__, dev->match_id, dev->core.bus_id, drv->match_id,
drv->core.name, (result ? "match" : "miss"));
return result;
}
static struct vuart_private vuart_private;
static int ps3_vuart_probe(struct device *_dev)
{
int result;
unsigned long tmp;
struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
struct ps3_vuart_port_driver *drv =
to_ps3_vuart_port_driver(_dev->driver);
dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
BUG_ON(!drv);
result = ps3_vuart_match_id_to_port(dev->match_id, &dev->port_number);
if (result) {
dev_dbg(&dev->core, "%s:%d: unknown match_id (%d)\n",
__func__, __LINE__, dev->match_id);
result = -EINVAL;
goto fail_match;
}
if (vuart_private.devices[dev->port_number]) {
dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__,
__LINE__, dev->port_number);
result = -EBUSY;
goto fail_match;
}
vuart_private.devices[dev->port_number] = dev;
INIT_LIST_HEAD(&dev->tx_list.head);
spin_lock_init(&dev->tx_list.lock);
INIT_LIST_HEAD(&dev->rx_list.head);
spin_lock_init(&dev->rx_list.lock);
vuart_private.in_use++;
if (vuart_private.in_use == 1) {
result = ps3_alloc_vuart_irq((void*)&vuart_private.bmp.status,
&vuart_private.virq);
if (result) {
dev_dbg(&dev->core,
"%s:%d: ps3_alloc_vuart_irq failed (%d)\n",
__func__, __LINE__, result);
result = -EPERM;
goto fail_alloc_irq;
}
result = request_irq(vuart_private.virq, ps3_vuart_irq_handler,
IRQF_DISABLED, "vuart", &vuart_private);
if (result) {
dev_info(&dev->core, "%s:%d: request_irq failed (%d)\n",
__func__, __LINE__, result);
goto fail_request_irq;
}
}
ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX);
/* clear stale pending interrupts */
ps3_vuart_get_interrupt_mask(dev, &tmp);
ps3_vuart_set_triggers(dev, 1, 1);
if (drv->probe)
result = drv->probe(dev);
else {
result = 0;
dev_info(&dev->core, "%s:%d: no probe method\n", __func__,
__LINE__);
}
if (result) {
dev_dbg(&dev->core, "%s:%d: drv->probe failed\n",
__func__, __LINE__);
goto fail_probe;
}
return result;
fail_probe:
fail_request_irq:
vuart_private.in_use--;
if (!vuart_private.in_use) {
ps3_free_vuart_irq(vuart_private.virq);
vuart_private.virq = NO_IRQ;
}
fail_alloc_irq:
fail_match:
dev_dbg(&dev->core, "%s:%d failed\n", __func__, __LINE__);
return result;
}
static int ps3_vuart_remove(struct device *_dev)
{
struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
struct ps3_vuart_port_driver *drv =
to_ps3_vuart_port_driver(_dev->driver);
dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__,
dev->core.bus_id);
BUG_ON(vuart_private.in_use < 1);
if (drv->remove)
drv->remove(dev);
else
dev_dbg(&dev->core, "%s:%d: %s no remove method\n", __func__,
__LINE__, dev->core.bus_id);
vuart_private.in_use--;
if (!vuart_private.in_use) {
free_irq(vuart_private.virq, &vuart_private);
ps3_free_vuart_irq(vuart_private.virq);
vuart_private.virq = NO_IRQ;
}
return 0;
}
/**
* ps3_vuart - The vuart instance.
*
* The vuart is managed as a bus that port devices connect to.
*/
struct bus_type ps3_vuart = {
.name = "ps3_vuart",
.match = ps3_vuart_match,
.probe = ps3_vuart_probe,
.remove = ps3_vuart_remove,
};
int __init ps3_vuart_init(void)
{
int result;
pr_debug("%s:%d:\n", __func__, __LINE__);
result = bus_register(&ps3_vuart);
BUG_ON(result);
return result;
}
void __exit ps3_vuart_exit(void)
{
pr_debug("%s:%d:\n", __func__, __LINE__);
bus_unregister(&ps3_vuart);
}
core_initcall(ps3_vuart_init);
module_exit(ps3_vuart_exit);
/**
* ps3_vuart_port_release_device - Remove a vuart port device.
*/
static void ps3_vuart_port_release_device(struct device *_dev)
{
struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
#if defined(DEBUG)
memset(dev, 0xad, sizeof(struct ps3_vuart_port_device));
#endif
kfree(dev);
}
/**
* ps3_vuart_port_device_register - Add a vuart port device.
*/
int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev)
{
int result;
static unsigned int dev_count = 1;
dev->core.parent = NULL;
dev->core.bus = &ps3_vuart;
dev->core.release = ps3_vuart_port_release_device;
snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x",
dev_count++);
dev_dbg(&dev->core, "%s:%d register\n", __func__, __LINE__);
result = device_register(&dev->core);
return result;
}
EXPORT_SYMBOL_GPL(ps3_vuart_port_device_register);
/**
* ps3_vuart_port_driver_register - Add a vuart port device driver.
*/
int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv)
{
int result;
pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name);
drv->core.bus = &ps3_vuart;
result = driver_register(&drv->core);
return result;
}
EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register);
/**
* ps3_vuart_port_driver_unregister - Remove a vuart port device driver.
*/
void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv)
{
driver_unregister(&drv->core);
}
EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_unregister);

94
drivers/ps3/vuart.h Normal file
View File

@ -0,0 +1,94 @@
/*
* PS3 virtual uart
*
* Copyright (C) 2006 Sony Computer Entertainment Inc.
* Copyright 2006 Sony Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if !defined(_PS3_VUART_H)
#define _PS3_VUART_H
struct ps3_vuart_stats {
unsigned long bytes_written;
unsigned long bytes_read;
unsigned long tx_interrupts;
unsigned long rx_interrupts;
unsigned long disconnect_interrupts;
};
/**
* struct ps3_vuart_port_device - a device on a vuart port
*/
struct ps3_vuart_port_device {
enum ps3_match_id match_id;
struct device core;
/* private driver variables */
unsigned int port_number;
unsigned long interrupt_mask;
struct {
spinlock_t lock;
struct list_head head;
} tx_list;
struct {
unsigned long bytes_held;
spinlock_t lock;
struct list_head head;
} rx_list;
struct ps3_vuart_stats stats;
};
/**
* struct ps3_vuart_port_driver - a driver for a device on a vuart port
*/
struct ps3_vuart_port_driver {
enum ps3_match_id match_id;
struct device_driver core;
int (*probe)(struct ps3_vuart_port_device *);
int (*remove)(struct ps3_vuart_port_device *);
int (*tx_event)(struct ps3_vuart_port_device *dev);
int (*rx_event)(struct ps3_vuart_port_device *dev);
int (*disconnect_event)(struct ps3_vuart_port_device *dev);
/* int (*suspend)(struct ps3_vuart_port_device *, pm_message_t); */
/* int (*resume)(struct ps3_vuart_port_device *); */
};
int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev);
int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv);
void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv);
int ps3_vuart_write(struct ps3_vuart_port_device *dev,
const void* buf, unsigned int bytes);
int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
unsigned int bytes);
static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver(
struct device_driver *_drv)
{
return container_of(_drv, struct ps3_vuart_port_driver, core);
}
static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device(
struct device *_dev)
{
return container_of(_dev, struct ps3_vuart_port_device, core);
}
int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
unsigned int bytes);
int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
unsigned int bytes);
#endif

View File

@ -17,7 +17,6 @@ header-y += ipc.h
header-y += poll.h
header-y += shmparam.h
header-y += sockios.h
header-y += spu_info.h
header-y += ucontext.h
header-y += ioctl.h
header-y += linkage.h
@ -37,6 +36,7 @@ unifdef-y += posix_types.h
unifdef-y += ptrace.h
unifdef-y += seccomp.h
unifdef-y += signal.h
unifdef-y += spu_info.h
unifdef-y += termios.h
unifdef-y += types.h
unifdef-y += unistd.h

View File

@ -13,36 +13,39 @@
#ifndef __ASSEMBLY__
struct bug_entry {
unsigned long bug_addr;
long line;
const char *file;
const char *function;
};
struct bug_entry *find_bug(unsigned long bugaddr);
/*
* If this bit is set in the line number it means that the trap
* is for WARN_ON rather than BUG or BUG_ON.
*/
#define BUG_WARNING_TRAP 0x1000000
#ifdef CONFIG_BUG
/* _EMIT_BUG_ENTRY expects args %0,%1,%2,%3 to be FILE, LINE, flags and
sizeof(struct bug_entry), respectively */
#ifdef CONFIG_DEBUG_BUGVERBOSE
#define _EMIT_BUG_ENTRY \
".section __bug_table,\"a\"\n" \
"2:\t" PPC_LONG "1b, %0\n" \
"\t.short %1, %2\n" \
".org 2b+%3\n" \
".previous\n"
#else
#define _EMIT_BUG_ENTRY \
".section __bug_table,\"a\"\n" \
"2:\t" PPC_LONG "1b\n" \
"\t.short %2\n" \
".org 2b+%3\n" \
".previous\n"
#endif
/*
* BUG_ON() and WARN_ON() do their best to cooperate with compile-time
* optimisations. However depending on the complexity of the condition
* some compiler versions may not produce optimal results.
*/
#define BUG() do { \
__asm__ __volatile__( \
"1: twi 31,0,0\n" \
".section __bug_table,\"a\"\n" \
"\t"PPC_LONG" 1b,%0,%1,%2\n" \
".previous" \
: : "i" (__LINE__), "i" (__FILE__), "i" (__FUNCTION__)); \
#define BUG() do { \
__asm__ __volatile__( \
"1: twi 31,0,0\n" \
_EMIT_BUG_ENTRY \
: : "i" (__FILE__), "i" (__LINE__), \
"i" (0), "i" (sizeof(struct bug_entry))); \
for(;;) ; \
} while (0)
#define BUG_ON(x) do { \
@ -51,23 +54,21 @@ struct bug_entry *find_bug(unsigned long bugaddr);
BUG(); \
} else { \
__asm__ __volatile__( \
"1: "PPC_TLNEI" %0,0\n" \
".section __bug_table,\"a\"\n" \
"\t"PPC_LONG" 1b,%1,%2,%3\n" \
".previous" \
: : "r" ((long)(x)), "i" (__LINE__), \
"i" (__FILE__), "i" (__FUNCTION__)); \
"1: "PPC_TLNEI" %4,0\n" \
_EMIT_BUG_ENTRY \
: : "i" (__FILE__), "i" (__LINE__), "i" (0), \
"i" (sizeof(struct bug_entry)), \
"r" ((long)(x))); \
} \
} while (0)
#define __WARN() do { \
__asm__ __volatile__( \
"1: twi 31,0,0\n" \
".section __bug_table,\"a\"\n" \
"\t"PPC_LONG" 1b,%0,%1,%2\n" \
".previous" \
: : "i" (__LINE__ + BUG_WARNING_TRAP), \
"i" (__FILE__), "i" (__FUNCTION__)); \
_EMIT_BUG_ENTRY \
: : "i" (__FILE__), "i" (__LINE__), \
"i" (BUGFLAG_WARNING), \
"i" (sizeof(struct bug_entry))); \
} while (0)
#define WARN_ON(x) ({ \
@ -77,13 +78,12 @@ struct bug_entry *find_bug(unsigned long bugaddr);
__WARN(); \
} else { \
__asm__ __volatile__( \
"1: "PPC_TLNEI" %0,0\n" \
".section __bug_table,\"a\"\n" \
"\t"PPC_LONG" 1b,%1,%2,%3\n" \
".previous" \
: : "r" (__ret_warn_on), \
"i" (__LINE__ + BUG_WARNING_TRAP), \
"i" (__FILE__), "i" (__FUNCTION__)); \
"1: "PPC_TLNEI" %4,0\n" \
_EMIT_BUG_ENTRY \
: : "i" (__FILE__), "i" (__LINE__), \
"i" (BUGFLAG_WARNING), \
"i" (sizeof(struct bug_entry)), \
"r" (__ret_warn_on)); \
} \
unlikely(__ret_warn_on); \
})

View File

@ -126,6 +126,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
#define CPU_FTR_NODSISRALIGN ASM_CONST(0x0000000000100000)
#define CPU_FTR_PPC_LE ASM_CONST(0x0000000000200000)
#define CPU_FTR_REAL_LE ASM_CONST(0x0000000000400000)
#define CPU_FTR_FPU_UNAVAILABLE ASM_CONST(0x0000000000800000)
/*
* Add the 64-bit processor unique features in the top half of the word;
@ -152,6 +153,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
#define CPU_FTR_PURR LONG_ASM_CONST(0x0000400000000000)
#define CPU_FTR_CELL_TB_BUG LONG_ASM_CONST(0x0000800000000000)
#define CPU_FTR_SPURR LONG_ASM_CONST(0x0001000000000000)
#define CPU_FTR_DSCR LONG_ASM_CONST(0x0002000000000000)
#ifndef __ASSEMBLY__
@ -295,6 +297,9 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
#define CPU_FTRS_E300 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \
CPU_FTR_COMMON)
#define CPU_FTRS_E300C2 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \
CPU_FTR_COMMON | CPU_FTR_FPU_UNAVAILABLE)
#define CPU_FTRS_CLASSIC32 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE)
#define CPU_FTRS_8XX (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB)
@ -330,13 +335,14 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_MMCRA | CPU_FTR_SMT | \
CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE)
CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
CPU_FTR_DSCR)
#define CPU_FTRS_POWER6X (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_MMCRA | CPU_FTR_SMT | \
CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
CPU_FTR_PURR | CPU_FTR_CI_LARGE_PAGE | \
CPU_FTR_SPURR | CPU_FTR_REAL_LE)
CPU_FTR_SPURR | CPU_FTR_REAL_LE | CPU_FTR_DSCR)
#define CPU_FTRS_CELL (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
@ -364,7 +370,8 @@ enum {
CPU_FTRS_7450_21 | CPU_FTRS_7450_23 | CPU_FTRS_7455_1 |
CPU_FTRS_7455_20 | CPU_FTRS_7455 | CPU_FTRS_7447_10 |
CPU_FTRS_7447 | CPU_FTRS_7447A | CPU_FTRS_82XX |
CPU_FTRS_G2_LE | CPU_FTRS_E300 | CPU_FTRS_CLASSIC32 |
CPU_FTRS_G2_LE | CPU_FTRS_E300 | CPU_FTRS_E300C2 |
CPU_FTRS_CLASSIC32 |
#else
CPU_FTRS_GENERIC_32 |
#endif
@ -403,7 +410,8 @@ enum {
CPU_FTRS_7450_21 & CPU_FTRS_7450_23 & CPU_FTRS_7455_1 &
CPU_FTRS_7455_20 & CPU_FTRS_7455 & CPU_FTRS_7447_10 &
CPU_FTRS_7447 & CPU_FTRS_7447A & CPU_FTRS_82XX &
CPU_FTRS_G2_LE & CPU_FTRS_E300 & CPU_FTRS_CLASSIC32 &
CPU_FTRS_G2_LE & CPU_FTRS_E300 & CPU_FTRS_E300C2 &
CPU_FTRS_CLASSIC32 &
#else
CPU_FTRS_GENERIC_32 &
#endif

View File

@ -20,8 +20,7 @@
#ifndef _ASM_POWERPC_DCR_NATIVE_H
#define _ASM_POWERPC_DCR_NATIVE_H
#ifdef __KERNEL__
#include <asm/reg.h>
#ifndef __ASSEMBLY__
typedef struct {} dcr_host_t;
@ -32,7 +31,41 @@ typedef struct {} dcr_host_t;
#define dcr_read(host, dcr_n) mfdcr(dcr_n)
#define dcr_write(host, dcr_n, value) mtdcr(dcr_n, value)
/* Device Control Registers */
void __mtdcr(int reg, unsigned int val);
unsigned int __mfdcr(int reg);
#define mfdcr(rn) \
({unsigned int rval; \
if (__builtin_constant_p(rn)) \
asm volatile("mfdcr %0," __stringify(rn) \
: "=r" (rval)); \
else \
rval = __mfdcr(rn); \
rval;})
#define mtdcr(rn, v) \
do { \
if (__builtin_constant_p(rn)) \
asm volatile("mtdcr " __stringify(rn) ",%0" \
: : "r" (v)); \
else \
__mtdcr(rn, v); \
} while (0)
/* R/W of indirect DCRs make use of standard naming conventions for DCRs */
#define mfdcri(base, reg) \
({ \
mtdcr(base ## _CFGADDR, base ## _ ## reg); \
mfdcr(base ## _CFGDATA); \
})
#define mtdcri(base, reg, data) \
do { \
mtdcr(base ## _CFGADDR, base ## _ ## reg); \
mtdcr(base ## _CFGDATA, data); \
} while (0)
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_DCR_NATIVE_H */

View File

@ -20,6 +20,7 @@
#ifndef _ASM_POWERPC_DCR_H
#define _ASM_POWERPC_DCR_H
#ifdef __KERNEL__
#ifdef CONFIG_PPC_DCR
#ifdef CONFIG_PPC_DCR_NATIVE
#include <asm/dcr-native.h>
@ -38,5 +39,6 @@ extern unsigned int dcr_resource_len(struct device_node *np,
unsigned int index);
#endif /* CONFIG_PPC_MERGE */
#endif /* CONFIG_PPC_DCR */
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_DCR_H */

View File

@ -107,25 +107,6 @@ static inline void local_irq_save_ptr(unsigned long *flags)
#endif /* CONFIG_PPC64 */
#define mask_irq(irq) \
({ \
irq_desc_t *desc = get_irq_desc(irq); \
if (desc->chip && desc->chip->disable) \
desc->chip->disable(irq); \
})
#define unmask_irq(irq) \
({ \
irq_desc_t *desc = get_irq_desc(irq); \
if (desc->chip && desc->chip->enable) \
desc->chip->enable(irq); \
})
#define ack_irq(irq) \
({ \
irq_desc_t *desc = get_irq_desc(irq); \
if (desc->chip && desc->chip->ack) \
desc->chip->ack(irq); \
})
/*
* interrupt-retrigger: should we handle this via lost interrupts and IPIs
* or should we not care like we do now ? --BenH.

View File

@ -46,8 +46,6 @@ struct mod_arch_specific {
unsigned int num_bugs;
};
extern struct bug_entry *module_find_bug(unsigned long bugaddr);
/*
* Select ELF headers.
* Make empty section for module_frob_arch_sections to expand.

View File

@ -31,12 +31,12 @@ struct pci_controller {
int last_busno;
void __iomem *io_base_virt;
unsigned long io_base_phys;
resource_size_t io_base_phys;
/* Some machines have a non 1:1 mapping of
* the PCI memory space in the CPU bus space
*/
unsigned long pci_mem_offset;
resource_size_t pci_mem_offset;
unsigned long pci_io_size;
struct pci_ops *ops;

View File

@ -143,8 +143,13 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
#define HAVE_PCI_MMAP 1
#ifdef CONFIG_PPC64
/* pci_unmap_{single,page} is not a nop, thus... */
#if defined(CONFIG_PPC64) || defined(CONFIG_NOT_COHERENT_CACHE)
/*
* For 64-bit kernels, pci_unmap_{single,page} is not a nop.
* For 32-bit non-coherent kernels, pci_dma_sync_single_for_cpu() and
* so on are not nops.
* and thus...
*/
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
dma_addr_t ADDR_NAME;
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
@ -158,6 +163,20 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
(((PTR)->LEN_NAME) = (VAL))
#else /* 32-bit && coherent */
/* pci_unmap_{page,single} is a nop so... */
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
#define pci_unmap_addr(PTR, ADDR_NAME) (0)
#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0)
#define pci_unmap_len(PTR, LEN_NAME) (0)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
#endif /* CONFIG_PPC64 || CONFIG_NOT_COHERENT_CACHE */
#ifdef CONFIG_PPC64
/* The PCI address space does not equal the physical memory address
* space (we have an IOMMU). The IDE and SCSI device layers use
* this boolean for bounce buffer decisions.
@ -172,16 +191,8 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
*/
#define PCI_DMA_BUS_IS_PHYS (1)
/* pci_unmap_{page,single} is a nop so... */
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
#define pci_unmap_addr(PTR, ADDR_NAME) (0)
#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0)
#define pci_unmap_len(PTR, LEN_NAME) (0)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
#endif /* CONFIG_PPC64 */
extern void pcibios_resource_to_bus(struct pci_dev *dev,
struct pci_bus_region *region,
struct resource *res);

View File

@ -143,6 +143,7 @@
/* Special Purpose Registers (SPRNs)*/
#define SPRN_CTR 0x009 /* Count Register */
#define SPRN_DSCR 0x11
#define SPRN_CTRLF 0x088
#define SPRN_CTRLT 0x098
#define CTRL_CT 0xc0000000 /* current thread */
@ -163,6 +164,7 @@
#define SPRN_TBRU 0x10D /* Time Base Read Upper Register (user, R/O) */
#define SPRN_TBWL 0x11C /* Time Base Lower Register (super, R/W) */
#define SPRN_TBWU 0x11D /* Time Base Upper Register (super, R/W) */
#define SPRN_SPURR 0x134 /* Scaled PURR */
#define SPRN_HIOR 0x137 /* 970 Hypervisor interrupt offset */
#define SPRN_DBAT0L 0x219 /* Data BAT 0 Lower Register */
#define SPRN_DBAT0U 0x218 /* Data BAT 0 Upper Register */

View File

@ -159,6 +159,7 @@ extern struct rtas_t rtas;
extern void enter_rtas(unsigned long);
extern int rtas_token(const char *service);
extern int rtas_service_present(const char *service);
extern int rtas_call(int token, int, int, int *, ...);
extern void rtas_restart(char *cmd);
extern void rtas_power_off(void);
@ -221,8 +222,6 @@ extern int rtas_get_error_log_max(void);
extern spinlock_t rtas_data_buf_lock;
extern char rtas_data_buf[RTAS_DATA_BUF_SIZE];
extern void rtas_stop_self(void);
/* RMO buffer reserved for user-space RTAS use */
extern unsigned long rtas_rmo_buf;

View File

@ -20,8 +20,8 @@ extern unsigned long pci_bus_mem_base_phys(unsigned int bus);
extern struct pci_controller* pcibios_alloc_controller(void);
/* Helper function for setting up resources */
extern void pci_init_resource(struct resource *res, unsigned long start,
unsigned long end, int flags, char *name);
extern void pci_init_resource(struct resource *res, resource_size_t start,
resource_size_t end, int flags, char *name);
/* Get the PCI host controller for a bus */
extern struct pci_controller* pci_bus_to_hose(int bus);
@ -50,12 +50,12 @@ struct pci_controller {
int bus_offset;
void __iomem *io_base_virt;
unsigned long io_base_phys;
resource_size_t io_base_phys;
/* Some machines (PReP) have a non 1:1 mapping of
* the PCI memory space in the CPU bus space
*/
unsigned long pci_mem_offset;
resource_size_t pci_mem_offset;
struct pci_ops *ops;
volatile unsigned int __iomem *cfg_addr;

View File

@ -61,6 +61,27 @@ extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr);
*/
#define PCI_DMA_BUS_IS_PHYS (1)
#ifdef CONFIG_NOT_COHERENT_CACHE
/*
* pci_unmap_{page,single} are NOPs but pci_dma_sync_single_for_cpu()
* and so on are not, so...
*/
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
dma_addr_t ADDR_NAME;
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
__u32 LEN_NAME;
#define pci_unmap_addr(PTR, ADDR_NAME) \
((PTR)->ADDR_NAME)
#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \
(((PTR)->ADDR_NAME) = (VAL))
#define pci_unmap_len(PTR, LEN_NAME) \
((PTR)->LEN_NAME)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
(((PTR)->LEN_NAME) = (VAL))
#else /* coherent */
/* pci_unmap_{page,single} is a nop so... */
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
@ -69,6 +90,8 @@ extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr);
#define pci_unmap_len(PTR, LEN_NAME) (0)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
#endif /* CONFIG_NOT_COHERENT_CACHE */
#ifdef CONFIG_PCI
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,

View File

@ -9,41 +9,9 @@
#ifndef __ASM_PPC_REG_BOOKE_H__
#define __ASM_PPC_REG_BOOKE_H__
#include <asm/dcr.h>
#ifndef __ASSEMBLY__
/* Device Control Registers */
void __mtdcr(int reg, unsigned int val);
unsigned int __mfdcr(int reg);
#define mfdcr(rn) \
({unsigned int rval; \
if (__builtin_constant_p(rn)) \
asm volatile("mfdcr %0," __stringify(rn) \
: "=r" (rval)); \
else \
rval = __mfdcr(rn); \
rval;})
#define mtdcr(rn, v) \
do { \
if (__builtin_constant_p(rn)) \
asm volatile("mtdcr " __stringify(rn) ",%0" \
: : "r" (v)); \
else \
__mtdcr(rn, v); \
} while (0)
/* R/W of indirect DCRs make use of standard naming conventions for DCRs */
#define mfdcri(base, reg) \
({ \
mtdcr(base ## _CFGADDR, base ## _ ## reg); \
mfdcr(base ## _CFGDATA); \
})
#define mtdcri(base, reg, data) \
do { \
mtdcr(base ## _CFGADDR, base ## _ ## reg); \
mtdcr(base ## _CFGDATA, data); \
} while (0)
/* Performance Monitor Registers */
#define mfpmr(rn) ({unsigned int rval; \
asm volatile("mfpmr %0," __stringify(rn) \

View File

@ -19,6 +19,7 @@
#define _FSL_DEVICE_H_
#include <linux/types.h>
#include <linux/phy.h>
/*
* Some conventions on how we handle peripherals on Freescale chips