diff options
Diffstat (limited to 'arch/powerpc/platforms/ps3')
| -rw-r--r-- | arch/powerpc/platforms/ps3/Kconfig | 36 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/Makefile | 1 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/device-init.c | 6 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/exports.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/gelic_udbg.c | 273 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/htab.c | 31 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/interrupt.c | 198 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/mm.c | 81 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/os-area.c | 7 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/platform.h | 17 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/repository.c | 369 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/setup.c | 15 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/smp.c | 80 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/spu.c | 9 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/system-bus.c | 22 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/time.c | 4 | 
16 files changed, 841 insertions, 310 deletions
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index dfe316b161a..56f274064d6 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -2,12 +2,9 @@ config PPC_PS3  	bool "Sony PS3"  	depends on PPC64 && PPC_BOOK3S  	select PPC_CELL -	select USB_ARCH_HAS_OHCI  	select USB_OHCI_LITTLE_ENDIAN  	select USB_OHCI_BIG_ENDIAN_MMIO -	select USB_ARCH_HAS_EHCI  	select USB_EHCI_BIG_ENDIAN_MMIO -	select MEMORY_HOTPLUG  	select PPC_PCI_CHOICE  	help  	  This option enables support for the Sony PS3 game console @@ -49,7 +46,7 @@ config PS3_HTAB_SIZE  	  system will have optimal runtime performance.  config PS3_DYNAMIC_DMA -	depends on PPC_PS3 && EXPERIMENTAL +	depends on PPC_PS3  	bool "PS3 Platform dynamic DMA page table management"  	default n  	help @@ -74,7 +71,7 @@ config PS3_PS3AV  	help  	  Include support for the PS3 AV Settings driver. -	  This support is required for graphics and sound. In +	  This support is required for PS3 graphics and sound. In  	  general, all users will say Y or M.  config PS3_SYS_MANAGER @@ -85,9 +82,22 @@ config PS3_SYS_MANAGER  	help  	  Include support for the PS3 System Manager. -	  This support is required for system control.  In +	  This support is required for PS3 system control.  In  	  general, all users will say Y or M. +config PS3_REPOSITORY_WRITE +	bool "PS3 Repository write support" if PS3_ADVANCED +	depends on PPC_PS3 +	default n +	help +	  Enables support for writing to the PS3 System Repository. + +	  This support is intended for bootloaders that need to store data +	  in the repository for later boot stages. + +	  If in doubt, say N here and reduce the size of the kernel by a +	  small amount. +  config PS3_STORAGE  	depends on PPC_PS3  	tristate @@ -122,7 +132,7 @@ config PS3_FLASH  	  This support is required to access the PS3 FLASH ROM, which  	  contains the boot loader and some boot options. -	  In general, all users will say Y or M. +	  In general, PS3 OtherOS users will say Y or M.  	  As this driver needs a fixed buffer of 256 KiB of memory, it can  	  be disabled on the kernel command line using "ps3flash=off", to @@ -148,4 +158,16 @@ config PS3_LPM  	  profiling support of the Cell processor with programs like  	  oprofile and perfmon2, then say Y or M, otherwise say N. +config PS3GELIC_UDBG +	bool "PS3 udbg output via UDP broadcasts on Ethernet" +	depends on PPC_PS3 +	help +	  Enables udbg early debugging output by sending broadcast UDP +	  via the Ethernet port (UDP port number 18194). + +	  This driver uses a trivial implementation and is independent +	  from the main PS3 gelic network driver. + +	  If in doubt, say N here. +  endmenu diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile index ac1bdf844ec..02b9e636dab 100644 --- a/arch/powerpc/platforms/ps3/Makefile +++ b/arch/powerpc/platforms/ps3/Makefile @@ -2,6 +2,7 @@ obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o  obj-y += interrupt.o exports.o os-area.o  obj-y += system-bus.o +obj-$(CONFIG_PS3GELIC_UDBG) += gelic_udbg.o  obj-$(CONFIG_SMP) += smp.o  obj-$(CONFIG_SPU_BASE) += spu.o  obj-y += device-init.o diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c index b341018326d..3f175e8aedb 100644 --- a/arch/powerpc/platforms/ps3/device-init.c +++ b/arch/powerpc/platforms/ps3/device-init.c @@ -566,10 +566,10 @@ static int ps3_setup_dynamic_device(const struct ps3_repository_device *repo)  	case PS3_DEV_TYPE_STOR_DISK:  		result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_DISK); -		/* Some devices are not accessable from the Other OS lpar. */ +		/* Some devices are not accessible from the Other OS lpar. */  		if (result == -ENODEV) {  			result = 0; -			pr_debug("%s:%u: not accessable\n", __func__, +			pr_debug("%s:%u: not accessible\n", __func__,  				 __LINE__);  		} @@ -825,7 +825,7 @@ static int ps3_probe_thread(void *data)  	spin_lock_init(&dev.lock); -	res = request_irq(irq, ps3_notification_interrupt, IRQF_DISABLED, +	res = request_irq(irq, ps3_notification_interrupt, 0,  			  "ps3_notification", &dev);  	if (res) {  		pr_err("%s:%u: request_irq failed %d\n", __func__, __LINE__, diff --git a/arch/powerpc/platforms/ps3/exports.c b/arch/powerpc/platforms/ps3/exports.c index a7e8ffd24a6..7df5b7d8fc6 100644 --- a/arch/powerpc/platforms/ps3/exports.c +++ b/arch/powerpc/platforms/ps3/exports.c @@ -18,8 +18,6 @@   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   */ -#include <linux/module.h> -  #define LV1_CALL(name, in, out, num)                          \    extern s64 _lv1_##name(LV1_##in##_IN_##out##_OUT_ARG_DECL); \    EXPORT_SYMBOL(_lv1_##name); diff --git a/arch/powerpc/platforms/ps3/gelic_udbg.c b/arch/powerpc/platforms/ps3/gelic_udbg.c new file mode 100644 index 00000000000..20b46a19a48 --- /dev/null +++ b/arch/powerpc/platforms/ps3/gelic_udbg.c @@ -0,0 +1,273 @@ +/* + * udbg debug output routine via GELIC UDP broadcasts + * + * Copyright (C) 2007 Sony Computer Entertainment Inc. + * Copyright 2006, 2007 Sony Corporation + * Copyright (C) 2010 Hector Martin <hector@marcansoft.com> + * Copyright (C) 2011 Andre Heider <a.heider@gmail.com> + * + * 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/io.h> +#include <asm/udbg.h> +#include <asm/lv1call.h> + +#define GELIC_BUS_ID 1 +#define GELIC_DEVICE_ID 0 +#define GELIC_DEBUG_PORT 18194 +#define GELIC_MAX_MESSAGE_SIZE 1000 + +#define GELIC_LV1_GET_MAC_ADDRESS 1 +#define GELIC_LV1_GET_VLAN_ID 4 +#define GELIC_LV1_VLAN_TX_ETHERNET_0 2 + +#define GELIC_DESCR_DMA_STAT_MASK 0xf0000000 +#define GELIC_DESCR_DMA_CARDOWNED 0xa0000000 + +#define GELIC_DESCR_TX_DMA_IKE 0x00080000 +#define GELIC_DESCR_TX_DMA_NO_CHKSUM 0x00000000 +#define GELIC_DESCR_TX_DMA_FRAME_TAIL 0x00040000 + +#define GELIC_DESCR_DMA_CMD_NO_CHKSUM (GELIC_DESCR_DMA_CARDOWNED | \ +				       GELIC_DESCR_TX_DMA_IKE | \ +				       GELIC_DESCR_TX_DMA_NO_CHKSUM) + +static u64 bus_addr; + +struct gelic_descr { +	/* as defined by the hardware */ +	__be32 buf_addr; +	__be32 buf_size; +	__be32 next_descr_addr; +	__be32 dmac_cmd_status; +	__be32 result_size; +	__be32 valid_size;	/* all zeroes for tx */ +	__be32 data_status; +	__be32 data_error;	/* all zeroes for tx */ +} __attribute__((aligned(32))); + +struct debug_block { +	struct gelic_descr descr; +	u8 pkt[1520]; +} __packed; + +struct ethhdr { +	u8 dest[6]; +	u8 src[6]; +	u16 type; +} __packed; + +struct vlantag { +	u16 vlan; +	u16 subtype; +} __packed; + +struct iphdr { +	u8 ver_len; +	u8 dscp_ecn; +	u16 total_length; +	u16 ident; +	u16 frag_off_flags; +	u8 ttl; +	u8 proto; +	u16 checksum; +	u32 src; +	u32 dest; +} __packed; + +struct udphdr { +	u16 src; +	u16 dest; +	u16 len; +	u16 checksum; +} __packed; + +static __iomem struct ethhdr *h_eth; +static __iomem struct vlantag *h_vlan; +static __iomem struct iphdr *h_ip; +static __iomem struct udphdr *h_udp; + +static __iomem char *pmsg; +static __iomem char *pmsgc; + +static __iomem struct debug_block dbg __attribute__((aligned(32))); + +static int header_size; + +static void map_dma_mem(int bus_id, int dev_id, void *start, size_t len, +			u64 *real_bus_addr) +{ +	s64 result; +	u64 real_addr = ((u64)start) & 0x0fffffffffffffffUL; +	u64 real_end = real_addr + len; +	u64 map_start = real_addr & ~0xfff; +	u64 map_end = (real_end + 0xfff) & ~0xfff; +	u64 bus_addr = 0; + +	u64 flags = 0xf800000000000000UL; + +	result = lv1_allocate_device_dma_region(bus_id, dev_id, +						map_end - map_start, 12, 0, +						&bus_addr); +	if (result) +		lv1_panic(0); + +	result = lv1_map_device_dma_region(bus_id, dev_id, map_start, +					   bus_addr, map_end - map_start, +					   flags); +	if (result) +		lv1_panic(0); + +	*real_bus_addr = bus_addr + real_addr - map_start; +} + +static int unmap_dma_mem(int bus_id, int dev_id, u64 bus_addr, size_t len) +{ +	s64 result; +	u64 real_bus_addr; + +	real_bus_addr = bus_addr & ~0xfff; +	len += bus_addr - real_bus_addr; +	len = (len + 0xfff) & ~0xfff; + +	result = lv1_unmap_device_dma_region(bus_id, dev_id, real_bus_addr, +					     len); +	if (result) +		return result; + +	return lv1_free_device_dma_region(bus_id, dev_id, real_bus_addr); +} + +static void gelic_debug_init(void) +{ +	s64 result; +	u64 v2; +	u64 mac; +	u64 vlan_id; + +	result = lv1_open_device(GELIC_BUS_ID, GELIC_DEVICE_ID, 0); +	if (result) +		lv1_panic(0); + +	map_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID, &dbg, sizeof(dbg), +		    &bus_addr); + +	memset(&dbg, 0, sizeof(dbg)); + +	dbg.descr.buf_addr = bus_addr + offsetof(struct debug_block, pkt); + +	wmb(); + +	result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID, +				 GELIC_LV1_GET_MAC_ADDRESS, 0, 0, 0, +				 &mac, &v2); +	if (result) +		lv1_panic(0); + +	mac <<= 16; + +	h_eth = (struct ethhdr *)dbg.pkt; + +	memset(&h_eth->dest, 0xff, 6); +	memcpy(&h_eth->src, &mac, 6); + +	header_size = sizeof(struct ethhdr); + +	result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID, +				 GELIC_LV1_GET_VLAN_ID, +				 GELIC_LV1_VLAN_TX_ETHERNET_0, 0, 0, +				 &vlan_id, &v2); +	if (!result) { +		h_eth->type = 0x8100; + +		header_size += sizeof(struct vlantag); +		h_vlan = (struct vlantag *)(h_eth + 1); +		h_vlan->vlan = vlan_id; +		h_vlan->subtype = 0x0800; +		h_ip = (struct iphdr *)(h_vlan + 1); +	} else { +		h_eth->type = 0x0800; +		h_ip = (struct iphdr *)(h_eth + 1); +	} + +	header_size += sizeof(struct iphdr); +	h_ip->ver_len = 0x45; +	h_ip->ttl = 10; +	h_ip->proto = 0x11; +	h_ip->src = 0x00000000; +	h_ip->dest = 0xffffffff; + +	header_size += sizeof(struct udphdr); +	h_udp = (struct udphdr *)(h_ip + 1); +	h_udp->src = GELIC_DEBUG_PORT; +	h_udp->dest = GELIC_DEBUG_PORT; + +	pmsgc = pmsg = (char *)(h_udp + 1); +} + +static void gelic_debug_shutdown(void) +{ +	if (bus_addr) +		unmap_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID, +			      bus_addr, sizeof(dbg)); +	lv1_close_device(GELIC_BUS_ID, GELIC_DEVICE_ID); +} + +static void gelic_sendbuf(int msgsize) +{ +	u16 *p; +	u32 sum; +	int i; + +	dbg.descr.buf_size = header_size + msgsize; +	h_ip->total_length = msgsize + sizeof(struct udphdr) + +			     sizeof(struct iphdr); +	h_udp->len = msgsize + sizeof(struct udphdr); + +	h_ip->checksum = 0; +	sum = 0; +	p = (u16 *)h_ip; +	for (i = 0; i < 5; i++) +		sum += *p++; +	h_ip->checksum = ~(sum + (sum >> 16)); + +	dbg.descr.dmac_cmd_status = GELIC_DESCR_DMA_CMD_NO_CHKSUM | +				    GELIC_DESCR_TX_DMA_FRAME_TAIL; +	dbg.descr.result_size = 0; +	dbg.descr.data_status = 0; + +	wmb(); + +	lv1_net_start_tx_dma(GELIC_BUS_ID, GELIC_DEVICE_ID, bus_addr, 0); + +	while ((dbg.descr.dmac_cmd_status & GELIC_DESCR_DMA_STAT_MASK) == +	       GELIC_DESCR_DMA_CARDOWNED) +		cpu_relax(); +} + +static void ps3gelic_udbg_putc(char ch) +{ +	*pmsgc++ = ch; +	if (ch == '\n' || (pmsgc-pmsg) >= GELIC_MAX_MESSAGE_SIZE) { +		gelic_sendbuf(pmsgc-pmsg); +		pmsgc = pmsg; +	} +} + +void __init udbg_init_ps3gelic(void) +{ +	gelic_debug_init(); +	udbg_putc = ps3gelic_udbg_putc; +} + +void udbg_shutdown_ps3gelic(void) +{ +	udbg_putc = NULL; +	gelic_debug_shutdown(); +} +EXPORT_SYMBOL(udbg_shutdown_ps3gelic); diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index 3124cf791eb..3e270e3412a 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c @@ -27,6 +27,7 @@  #include <asm/lv1call.h>  #include <asm/ps3fb.h> +#define PS3_VERBOSE_RESULT  #include "platform.h"  /** @@ -43,9 +44,9 @@ enum ps3_lpar_vas_id {  static DEFINE_SPINLOCK(ps3_htab_lock); -static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va, +static long ps3_hpte_insert(unsigned long hpte_group, unsigned long vpn,  	unsigned long pa, unsigned long rflags, unsigned long vflags, -	int psize, int ssize) +	int psize, int apsize, int ssize)  {  	int result;  	u64 hpte_v, hpte_r; @@ -61,8 +62,8 @@ static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va,  	 */  	vflags &= ~HPTE_V_SECONDARY; -	hpte_v = hpte_encode_v(va, psize, ssize) | vflags | HPTE_V_VALID; -	hpte_r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize) | rflags; +	hpte_v = hpte_encode_v(vpn, psize, apsize, ssize) | vflags | HPTE_V_VALID; +	hpte_r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize, apsize) | rflags;  	spin_lock_irqsave(&ps3_htab_lock, flags); @@ -75,8 +76,9 @@ static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va,  	if (result) {  		/* all entries bolted !*/ -		pr_info("%s:result=%d va=%lx pa=%lx ix=%lx v=%llx r=%llx\n", -			__func__, result, va, pa, hpte_group, hpte_v, hpte_r); +		pr_info("%s:result=%s vpn=%lx pa=%lx ix=%lx v=%llx r=%llx\n", +			__func__, ps3_result(result), vpn, pa, hpte_group, +			hpte_v, hpte_r);  		BUG();  	} @@ -107,7 +109,8 @@ static long ps3_hpte_remove(unsigned long hpte_group)  }  static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp, -	unsigned long va, int psize, int ssize, int local) +			      unsigned long vpn, int psize, int apsize, +			      int ssize, int local)  {  	int result;  	u64 hpte_v, want_v, hpte_rs; @@ -115,7 +118,7 @@ static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp,  	unsigned long flags;  	long ret; -	want_v = hpte_encode_v(va, psize, ssize); +	want_v = hpte_encode_avpn(vpn, psize, ssize);  	spin_lock_irqsave(&ps3_htab_lock, flags); @@ -125,8 +128,8 @@ static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp,  				       &hpte_rs);  	if (result) { -		pr_info("%s: res=%d read va=%lx slot=%lx psize=%d\n", -			__func__, result, va, slot, psize); +		pr_info("%s: result=%s read vpn=%lx slot=%lx psize=%d\n", +			__func__, ps3_result(result), vpn, slot, psize);  		BUG();  	} @@ -159,8 +162,8 @@ static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,  	panic("ps3_hpte_updateboltedpp() not implemented");  } -static void ps3_hpte_invalidate(unsigned long slot, unsigned long va, -	int psize, int ssize, int local) +static void ps3_hpte_invalidate(unsigned long slot, unsigned long vpn, +				int psize, int apsize, int ssize, int local)  {  	unsigned long flags;  	int result; @@ -170,8 +173,8 @@ static void ps3_hpte_invalidate(unsigned long slot, unsigned long va,  	result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, slot, 0, 0);  	if (result) { -		pr_info("%s: res=%d va=%lx slot=%lx psize=%d\n", -			__func__, result, va, slot, psize); +		pr_info("%s: result=%s vpn=%lx slot=%lx psize=%d\n", +			__func__, ps3_result(result), vpn, slot, psize);  		BUG();  	} diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 59d9712d736..5f3b23220b8 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -19,7 +19,7 @@   */  #include <linux/kernel.h> -#include <linux/module.h> +#include <linux/export.h>  #include <linux/irq.h>  #include <asm/machdep.h> @@ -31,20 +31,20 @@  #if defined(DEBUG)  #define DBG udbg_printf +#define FAIL udbg_printf  #else -#define DBG pr_debug +#define DBG pr_devel +#define FAIL pr_debug  #endif  /**   * struct ps3_bmp - a per cpu irq status and mask bitmap structure   * @status: 256 bit status bitmap indexed by plug - * @unused_1: + * @unused_1: Alignment   * @mask: 256 bit mask bitmap indexed by plug - * @unused_2: - * @lock: - * @ipi_debug_brk_mask: + * @unused_2: Alignment   * - * The HV mantains per SMT thread mappings of HV outlet to HV plug on + * The HV maintains per SMT thread mappings of HV outlet to HV plug on   * behalf of the guest.  These mappings are implemented as 256 bit guest   * supplied bitmaps indexed by plug number.  The addresses of the bitmaps   * are registered with the HV through lv1_configure_irq_state_bitmap(). @@ -73,21 +73,25 @@ struct ps3_bmp {  		unsigned long mask;  		u64 unused_2[3];  	}; -	u64 ipi_debug_brk_mask; -	spinlock_t lock;  };  /**   * struct ps3_private - a per cpu data structure   * @bmp: ps3_bmp structure + * @bmp_lock: Syncronize access to bmp. + * @ipi_debug_brk_mask: Mask for debug break IPIs   * @ppe_id: HV logical_ppe_id   * @thread_id: HV thread_id + * @ipi_mask: Mask of IPI virqs   */  struct ps3_private {  	struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN))); +	spinlock_t bmp_lock;  	u64 ppe_id;  	u64 thread_id; +	unsigned long ipi_debug_brk_mask; +	unsigned long ipi_mask;  };  static DEFINE_PER_CPU(struct ps3_private, ps3_private); @@ -99,16 +103,16 @@ static DEFINE_PER_CPU(struct ps3_private, ps3_private);   * Sets ps3_bmp.mask and calls lv1_did_update_interrupt_mask().   */ -static void ps3_chip_mask(unsigned int virq) +static void ps3_chip_mask(struct irq_data *d)  { -	struct ps3_private *pd = get_irq_chip_data(virq); +	struct ps3_private *pd = irq_data_get_irq_chip_data(d);  	unsigned long flags; -	pr_debug("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__, -		pd->thread_id, virq); +	DBG("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__, +		pd->thread_id, d->irq);  	local_irq_save(flags); -	clear_bit(63 - virq, &pd->bmp.mask); +	clear_bit(63 - d->irq, &pd->bmp.mask);  	lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);  	local_irq_restore(flags);  } @@ -120,16 +124,16 @@ static void ps3_chip_mask(unsigned int virq)   * Clears ps3_bmp.mask and calls lv1_did_update_interrupt_mask().   */ -static void ps3_chip_unmask(unsigned int virq) +static void ps3_chip_unmask(struct irq_data *d)  { -	struct ps3_private *pd = get_irq_chip_data(virq); +	struct ps3_private *pd = irq_data_get_irq_chip_data(d);  	unsigned long flags; -	pr_debug("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__, -		pd->thread_id, virq); +	DBG("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__, +		pd->thread_id, d->irq);  	local_irq_save(flags); -	set_bit(63 - virq, &pd->bmp.mask); +	set_bit(63 - d->irq, &pd->bmp.mask);  	lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);  	local_irq_restore(flags);  } @@ -141,10 +145,14 @@ static void ps3_chip_unmask(unsigned int virq)   * Calls lv1_end_of_interrupt_ext().   */ -static void ps3_chip_eoi(unsigned int virq) +static void ps3_chip_eoi(struct irq_data *d)  { -	const struct ps3_private *pd = get_irq_chip_data(virq); -	lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, virq); +	const struct ps3_private *pd = irq_data_get_irq_chip_data(d); + +	/* non-IPIs are EOIed here. */ + +	if (!test_bit(63 - d->irq, &pd->ipi_mask)) +		lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq);  }  /** @@ -153,9 +161,9 @@ static void ps3_chip_eoi(unsigned int virq)  static struct irq_chip ps3_irq_chip = {  	.name = "ps3", -	.mask = ps3_chip_mask, -	.unmask = ps3_chip_unmask, -	.eoi = ps3_chip_eoi, +	.irq_mask = ps3_chip_mask, +	.irq_unmask = ps3_chip_unmask, +	.irq_eoi = ps3_chip_eoi,  };  /** @@ -185,24 +193,24 @@ static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,  	*virq = irq_create_mapping(NULL, outlet);  	if (*virq == NO_IRQ) { -		pr_debug("%s:%d: irq_create_mapping failed: outlet %lu\n", +		FAIL("%s:%d: irq_create_mapping failed: outlet %lu\n",  			__func__, __LINE__, outlet);  		result = -ENOMEM;  		goto fail_create;  	} -	pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__, +	DBG("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,  		outlet, cpu, *virq); -	result = set_irq_chip_data(*virq, pd); +	result = irq_set_chip_data(*virq, pd);  	if (result) { -		pr_debug("%s:%d: set_irq_chip_data failed\n", +		FAIL("%s:%d: irq_set_chip_data failed\n",  			__func__, __LINE__);  		goto fail_set;  	} -	ps3_chip_mask(*virq); +	ps3_chip_mask(irq_get_irq_data(*virq));  	return result; @@ -221,15 +229,15 @@ fail_create:  static int ps3_virq_destroy(unsigned int virq)  { -	const struct ps3_private *pd = get_irq_chip_data(virq); +	const struct ps3_private *pd = irq_get_chip_data(virq); -	pr_debug("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__, +	DBG("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__,  		__LINE__, pd->ppe_id, pd->thread_id, virq); -	set_irq_chip_data(virq, NULL); +	irq_set_chip_data(virq, NULL);  	irq_dispose_mapping(virq); -	pr_debug("%s:%d <-\n", __func__, __LINE__); +	DBG("%s:%d <-\n", __func__, __LINE__);  	return 0;  } @@ -252,11 +260,11 @@ int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,  	result = ps3_virq_setup(cpu, outlet, virq);  	if (result) { -		pr_debug("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__); +		FAIL("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__);  		goto fail_setup;  	} -	pd = get_irq_chip_data(*virq); +	pd = irq_get_chip_data(*virq);  	/* Binds outlet to cpu + virq. */ @@ -264,7 +272,7 @@ int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,  		outlet, 0);  	if (result) { -		pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", +		FAIL("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",  		__func__, __LINE__, ps3_result(result));  		result = -EPERM;  		goto fail_connect; @@ -291,17 +299,17 @@ EXPORT_SYMBOL_GPL(ps3_irq_plug_setup);  int ps3_irq_plug_destroy(unsigned int virq)  {  	int result; -	const struct ps3_private *pd = get_irq_chip_data(virq); +	const struct ps3_private *pd = irq_get_chip_data(virq); -	pr_debug("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__, +	DBG("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__,  		__LINE__, pd->ppe_id, pd->thread_id, virq); -	ps3_chip_mask(virq); +	ps3_chip_mask(irq_get_irq_data(virq));  	result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq);  	if (result) -		pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", +		FAIL("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",  		__func__, __LINE__, ps3_result(result));  	ps3_virq_destroy(virq); @@ -329,7 +337,7 @@ int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq)  	result = lv1_construct_event_receive_port(&outlet);  	if (result) { -		pr_debug("%s:%d: lv1_construct_event_receive_port failed: %s\n", +		FAIL("%s:%d: lv1_construct_event_receive_port failed: %s\n",  			__func__, __LINE__, ps3_result(result));  		*virq = NO_IRQ;  		return result; @@ -355,14 +363,14 @@ int ps3_event_receive_port_destroy(unsigned int virq)  {  	int result; -	pr_debug(" -> %s:%d virq %u\n", __func__, __LINE__, virq); +	DBG(" -> %s:%d virq %u\n", __func__, __LINE__, virq); -	ps3_chip_mask(virq); +	ps3_chip_mask(irq_get_irq_data(virq));  	result = lv1_destruct_event_receive_port(virq_to_hw(virq));  	if (result) -		pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", +		FAIL("%s:%d: lv1_destruct_event_receive_port failed: %s\n",  			__func__, __LINE__, ps3_result(result));  	/* @@ -370,7 +378,7 @@ int ps3_event_receive_port_destroy(unsigned int virq)  	 * calls from interrupt context (smp_call_function) when kexecing.  	 */ -	pr_debug(" <- %s:%d\n", __func__, __LINE__); +	DBG(" <- %s:%d\n", __func__, __LINE__);  	return result;  } @@ -406,7 +414,7 @@ int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev,  		dev->dev_id, virq_to_hw(*virq), dev->interrupt_id);  	if (result) { -		pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port" +		FAIL("%s:%d: lv1_connect_interrupt_event_receive_port"  			" failed: %s\n", __func__, __LINE__,  			ps3_result(result));  		ps3_event_receive_port_destroy(*virq); @@ -414,7 +422,7 @@ int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev,  		return result;  	} -	pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, +	DBG("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,  		dev->interrupt_id, *virq);  	return 0; @@ -428,14 +436,14 @@ int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev,  	int result; -	pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, +	DBG(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,  		dev->interrupt_id, virq);  	result = lv1_disconnect_interrupt_event_receive_port(dev->bus_id,  		dev->dev_id, virq_to_hw(virq), dev->interrupt_id);  	if (result) -		pr_debug("%s:%d: lv1_disconnect_interrupt_event_receive_port" +		FAIL("%s:%d: lv1_disconnect_interrupt_event_receive_port"  			" failed: %s\n", __func__, __LINE__,  			ps3_result(result)); @@ -450,7 +458,7 @@ int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev,  	result = ps3_virq_destroy(virq);  	BUG_ON(result); -	pr_debug(" <- %s:%d\n", __func__, __LINE__); +	DBG(" <- %s:%d\n", __func__, __LINE__);  	return result;  }  EXPORT_SYMBOL(ps3_sb_event_receive_port_destroy); @@ -475,7 +483,7 @@ int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id,  	result = lv1_construct_io_irq_outlet(interrupt_id, &outlet);  	if (result) { -		pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n", +		FAIL("%s:%d: lv1_construct_io_irq_outlet failed: %s\n",  			__func__, __LINE__, ps3_result(result));  		return result;  	} @@ -492,7 +500,7 @@ int ps3_io_irq_destroy(unsigned int virq)  	int result;  	unsigned long outlet = virq_to_hw(virq); -	ps3_chip_mask(virq); +	ps3_chip_mask(irq_get_irq_data(virq));  	/*  	 * lv1_destruct_io_irq_outlet() will destroy the IRQ plug, @@ -505,7 +513,7 @@ int ps3_io_irq_destroy(unsigned int virq)  	result = lv1_destruct_io_irq_outlet(outlet);  	if (result) -		pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", +		FAIL("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",  			__func__, __LINE__, ps3_result(result));  	return result; @@ -537,7 +545,7 @@ int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp,  	result = lv1_configure_virtual_uart_irq(lpar_addr, &outlet);  	if (result) { -		pr_debug("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n", +		FAIL("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n",  			__func__, __LINE__, ps3_result(result));  		return result;  	} @@ -553,11 +561,11 @@ int ps3_vuart_irq_destroy(unsigned int virq)  {  	int result; -	ps3_chip_mask(virq); +	ps3_chip_mask(irq_get_irq_data(virq));  	result = lv1_deconfigure_virtual_uart_irq();  	if (result) { -		pr_debug("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n", +		FAIL("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n",  			__func__, __LINE__, ps3_result(result));  		return result;  	} @@ -590,7 +598,7 @@ int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id,  	result = lv1_get_spe_irq_outlet(spe_id, class, &outlet);  	if (result) { -		pr_debug("%s:%d: lv1_get_spe_irq_outlet failed: %s\n", +		FAIL("%s:%d: lv1_get_spe_irq_outlet failed: %s\n",  			__func__, __LINE__, ps3_result(result));  		return result;  	} @@ -605,7 +613,7 @@ int ps3_spe_irq_destroy(unsigned int virq)  {  	int result; -	ps3_chip_mask(virq); +	ps3_chip_mask(irq_get_irq_data(virq));  	result = ps3_irq_plug_destroy(virq);  	BUG_ON(result); @@ -621,7 +629,7 @@ int ps3_spe_irq_destroy(unsigned int virq)  static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu,  	const char* func, int line)  { -	pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n", +	pr_debug("%s:%d: %s %u {%04llx_%04llx_%04llx_%04llx}\n",  		func, line, header, cpu,  		*p >> 48, (*p >> 32) & 0xffff, (*p >> 16) & 0xffff,  		*p & 0xffff); @@ -630,7 +638,7 @@ static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu,  static void __maybe_unused _dump_256_bmp(const char *header,  	const u64 *p, unsigned cpu, const char* func, int line)  { -	pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n", +	pr_debug("%s:%d: %s %u {%016llx:%016llx:%016llx:%016llx}\n",  		func, line, header, cpu, p[0], p[1], p[2], p[3]);  } @@ -639,10 +647,10 @@ static void _dump_bmp(struct ps3_private* pd, const char* func, int line)  {  	unsigned long flags; -	spin_lock_irqsave(&pd->bmp.lock, flags); +	spin_lock_irqsave(&pd->bmp_lock, flags);  	_dump_64_bmp("stat", &pd->bmp.status, pd->thread_id, func, line); -	_dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line); -	spin_unlock_irqrestore(&pd->bmp.lock, flags); +	_dump_64_bmp("mask", (u64*)&pd->bmp.mask, pd->thread_id, func, line); +	spin_unlock_irqrestore(&pd->bmp_lock, flags);  }  #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__) @@ -651,39 +659,33 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd,  {  	unsigned long flags; -	spin_lock_irqsave(&pd->bmp.lock, flags); -	_dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line); -	spin_unlock_irqrestore(&pd->bmp.lock, flags); +	spin_lock_irqsave(&pd->bmp_lock, flags); +	_dump_64_bmp("mask", (u64*)&pd->bmp.mask, pd->thread_id, func, line); +	spin_unlock_irqrestore(&pd->bmp_lock, flags);  }  #else  static void dump_bmp(struct ps3_private* pd) {};  #endif /* defined(DEBUG) */ -static void ps3_host_unmap(struct irq_host *h, unsigned int virq) -{ -	set_irq_chip_data(virq, NULL); -} - -static int ps3_host_map(struct irq_host *h, unsigned int virq, +static int ps3_host_map(struct irq_domain *h, unsigned int virq,  	irq_hw_number_t hwirq)  { -	pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, +	DBG("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,  		virq); -	set_irq_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq); +	irq_set_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq);  	return 0;  } -static int ps3_host_match(struct irq_host *h, struct device_node *np) +static int ps3_host_match(struct irq_domain *h, struct device_node *np)  {  	/* Match all */  	return 1;  } -static struct irq_host_ops ps3_host_ops = { +static const struct irq_domain_ops ps3_host_ops = {  	.map = ps3_host_map, -	.unmap = ps3_host_unmap,  	.match = ps3_host_match,  }; @@ -691,10 +693,20 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)  {  	struct ps3_private *pd = &per_cpu(ps3_private, cpu); -	pd->bmp.ipi_debug_brk_mask = 0x8000000000000000UL >> virq; +	set_bit(63 - virq, &pd->ipi_debug_brk_mask); + +	DBG("%s:%d: cpu %u, virq %u, mask %lxh\n", __func__, __LINE__, +		cpu, virq, pd->ipi_debug_brk_mask); +} + +void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq) +{ +	struct ps3_private *pd = &per_cpu(ps3_private, cpu); + +	set_bit(63 - virq, &pd->ipi_mask); -	pr_debug("%s:%d: cpu %u, virq %u, mask %llxh\n", __func__, __LINE__, -		cpu, virq, pd->bmp.ipi_debug_brk_mask); +	DBG("%s:%d: cpu %u, virq %u, ipi_mask %lxh\n", __func__, __LINE__, +		cpu, virq, pd->ipi_mask);  }  static unsigned int ps3_get_irq(void) @@ -705,14 +717,14 @@ static unsigned int ps3_get_irq(void)  	/* check for ipi break first to stop this cpu ASAP */ -	if (x & pd->bmp.ipi_debug_brk_mask) -		x &= pd->bmp.ipi_debug_brk_mask; +	if (x & pd->ipi_debug_brk_mask) +		x &= pd->ipi_debug_brk_mask;  	asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x));  	plug &= 0x3f;  	if (unlikely(plug == NO_IRQ)) { -		pr_debug("%s:%d: no plug found: thread_id %llu\n", __func__, +		DBG("%s:%d: no plug found: thread_id %llu\n", __func__,  			__LINE__, pd->thread_id);  		dump_bmp(&per_cpu(ps3_private, 0));  		dump_bmp(&per_cpu(ps3_private, 1)); @@ -726,6 +738,12 @@ static unsigned int ps3_get_irq(void)  		BUG();  	}  #endif + +	/* IPIs are EOIed here. */ + +	if (test_bit(63 - plug, &pd->ipi_mask)) +		lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, plug); +  	return plug;  } @@ -733,21 +751,19 @@ void __init ps3_init_IRQ(void)  {  	int result;  	unsigned cpu; -	struct irq_host *host; +	struct irq_domain *host; -	host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops, -		PS3_INVALID_OUTLET); +	host = irq_domain_add_nomap(NULL, PS3_PLUG_MAX + 1, &ps3_host_ops, NULL);  	irq_set_default_host(host); -	irq_set_virq_count(PS3_PLUG_MAX + 1);  	for_each_possible_cpu(cpu) {  		struct ps3_private *pd = &per_cpu(ps3_private, cpu);  		lv1_get_logical_ppe_id(&pd->ppe_id);  		pd->thread_id = get_hard_smp_processor_id(cpu); -		spin_lock_init(&pd->bmp.lock); +		spin_lock_init(&pd->bmp_lock); -		pr_debug("%s:%d: ppe_id %llu, thread_id %llu, bmp %lxh\n", +		DBG("%s:%d: ppe_id %llu, thread_id %llu, bmp %lxh\n",  			__func__, __LINE__, pd->ppe_id, pd->thread_id,  			ps3_mm_phys_to_lpar(__pa(&pd->bmp))); @@ -755,7 +771,7 @@ void __init ps3_init_IRQ(void)  			pd->thread_id, ps3_mm_phys_to_lpar(__pa(&pd->bmp)));  		if (result) -			pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:" +			FAIL("%s:%d: lv1_configure_irq_state_bitmap failed:"  				" %s\n", __func__, __LINE__,  				ps3_result(result));  	} diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index c2045880e67..0c9f643d9e2 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -19,8 +19,7 @@   */  #include <linux/kernel.h> -#include <linux/module.h> -#include <linux/memory_hotplug.h> +#include <linux/export.h>  #include <linux/memblock.h>  #include <linux/slab.h> @@ -29,6 +28,7 @@  #include <asm/prom.h>  #include <asm/udbg.h>  #include <asm/lv1call.h> +#include <asm/setup.h>  #include "platform.h" @@ -78,12 +78,14 @@ enum {   * @base: base address   * @size: size in bytes   * @offset: difference between base and rm.size + * @destroy: flag if region should be destroyed upon shutdown   */  struct mem_region {  	u64 base;  	u64 size;  	unsigned long offset; +	int destroy;  };  /** @@ -95,7 +97,7 @@ struct mem_region {   * The HV virtual address space (vas) allows for hotplug memory regions.   * Memory regions can be created and destroyed in the vas at runtime.   * @rm: real mode (bootmem) region - * @r1: hotplug memory region(s) + * @r1: highmem region(s)   *   * ps3 addresses   * virt_addr: a cpu 'translated' effective address @@ -221,10 +223,6 @@ void ps3_mm_vas_destroy(void)  	}  } -/*============================================================================*/ -/* memory hotplug routines                                                    */ -/*============================================================================*/ -  /**   * ps3_mm_region_create - create a memory region in the vas   * @r: pointer to a struct mem_region to accept initialized values @@ -261,6 +259,7 @@ static int ps3_mm_region_create(struct mem_region *r, unsigned long size)  		goto zero_region;  	} +	r->destroy = 1;  	r->offset = r->base - map.rm.size;  	return result; @@ -278,7 +277,14 @@ static void ps3_mm_region_destroy(struct mem_region *r)  {  	int result; +	if (!r->destroy) { +		pr_info("%s:%d: Not destroying high region: %llxh %llxh\n", +			__func__, __LINE__, r->base, r->size); +		return; +	} +  	DBG("%s:%d: r->base = %llxh\n", __func__, __LINE__, r->base); +  	if (r->base) {  		result = lv1_release_memory(r->base);  		BUG_ON(result); @@ -287,51 +293,36 @@ static void ps3_mm_region_destroy(struct mem_region *r)  	}  } -/** - * ps3_mm_add_memory - hot add memory - */ - -static int __init ps3_mm_add_memory(void) +static int ps3_mm_get_repository_highmem(struct mem_region *r)  {  	int result; -	unsigned long start_addr; -	unsigned long start_pfn; -	unsigned long nr_pages; - -	if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) -		return -ENODEV; -	BUG_ON(!mem_init_done); +	/* Assume a single highmem region. */ -	start_addr = map.rm.size; -	start_pfn = start_addr >> PAGE_SHIFT; -	nr_pages = (map.r1.size + PAGE_SIZE - 1) >> PAGE_SHIFT; +	result = ps3_repository_read_highmem_info(0, &r->base, &r->size); -	DBG("%s:%d: start_addr %lxh, start_pfn %lxh, nr_pages %lxh\n", -		__func__, __LINE__, start_addr, start_pfn, nr_pages); - -	result = add_memory(0, start_addr, map.r1.size); +	if (result) +		goto zero_region; -	if (result) { -		pr_err("%s:%d: add_memory failed: (%d)\n", -			__func__, __LINE__, result); -		return result; +	if (!r->base || !r->size) { +		result = -1; +		goto zero_region;  	} -	memblock_add(start_addr, map.r1.size); -	memblock_analyze(); +	r->offset = r->base - map.rm.size; -	result = online_pages(start_pfn, nr_pages); +	DBG("%s:%d: Found high region in repository: %llxh %llxh\n", +	    __func__, __LINE__, r->base, r->size); -	if (result) -		pr_err("%s:%d: online_pages failed: (%d)\n", -			__func__, __LINE__, result); +	return 0; +zero_region: +	DBG("%s:%d: No high region in repository.\n", __func__, __LINE__); + +	r->size = r->base = r->offset = 0;  	return result;  } -device_initcall(ps3_mm_add_memory); -  /*============================================================================*/  /* dma routines                                                               */  /*============================================================================*/ @@ -1217,13 +1208,23 @@ void __init ps3_mm_init(void)  	BUG_ON(map.rm.base);  	BUG_ON(!map.rm.size); +	/* Check if we got the highmem region from an earlier boot step */ -	/* arrange to do this in ps3_mm_add_memory */ -	ps3_mm_region_create(&map.r1, map.total - map.rm.size); +	if (ps3_mm_get_repository_highmem(&map.r1)) +		ps3_mm_region_create(&map.r1, map.total - map.rm.size);  	/* correct map.total for the real total amount of memory we use */  	map.total = map.rm.size + map.r1.size; +	if (!map.r1.size) { +		DBG("%s:%d: No highmem region found\n", __func__, __LINE__); +	} else { +		DBG("%s:%d: Adding highmem region: %llxh %llxh\n", +			__func__, __LINE__, map.rm.size, +			map.total - map.rm.size); +		memblock_add(map.rm.size, map.total - map.rm.size); +	} +  	DBG(" <- %s:%d\n", __func__, __LINE__);  } diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index 5b759b66959..09787139834 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -23,6 +23,7 @@  #include <linux/workqueue.h>  #include <linux/fs.h>  #include <linux/syscalls.h> +#include <linux/export.h>  #include <linux/ctype.h>  #include <linux/memblock.h>  #include <linux/of.h> @@ -279,13 +280,13 @@ static void os_area_set_property(struct device_node *node,  	if (tmp) {  		pr_debug("%s:%d found %s\n", __func__, __LINE__, prop->name); -		prom_remove_property(node, tmp); +		of_remove_property(node, tmp);  	} -	result = prom_add_property(node, prop); +	result = of_add_property(node, prop);  	if (result) -		pr_debug("%s:%d prom_set_property failed\n", __func__, +		pr_debug("%s:%d of_set_property failed\n", __func__,  			__LINE__);  } diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 9a196a88eda..d71329a8e32 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -43,6 +43,7 @@ void ps3_mm_shutdown(void);  void ps3_init_IRQ(void);  void ps3_shutdown_IRQ(int cpu);  void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq); +void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq);  /* smp */ @@ -187,6 +188,22 @@ int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size);  int ps3_repository_read_region_total(u64 *region_total);  int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size,  	u64 *region_total); +int ps3_repository_read_highmem_region_count(unsigned int *region_count); +int ps3_repository_read_highmem_base(unsigned int region_index, +	u64 *highmem_base); +int ps3_repository_read_highmem_size(unsigned int region_index, +	u64 *highmem_size); +int ps3_repository_read_highmem_info(unsigned int region_index, +	u64 *highmem_base, u64 *highmem_size); + +int ps3_repository_write_highmem_region_count(unsigned int region_count); +int ps3_repository_write_highmem_base(unsigned int region_index, +	u64 highmem_base); +int ps3_repository_write_highmem_size(unsigned int region_index, +	u64 highmem_size); +int ps3_repository_write_highmem_info(unsigned int region_index, +	u64 highmem_base, u64 highmem_size); +int ps3_repository_delete_highmem_info(unsigned int region_index);  /* repository pme info */ diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index 5e304c292f6..bfccdc7cb85 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c @@ -44,7 +44,7 @@ static void _dump_field(const char *hdr, u64 n, const char *func, int line)  		s[i] = (in[i] <= 126 && in[i] >= 32) ? in[i] : '.';  	s[i] = 0; -	pr_debug("%s:%d: %s%016llx : %s\n", func, line, hdr, n, s); +	pr_devel("%s:%d: %s%016llx : %s\n", func, line, hdr, n, s);  #endif  } @@ -53,7 +53,7 @@ static void _dump_field(const char *hdr, u64 n, const char *func, int line)  static void _dump_node_name(unsigned int lpar_id, u64 n1, u64 n2, u64 n3,  	u64 n4, const char *func, int line)  { -	pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id); +	pr_devel("%s:%d: lpar: %u\n", func, line, lpar_id);  	_dump_field("n1: ", n1, func, line);  	_dump_field("n2: ", n2, func, line);  	_dump_field("n3: ", n3, func, line); @@ -65,13 +65,13 @@ static void _dump_node_name(unsigned int lpar_id, u64 n1, u64 n2, u64 n3,  static void _dump_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,  	u64 v1, u64 v2, const char *func, int line)  { -	pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id); +	pr_devel("%s:%d: lpar: %u\n", func, line, lpar_id);  	_dump_field("n1: ", n1, func, line);  	_dump_field("n2: ", n2, func, line);  	_dump_field("n3: ", n3, func, line);  	_dump_field("n4: ", n4, func, line); -	pr_debug("%s:%d: v1: %016llx\n", func, line, v1); -	pr_debug("%s:%d: v2: %016llx\n", func, line, v2); +	pr_devel("%s:%d: v1: %016llx\n", func, line, v1); +	pr_devel("%s:%d: v2: %016llx\n", func, line, v2);  }  /** @@ -131,11 +131,11 @@ static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,  		lpar_id = id;  	} -	result = lv1_get_repository_node_value(lpar_id, n1, n2, n3, n4, &v1, +	result = lv1_read_repository_node(lpar_id, n1, n2, n3, n4, &v1,  		&v2);  	if (result) { -		pr_debug("%s:%d: lv1_get_repository_node_value failed: %s\n", +		pr_warn("%s:%d: lv1_read_repository_node failed: %s\n",  			__func__, __LINE__, ps3_result(result));  		dump_node_name(lpar_id, n1, n2, n3, n4);  		return -ENOENT; @@ -149,10 +149,10 @@ static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,  		*_v2 = v2;  	if (v1 && !_v1) -		pr_debug("%s:%d: warning: discarding non-zero v1: %016llx\n", +		pr_devel("%s:%d: warning: discarding non-zero v1: %016llx\n",  			__func__, __LINE__, v1);  	if (v2 && !_v2) -		pr_debug("%s:%d: warning: discarding non-zero v2: %016llx\n", +		pr_devel("%s:%d: warning: discarding non-zero v2: %016llx\n",  			__func__, __LINE__, v2);  	return 0; @@ -184,7 +184,7 @@ int ps3_repository_read_bus_type(unsigned int bus_index,  	enum ps3_bus_type *bus_type)  {  	int result; -	u64 v1; +	u64 v1 = 0;  	result = read_node(PS3_LPAR_ID_PME,  		make_first_field("bus", bus_index), @@ -199,7 +199,7 @@ int ps3_repository_read_bus_num_dev(unsigned int bus_index,  	unsigned int *num_dev)  {  	int result; -	u64 v1; +	u64 v1 = 0;  	result = read_node(PS3_LPAR_ID_PME,  		make_first_field("bus", bus_index), @@ -239,7 +239,7 @@ int ps3_repository_read_dev_type(unsigned int bus_index,  	unsigned int dev_index, enum ps3_dev_type *dev_type)  {  	int result; -	u64 v1; +	u64 v1 = 0;  	result = read_node(PS3_LPAR_ID_PME,  		make_first_field("bus", bus_index), @@ -256,8 +256,8 @@ int ps3_repository_read_dev_intr(unsigned int bus_index,  	enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id)  {  	int result; -	u64 v1; -	u64 v2; +	u64 v1 = 0; +	u64 v2 = 0;  	result = read_node(PS3_LPAR_ID_PME,  		make_first_field("bus", bus_index), @@ -275,7 +275,7 @@ int ps3_repository_read_dev_reg_type(unsigned int bus_index,  	enum ps3_reg_type *reg_type)  {  	int result; -	u64 v1; +	u64 v1 = 0;  	result = read_node(PS3_LPAR_ID_PME,  		make_first_field("bus", bus_index), @@ -323,16 +323,16 @@ int ps3_repository_find_device(struct ps3_repository_device *repo)  	result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev);  	if (result) { -		pr_debug("%s:%d read_bus_num_dev failed\n", __func__, __LINE__); +		pr_devel("%s:%d read_bus_num_dev failed\n", __func__, __LINE__);  		return result;  	} -	pr_debug("%s:%d: bus_type %u, bus_index %u, bus_id %llu, num_dev %u\n", +	pr_devel("%s:%d: bus_type %u, bus_index %u, bus_id %llu, num_dev %u\n",  		__func__, __LINE__, tmp.bus_type, tmp.bus_index, tmp.bus_id,  		num_dev);  	if (tmp.dev_index >= num_dev) { -		pr_debug("%s:%d: no device found\n", __func__, __LINE__); +		pr_devel("%s:%d: no device found\n", __func__, __LINE__);  		return -ENODEV;  	} @@ -340,7 +340,7 @@ int ps3_repository_find_device(struct ps3_repository_device *repo)  		&tmp.dev_type);  	if (result) { -		pr_debug("%s:%d read_dev_type failed\n", __func__, __LINE__); +		pr_devel("%s:%d read_dev_type failed\n", __func__, __LINE__);  		return result;  	} @@ -348,12 +348,12 @@ int ps3_repository_find_device(struct ps3_repository_device *repo)  		&tmp.dev_id);  	if (result) { -		pr_debug("%s:%d ps3_repository_read_dev_id failed\n", __func__, +		pr_devel("%s:%d ps3_repository_read_dev_id failed\n", __func__,  		__LINE__);  		return result;  	} -	pr_debug("%s:%d: found: dev_type %u, dev_index %u, dev_id %llu\n", +	pr_devel("%s:%d: found: dev_type %u, dev_index %u, dev_id %llu\n",  		__func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id);  	*repo = tmp; @@ -367,14 +367,14 @@ int ps3_repository_find_device_by_id(struct ps3_repository_device *repo,  	struct ps3_repository_device tmp;  	unsigned int num_dev; -	pr_debug(" -> %s:%u: find device by id %llu:%llu\n", __func__, __LINE__, +	pr_devel(" -> %s:%u: find device by id %llu:%llu\n", __func__, __LINE__,  		 bus_id, dev_id);  	for (tmp.bus_index = 0; tmp.bus_index < 10; tmp.bus_index++) {  		result = ps3_repository_read_bus_id(tmp.bus_index,  						    &tmp.bus_id);  		if (result) { -			pr_debug("%s:%u read_bus_id(%u) failed\n", __func__, +			pr_devel("%s:%u read_bus_id(%u) failed\n", __func__,  				 __LINE__, tmp.bus_index);  			return result;  		} @@ -382,23 +382,23 @@ int ps3_repository_find_device_by_id(struct ps3_repository_device *repo,  		if (tmp.bus_id == bus_id)  			goto found_bus; -		pr_debug("%s:%u: skip, bus_id %llu\n", __func__, __LINE__, +		pr_devel("%s:%u: skip, bus_id %llu\n", __func__, __LINE__,  			 tmp.bus_id);  	} -	pr_debug(" <- %s:%u: bus not found\n", __func__, __LINE__); +	pr_devel(" <- %s:%u: bus not found\n", __func__, __LINE__);  	return result;  found_bus:  	result = ps3_repository_read_bus_type(tmp.bus_index, &tmp.bus_type);  	if (result) { -		pr_debug("%s:%u read_bus_type(%u) failed\n", __func__, +		pr_devel("%s:%u read_bus_type(%u) failed\n", __func__,  			 __LINE__, tmp.bus_index);  		return result;  	}  	result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev);  	if (result) { -		pr_debug("%s:%u read_bus_num_dev failed\n", __func__, +		pr_devel("%s:%u read_bus_num_dev failed\n", __func__,  			 __LINE__);  		return result;  	} @@ -408,7 +408,7 @@ found_bus:  						    tmp.dev_index,  						    &tmp.dev_id);  		if (result) { -			pr_debug("%s:%u read_dev_id(%u:%u) failed\n", __func__, +			pr_devel("%s:%u read_dev_id(%u:%u) failed\n", __func__,  				 __LINE__, tmp.bus_index, tmp.dev_index);  			return result;  		} @@ -416,45 +416,45 @@ found_bus:  		if (tmp.dev_id == dev_id)  			goto found_dev; -		pr_debug("%s:%u: skip, dev_id %llu\n", __func__, __LINE__, +		pr_devel("%s:%u: skip, dev_id %llu\n", __func__, __LINE__,  			 tmp.dev_id);  	} -	pr_debug(" <- %s:%u: dev not found\n", __func__, __LINE__); +	pr_devel(" <- %s:%u: dev not found\n", __func__, __LINE__);  	return result;  found_dev:  	result = ps3_repository_read_dev_type(tmp.bus_index, tmp.dev_index,  					      &tmp.dev_type);  	if (result) { -		pr_debug("%s:%u read_dev_type failed\n", __func__, __LINE__); +		pr_devel("%s:%u read_dev_type failed\n", __func__, __LINE__);  		return result;  	} -	pr_debug(" <- %s:%u: found: type (%u:%u) index (%u:%u) id (%llu:%llu)\n", +	pr_devel(" <- %s:%u: found: type (%u:%u) index (%u:%u) id (%llu:%llu)\n",  		 __func__, __LINE__, tmp.bus_type, tmp.dev_type, tmp.bus_index,  		 tmp.dev_index, tmp.bus_id, tmp.dev_id);  	*repo = tmp;  	return 0;  } -int __devinit ps3_repository_find_devices(enum ps3_bus_type bus_type, +int ps3_repository_find_devices(enum ps3_bus_type bus_type,  	int (*callback)(const struct ps3_repository_device *repo))  {  	int result = 0;  	struct ps3_repository_device repo; -	pr_debug(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type); +	pr_devel(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type);  	repo.bus_type = bus_type;  	result = ps3_repository_find_bus(repo.bus_type, 0, &repo.bus_index);  	if (result) { -		pr_debug(" <- %s:%u: bus not found\n", __func__, __LINE__); +		pr_devel(" <- %s:%u: bus not found\n", __func__, __LINE__);  		return result;  	}  	result = ps3_repository_read_bus_id(repo.bus_index, &repo.bus_id);  	if (result) { -		pr_debug("%s:%d read_bus_id(%u) failed\n", __func__, __LINE__, +		pr_devel("%s:%d read_bus_id(%u) failed\n", __func__, __LINE__,  			 repo.bus_index);  		return result;  	} @@ -469,13 +469,13 @@ int __devinit ps3_repository_find_devices(enum ps3_bus_type bus_type,  		result = callback(&repo);  		if (result) { -			pr_debug("%s:%d: abort at callback\n", __func__, +			pr_devel("%s:%d: abort at callback\n", __func__,  				__LINE__);  			break;  		}  	} -	pr_debug(" <- %s:%d\n", __func__, __LINE__); +	pr_devel(" <- %s:%d\n", __func__, __LINE__);  	return result;  } @@ -489,7 +489,7 @@ int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from,  	for (i = from; i < 10; i++) {  		error = ps3_repository_read_bus_type(i, &type);  		if (error) { -			pr_debug("%s:%d read_bus_type failed\n", +			pr_devel("%s:%d read_bus_type failed\n",  				__func__, __LINE__);  			*bus_index = UINT_MAX;  			return error; @@ -509,7 +509,7 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *repo,  	int result = 0;  	unsigned int res_index; -	pr_debug("%s:%d: find intr_type %u\n", __func__, __LINE__, intr_type); +	pr_devel("%s:%d: find intr_type %u\n", __func__, __LINE__, intr_type);  	*interrupt_id = UINT_MAX; @@ -521,7 +521,7 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *repo,  			repo->dev_index, res_index, &t, &id);  		if (result) { -			pr_debug("%s:%d read_dev_intr failed\n", +			pr_devel("%s:%d read_dev_intr failed\n",  				__func__, __LINE__);  			return result;  		} @@ -535,7 +535,7 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *repo,  	if (res_index == 10)  		return -ENODEV; -	pr_debug("%s:%d: found intr_type %u at res_index %u\n", +	pr_devel("%s:%d: found intr_type %u at res_index %u\n",  		__func__, __LINE__, intr_type, res_index);  	return result; @@ -547,7 +547,7 @@ int ps3_repository_find_reg(const struct ps3_repository_device *repo,  	int result = 0;  	unsigned int res_index; -	pr_debug("%s:%d: find reg_type %u\n", __func__, __LINE__, reg_type); +	pr_devel("%s:%d: find reg_type %u\n", __func__, __LINE__, reg_type);  	*bus_addr = *len = 0; @@ -560,7 +560,7 @@ int ps3_repository_find_reg(const struct ps3_repository_device *repo,  			repo->dev_index, res_index, &t, &a, &l);  		if (result) { -			pr_debug("%s:%d read_dev_reg failed\n", +			pr_devel("%s:%d read_dev_reg failed\n",  				__func__, __LINE__);  			return result;  		} @@ -575,7 +575,7 @@ int ps3_repository_find_reg(const struct ps3_repository_device *repo,  	if (res_index == 10)  		return -ENODEV; -	pr_debug("%s:%d: found reg_type %u at res_index %u\n", +	pr_devel("%s:%d: found reg_type %u at res_index %u\n",  		__func__, __LINE__, reg_type, res_index);  	return result; @@ -615,7 +615,7 @@ int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index,  	unsigned int dev_index, unsigned int *num_regions)  {  	int result; -	u64 v1; +	u64 v1 = 0;  	result = read_node(PS3_LPAR_ID_PME,  		make_first_field("bus", bus_index), @@ -631,7 +631,7 @@ int ps3_repository_read_stor_dev_region_id(unsigned int bus_index,  	unsigned int *region_id)  {  	int result; -	u64 v1; +	u64 v1 = 0;  	result = read_node(PS3_LPAR_ID_PME,  	    make_first_field("bus", bus_index), @@ -779,6 +779,72 @@ int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, u64 *region_total)  }  /** + * ps3_repository_read_highmem_region_count - Read the number of highmem regions + * + * Bootloaders must arrange the repository nodes such that regions are indexed + * with a region_index from 0 to region_count-1. + */ + +int ps3_repository_read_highmem_region_count(unsigned int *region_count) +{ +	int result; +	u64 v1 = 0; + +	result = read_node(PS3_LPAR_ID_CURRENT, +		make_first_field("highmem", 0), +		make_field("region", 0), +		make_field("count", 0), +		0, +		&v1, NULL); +	*region_count = v1; +	return result; +} + + +int ps3_repository_read_highmem_base(unsigned int region_index, +	u64 *highmem_base) +{ +	return read_node(PS3_LPAR_ID_CURRENT, +		make_first_field("highmem", 0), +		make_field("region", region_index), +		make_field("base", 0), +		0, +		highmem_base, NULL); +} + +int ps3_repository_read_highmem_size(unsigned int region_index, +	u64 *highmem_size) +{ +	return read_node(PS3_LPAR_ID_CURRENT, +		make_first_field("highmem", 0), +		make_field("region", region_index), +		make_field("size", 0), +		0, +		highmem_size, NULL); +} + +/** + * ps3_repository_read_highmem_info - Read high memory region info + * @region_index: Region index, {0,..,region_count-1}. + * @highmem_base: High memory base address. + * @highmem_size: High memory size. + * + * Bootloaders that preallocate highmem regions must place the + * region info into the repository at these well known nodes. + */ + +int ps3_repository_read_highmem_info(unsigned int region_index, +	u64 *highmem_base, u64 *highmem_size) +{ +	int result; + +	*highmem_base = 0; +	result = ps3_repository_read_highmem_base(region_index, highmem_base); +	return result ? result +		: ps3_repository_read_highmem_size(region_index, highmem_size); +} + +/**   * ps3_repository_read_num_spu_reserved - Number of physical spus reserved.   * @num_spu: Number of physical spus.   */ @@ -786,7 +852,7 @@ int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, u64 *region_total)  int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved)  {  	int result; -	u64 v1; +	u64 v1 = 0;  	result = read_node(PS3_LPAR_ID_CURRENT,  		make_first_field("bi", 0), @@ -805,7 +871,7 @@ int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved)  int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id)  {  	int result; -	u64 v1; +	u64 v1 = 0;  	result = read_node(PS3_LPAR_ID_CURRENT,  		make_first_field("bi", 0), @@ -827,8 +893,8 @@ int ps3_repository_read_spu_resource_id(unsigned int res_index,  	enum ps3_spu_resource_type *resource_type, unsigned int *resource_id)  {  	int result; -	u64 v1; -	u64 v2; +	u64 v1 = 0; +	u64 v2 = 0;  	result = read_node(PS3_LPAR_ID_CURRENT,  		make_first_field("bi", 0), @@ -854,7 +920,7 @@ static int ps3_repository_read_boot_dat_address(u64 *address)  int ps3_repository_read_boot_dat_size(unsigned int *size)  {  	int result; -	u64 v1; +	u64 v1 = 0;  	result = read_node(PS3_LPAR_ID_CURRENT,  		make_first_field("bi", 0), @@ -869,7 +935,7 @@ int ps3_repository_read_boot_dat_size(unsigned int *size)  int ps3_repository_read_vuart_av_port(unsigned int *port)  {  	int result; -	u64 v1; +	u64 v1 = 0;  	result = read_node(PS3_LPAR_ID_CURRENT,  		make_first_field("bi", 0), @@ -884,7 +950,7 @@ int ps3_repository_read_vuart_av_port(unsigned int *port)  int ps3_repository_read_vuart_sysmgr_port(unsigned int *port)  {  	int result; -	u64 v1; +	u64 v1 = 0;  	result = read_node(PS3_LPAR_ID_CURRENT,  		make_first_field("bi", 0), @@ -919,7 +985,7 @@ int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size)  int ps3_repository_read_num_be(unsigned int *num_be)  {  	int result; -	u64 v1; +	u64 v1 = 0;  	result = read_node(PS3_LPAR_ID_PME,  		make_first_field("ben", 0), @@ -1002,6 +1068,138 @@ int ps3_repository_read_lpm_privileges(unsigned int be_index, u64 *lpar,  			    lpar, rights);  } +#if defined(CONFIG_PS3_REPOSITORY_WRITE) + +static int create_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2) +{ +	int result; + +	dump_node(0, n1, n2, n3, n4, v1, v2); + +	result = lv1_create_repository_node(n1, n2, n3, n4, v1, v2); + +	if (result) { +		pr_devel("%s:%d: lv1_create_repository_node failed: %s\n", +			__func__, __LINE__, ps3_result(result)); +		return -ENOENT; +	} + +	return 0; +} + +static int delete_node(u64 n1, u64 n2, u64 n3, u64 n4) +{ +	int result; + +	dump_node(0, n1, n2, n3, n4, 0, 0); + +	result = lv1_delete_repository_node(n1, n2, n3, n4); + +	if (result) { +		pr_devel("%s:%d: lv1_delete_repository_node failed: %s\n", +			__func__, __LINE__, ps3_result(result)); +		return -ENOENT; +	} + +	return 0; +} + +static int write_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2) +{ +	int result; + +	result = create_node(n1, n2, n3, n4, v1, v2); + +	if (!result) +		return 0; + +	result = lv1_write_repository_node(n1, n2, n3, n4, v1, v2); + +	if (result) { +		pr_devel("%s:%d: lv1_write_repository_node failed: %s\n", +			__func__, __LINE__, ps3_result(result)); +		return -ENOENT; +	} + +	return 0; +} + +int ps3_repository_write_highmem_region_count(unsigned int region_count) +{ +	int result; +	u64 v1 = (u64)region_count; + +	result = write_node( +		make_first_field("highmem", 0), +		make_field("region", 0), +		make_field("count", 0), +		0, +		v1, 0); +	return result; +} + +int ps3_repository_write_highmem_base(unsigned int region_index, +	u64 highmem_base) +{ +	return write_node( +		make_first_field("highmem", 0), +		make_field("region", region_index), +		make_field("base", 0), +		0, +		highmem_base, 0); +} + +int ps3_repository_write_highmem_size(unsigned int region_index, +	u64 highmem_size) +{ +	return write_node( +		make_first_field("highmem", 0), +		make_field("region", region_index), +		make_field("size", 0), +		0, +		highmem_size, 0); +} + +int ps3_repository_write_highmem_info(unsigned int region_index, +	u64 highmem_base, u64 highmem_size) +{ +	int result; + +	result = ps3_repository_write_highmem_base(region_index, highmem_base); +	return result ? result +		: ps3_repository_write_highmem_size(region_index, highmem_size); +} + +static int ps3_repository_delete_highmem_base(unsigned int region_index) +{ +	return delete_node( +		make_first_field("highmem", 0), +		make_field("region", region_index), +		make_field("base", 0), +		0); +} + +static int ps3_repository_delete_highmem_size(unsigned int region_index) +{ +	return delete_node( +		make_first_field("highmem", 0), +		make_field("region", region_index), +		make_field("size", 0), +		0); +} + +int ps3_repository_delete_highmem_info(unsigned int region_index) +{ +	int result; + +	result = ps3_repository_delete_highmem_base(region_index); +	result += ps3_repository_delete_highmem_size(region_index); + +	return result ? -1 : 0; +} + +#endif /* defined(CONFIG_PS3_WRITE_REPOSITORY) */ +  #if defined(DEBUG)  int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo) @@ -1009,7 +1207,7 @@ int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo)  	int result = 0;  	unsigned int res_index; -	pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, +	pr_devel(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,  		repo->bus_index, repo->dev_index);  	for (res_index = 0; res_index < 10; res_index++) { @@ -1021,13 +1219,13 @@ int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo)  		if (result) {  			if (result !=  LV1_NO_ENTRY) -				pr_debug("%s:%d ps3_repository_read_dev_intr" +				pr_devel("%s:%d ps3_repository_read_dev_intr"  					" (%u:%u) failed\n", __func__, __LINE__,  					repo->bus_index, repo->dev_index);  			break;  		} -		pr_debug("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n", +		pr_devel("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n",  			__func__, __LINE__, repo->bus_index, repo->dev_index,  			intr_type, interrupt_id);  	} @@ -1042,18 +1240,18 @@ int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo)  		if (result) {  			if (result !=  LV1_NO_ENTRY) -				pr_debug("%s:%d ps3_repository_read_dev_reg" +				pr_devel("%s:%d ps3_repository_read_dev_reg"  					" (%u:%u) failed\n", __func__, __LINE__,  					repo->bus_index, repo->dev_index);  			break;  		} -		pr_debug("%s:%d (%u:%u) reg_type %u, bus_addr %lxh, len %lxh\n", +		pr_devel("%s:%d (%u:%u) reg_type %u, bus_addr %llxh, len %llxh\n",  			__func__, __LINE__, repo->bus_index, repo->dev_index,  			reg_type, bus_addr, len);  	} -	pr_debug(" <- %s:%d\n", __func__, __LINE__); +	pr_devel(" <- %s:%d\n", __func__, __LINE__);  	return result;  } @@ -1063,22 +1261,22 @@ static int dump_stor_dev_info(struct ps3_repository_device *repo)  	unsigned int num_regions, region_index;  	u64 port, blk_size, num_blocks; -	pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, +	pr_devel(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,  		repo->bus_index, repo->dev_index);  	result = ps3_repository_read_stor_dev_info(repo->bus_index,  		repo->dev_index, &port, &blk_size, &num_blocks, &num_regions);  	if (result) { -		pr_debug("%s:%d ps3_repository_read_stor_dev_info" +		pr_devel("%s:%d ps3_repository_read_stor_dev_info"  			" (%u:%u) failed\n", __func__, __LINE__,  			repo->bus_index, repo->dev_index);  		goto out;  	} -	pr_debug("%s:%d  (%u:%u): port %lu, blk_size %lu, num_blocks " -		 "%lu, num_regions %u\n", -		 __func__, __LINE__, repo->bus_index, repo->dev_index, port, -		 blk_size, num_blocks, num_regions); +	pr_devel("%s:%d  (%u:%u): port %llu, blk_size %llu, num_blocks " +		 "%llu, num_regions %u\n", +		 __func__, __LINE__, repo->bus_index, repo->dev_index, +		port, blk_size, num_blocks, num_regions);  	for (region_index = 0; region_index < num_regions; region_index++) {  		unsigned int region_id; @@ -1088,19 +1286,20 @@ static int dump_stor_dev_info(struct ps3_repository_device *repo)  			repo->dev_index, region_index, ®ion_id,  			®ion_start, ®ion_size);  		if (result) { -			 pr_debug("%s:%d ps3_repository_read_stor_dev_region" +			 pr_devel("%s:%d ps3_repository_read_stor_dev_region"  				  " (%u:%u) failed\n", __func__, __LINE__,  				  repo->bus_index, repo->dev_index);  			break;  		} -		pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n", +		pr_devel("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n",  			__func__, __LINE__, repo->bus_index, repo->dev_index, -			region_id, region_start, region_size); +			region_id, (unsigned long)region_start, +			(unsigned long)region_size);  	}  out: -	pr_debug(" <- %s:%d\n", __func__, __LINE__); +	pr_devel(" <- %s:%d\n", __func__, __LINE__);  	return result;  } @@ -1109,7 +1308,7 @@ static int dump_device_info(struct ps3_repository_device *repo,  {  	int result = 0; -	pr_debug(" -> %s:%d: bus_%u\n", __func__, __LINE__, repo->bus_index); +	pr_devel(" -> %s:%d: bus_%u\n", __func__, __LINE__, repo->bus_index);  	for (repo->dev_index = 0; repo->dev_index < num_dev;  		repo->dev_index++) { @@ -1118,7 +1317,7 @@ static int dump_device_info(struct ps3_repository_device *repo,  			repo->dev_index, &repo->dev_type);  		if (result) { -			pr_debug("%s:%d ps3_repository_read_dev_type" +			pr_devel("%s:%d ps3_repository_read_dev_type"  				" (%u:%u) failed\n", __func__, __LINE__,  				repo->bus_index, repo->dev_index);  			break; @@ -1128,15 +1327,15 @@ static int dump_device_info(struct ps3_repository_device *repo,  			repo->dev_index, &repo->dev_id);  		if (result) { -			pr_debug("%s:%d ps3_repository_read_dev_id" +			pr_devel("%s:%d ps3_repository_read_dev_id"  				" (%u:%u) failed\n", __func__, __LINE__,  				repo->bus_index, repo->dev_index);  			continue;  		} -		pr_debug("%s:%d  (%u:%u): dev_type %u, dev_id %lu\n", __func__, +		pr_devel("%s:%d  (%u:%u): dev_type %u, dev_id %lu\n", __func__,  			__LINE__, repo->bus_index, repo->dev_index, -			repo->dev_type, repo->dev_id); +			repo->dev_type, (unsigned long)repo->dev_id);  		ps3_repository_dump_resource_info(repo); @@ -1144,7 +1343,7 @@ static int dump_device_info(struct ps3_repository_device *repo,  			dump_stor_dev_info(repo);  	} -	pr_debug(" <- %s:%d\n", __func__, __LINE__); +	pr_devel(" <- %s:%d\n", __func__, __LINE__);  	return result;  } @@ -1153,7 +1352,7 @@ int ps3_repository_dump_bus_info(void)  	int result = 0;  	struct ps3_repository_device repo; -	pr_debug(" -> %s:%d\n", __func__, __LINE__); +	pr_devel(" -> %s:%d\n", __func__, __LINE__);  	memset(&repo, 0, sizeof(repo)); @@ -1164,7 +1363,7 @@ int ps3_repository_dump_bus_info(void)  			&repo.bus_type);  		if (result) { -			pr_debug("%s:%d read_bus_type(%u) failed\n", +			pr_devel("%s:%d read_bus_type(%u) failed\n",  				__func__, __LINE__, repo.bus_index);  			break;  		} @@ -1173,32 +1372,32 @@ int ps3_repository_dump_bus_info(void)  			&repo.bus_id);  		if (result) { -			pr_debug("%s:%d read_bus_id(%u) failed\n", +			pr_devel("%s:%d read_bus_id(%u) failed\n",  				__func__, __LINE__, repo.bus_index);  			continue;  		}  		if (repo.bus_index != repo.bus_id) -			pr_debug("%s:%d bus_index != bus_id\n", +			pr_devel("%s:%d bus_index != bus_id\n",  				__func__, __LINE__);  		result = ps3_repository_read_bus_num_dev(repo.bus_index,  			&num_dev);  		if (result) { -			pr_debug("%s:%d read_bus_num_dev(%u) failed\n", +			pr_devel("%s:%d read_bus_num_dev(%u) failed\n",  				__func__, __LINE__, repo.bus_index);  			continue;  		} -		pr_debug("%s:%d bus_%u: bus_type %u, bus_id %lu, num_dev %u\n", +		pr_devel("%s:%d bus_%u: bus_type %u, bus_id %lu, num_dev %u\n",  			__func__, __LINE__, repo.bus_index, repo.bus_type, -			repo.bus_id, num_dev); +			(unsigned long)repo.bus_id, num_dev);  		dump_device_info(&repo, num_dev);  	} -	pr_debug(" <- %s:%d\n", __func__, __LINE__); +	pr_devel(" <- %s:%d\n", __func__, __LINE__);  	return result;  } diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 149bea2ce58..3f509f86432 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -23,6 +23,7 @@  #include <linux/fs.h>  #include <linux/root_dev.h>  #include <linux/console.h> +#include <linux/export.h>  #include <linux/bootmem.h>  #include <asm/machdep.h> @@ -183,19 +184,25 @@ early_param("ps3flash", early_parse_ps3flash);  #define prealloc_ps3flash_bounce_buffer()	do { } while (0)  #endif -static int ps3_set_dabr(unsigned long dabr) +static int ps3_set_dabr(unsigned long dabr, unsigned long dabrx)  { -	enum {DABR_USER = 1, DABR_KERNEL = 2,}; +	/* Have to set at least one bit in the DABRX */ +	if (dabrx == 0 && dabr == 0) +		dabrx = DABRX_USER; +	/* hypervisor only allows us to set BTI, Kernel and user */ +	dabrx &= DABRX_BTI | DABRX_KERNEL | DABRX_USER; -	return lv1_set_dabr(dabr, DABR_KERNEL | DABR_USER) ? -1 : 0; +	return lv1_set_dabr(dabr, dabrx) ? -1 : 0;  }  static void __init ps3_setup_arch(void)  { +	u64 tmp;  	DBG(" -> %s:%d\n", __func__, __LINE__); -	lv1_get_version_info(&ps3_firmware_version.raw); +	lv1_get_version_info(&ps3_firmware_version.raw, &tmp); +  	printk(KERN_INFO "PS3 firmware version %u.%u.%u\n",  	       ps3_firmware_version.major, ps3_firmware_version.minor,  	       ps3_firmware_version.rev); diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index 51ffde40af2..b358bec6c8c 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c @@ -39,7 +39,7 @@  #define MSG_COUNT 4  static DEFINE_PER_CPU(unsigned int [MSG_COUNT], ps3_ipi_virqs); -static void do_message_pass(int target, int msg) +static void ps3_smp_message_pass(int cpu, int msg)  {  	int result;  	unsigned int virq; @@ -49,72 +49,59 @@ static void do_message_pass(int target, int msg)  		return;  	} -	virq = per_cpu(ps3_ipi_virqs, target)[msg]; +	virq = per_cpu(ps3_ipi_virqs, cpu)[msg];  	result = ps3_send_event_locally(virq);  	if (result)  		DBG("%s:%d: ps3_send_event_locally(%d, %d) failed" -			" (%d)\n", __func__, __LINE__, target, msg, result); +			" (%d)\n", __func__, __LINE__, cpu, msg, result);  } -static void ps3_smp_message_pass(int target, int msg) +static int __init ps3_smp_probe(void)  {  	int cpu; -	if (target < NR_CPUS) -		do_message_pass(target, msg); -	else if (target == MSG_ALL_BUT_SELF) { -		for_each_online_cpu(cpu) -			if (cpu != smp_processor_id()) -				do_message_pass(cpu, msg); -	} else { -		for_each_online_cpu(cpu) -			do_message_pass(cpu, msg); -	} -} +	for (cpu = 0; cpu < 2; cpu++) { +		int result; +		unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu); +		int i; -static int ps3_smp_probe(void) -{ -	return 2; -} +		DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); -static void __init ps3_smp_setup_cpu(int cpu) -{ -	int result; -	unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu); -	int i; +		/* +		* Check assumptions on ps3_ipi_virqs[] indexing. If this +		* check fails, then a different mapping of PPC_MSG_ +		* to index needs to be setup. +		*/ -	DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); +		BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION    != 0); +		BUILD_BUG_ON(PPC_MSG_RESCHEDULE       != 1); +		BUILD_BUG_ON(PPC_MSG_TICK_BROADCAST   != 2); +		BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK   != 3); -	/* -	 * Check assumptions on ps3_ipi_virqs[] indexing. If this -	 * check fails, then a different mapping of PPC_MSG_ -	 * to index needs to be setup. -	 */ +		for (i = 0; i < MSG_COUNT; i++) { +			result = ps3_event_receive_port_setup(cpu, &virqs[i]); -	BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION    != 0); -	BUILD_BUG_ON(PPC_MSG_RESCHEDULE       != 1); -	BUILD_BUG_ON(PPC_MSG_CALL_FUNC_SINGLE != 2); -	BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK   != 3); +			if (result) +				continue; -	for (i = 0; i < MSG_COUNT; i++) { -		result = ps3_event_receive_port_setup(cpu, &virqs[i]); +			DBG("%s:%d: (%d, %d) => virq %u\n", +				__func__, __LINE__, cpu, i, virqs[i]); -		if (result) -			continue; +			result = smp_request_message_ipi(virqs[i], i); -		DBG("%s:%d: (%d, %d) => virq %u\n", -			__func__, __LINE__, cpu, i, virqs[i]); +			if (result) +				virqs[i] = NO_IRQ; +			else +				ps3_register_ipi_irq(cpu, virqs[i]); +		} -		result = smp_request_message_ipi(virqs[i], i); +		ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_DEBUGGER_BREAK]); -		if (result) -			virqs[i] = NO_IRQ; +		DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);  	} -	ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_DEBUGGER_BREAK]); - -	DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu); +	return 2;  }  void ps3_smp_cleanup_cpu(int cpu) @@ -137,7 +124,6 @@ static struct smp_ops_t ps3_smp_ops = {  	.probe		= ps3_smp_probe,  	.message_pass	= ps3_smp_message_pass,  	.kick_cpu	= smp_generic_kick_cpu, -	.setup_cpu	= ps3_smp_setup_cpu,  };  void smp_init_ps3(void) diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index 39a472e9e80..a0bca05e26b 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -22,6 +22,7 @@  #include <linux/init.h>  #include <linux/slab.h>  #include <linux/mmzone.h> +#include <linux/export.h>  #include <linux/io.h>  #include <linux/mm.h> @@ -142,7 +143,7 @@ static void _dump_areas(unsigned int spe_id, unsigned long priv2,  	pr_debug("%s:%d: shadow:  %lxh\n", func, line, shadow);  } -inline u64 ps3_get_spe_id(void *arg) +u64 ps3_get_spe_id(void *arg)  {  	return spu_pdata(arg)->spe_id;  } @@ -153,7 +154,7 @@ static unsigned long get_vas_id(void)  	u64 id;  	lv1_get_logical_ppe_id(&id); -	lv1_get_virtual_address_space_id_of_ppe(id, &id); +	lv1_get_virtual_address_space_id_of_ppe(&id);  	return id;  } @@ -197,7 +198,7 @@ static void spu_unmap(struct spu *spu)   * The current HV requires the spu shadow regs to be mapped with the   * PTE page protection bits set as read-only (PP=3).  This implementation   * uses the low level __ioremap() to bypass the page protection settings - * inforced by ioremap_flags() to get the needed PTE bits set for the + * inforced by ioremap_prot() to get the needed PTE bits set for the   * shadow regs.   */ @@ -214,7 +215,7 @@ static int __init setup_areas(struct spu *spu)  		goto fail_ioremap;  	} -	spu->local_store = (__force void *)ioremap_flags(spu->local_store_phys, +	spu->local_store = (__force void *)ioremap_prot(spu->local_store_phys,  		LS_SIZE, _PAGE_NO_CACHE);  	if (!spu->local_store) { diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 23083c39752..5606fe36faf 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -20,7 +20,7 @@  #include <linux/kernel.h>  #include <linux/init.h> -#include <linux/module.h> +#include <linux/export.h>  #include <linux/dma-mapping.h>  #include <linux/err.h>  #include <linux/slab.h> @@ -515,7 +515,8 @@ core_initcall(ps3_system_bus_init);   * to the dma address (mapping) of the first page.   */  static void * ps3_alloc_coherent(struct device *_dev, size_t size, -				      dma_addr_t *dma_handle, gfp_t flag) +				 dma_addr_t *dma_handle, gfp_t flag, +				 struct dma_attrs *attrs)  {  	int result;  	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); @@ -552,7 +553,7 @@ clean_none:  }  static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, -	dma_addr_t dma_handle) +			      dma_addr_t dma_handle, struct dma_attrs *attrs)  {  	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); @@ -695,22 +696,29 @@ static int ps3_dma_supported(struct device *_dev, u64 mask)  	return mask >= DMA_BIT_MASK(32);  } +static u64 ps3_dma_get_required_mask(struct device *_dev) +{ +	return DMA_BIT_MASK(32); +} +  static struct dma_map_ops ps3_sb_dma_ops = { -	.alloc_coherent = ps3_alloc_coherent, -	.free_coherent = ps3_free_coherent, +	.alloc = ps3_alloc_coherent, +	.free = ps3_free_coherent,  	.map_sg = ps3_sb_map_sg,  	.unmap_sg = ps3_sb_unmap_sg,  	.dma_supported = ps3_dma_supported, +	.get_required_mask = ps3_dma_get_required_mask,  	.map_page = ps3_sb_map_page,  	.unmap_page = ps3_unmap_page,  };  static struct dma_map_ops ps3_ioc0_dma_ops = { -	.alloc_coherent = ps3_alloc_coherent, -	.free_coherent = ps3_free_coherent, +	.alloc = ps3_alloc_coherent, +	.free = ps3_free_coherent,  	.map_sg = ps3_ioc0_map_sg,  	.unmap_sg = ps3_ioc0_unmap_sg,  	.dma_supported = ps3_dma_supported, +	.get_required_mask = ps3_dma_get_required_mask,  	.map_page = ps3_ioc0_map_page,  	.unmap_page = ps3_unmap_page,  }; diff --git a/arch/powerpc/platforms/ps3/time.c b/arch/powerpc/platforms/ps3/time.c index 40b5cb43300..ce73ce86561 100644 --- a/arch/powerpc/platforms/ps3/time.c +++ b/arch/powerpc/platforms/ps3/time.c @@ -89,10 +89,8 @@ static int __init ps3_rtc_init(void)  		return -ENODEV;  	pdev = platform_device_register_simple("rtc-ps3", -1, NULL, 0); -	if (IS_ERR(pdev)) -		return PTR_ERR(pdev); -	return 0; +	return PTR_ERR_OR_ZERO(pdev);  }  module_init(ps3_rtc_init);  | 
