diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-31 13:37:27 +1100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-31 13:37:27 +1100 |
commit | 8af03e782cae1e0a0f530ddd22301cdd12cf9dc0 (patch) | |
tree | c4af13a38bd3cc1a811a37f2358491f171052070 /arch/powerpc/platforms/ps3 | |
parent | 6232665040f9a23fafd9d94d4ae8d5a2dc850f65 (diff) | |
parent | 99e139126ab2e84be67969650f92eb37c12ab5cd (diff) | |
download | talos-op-linux-8af03e782cae1e0a0f530ddd22301cdd12cf9dc0.tar.gz talos-op-linux-8af03e782cae1e0a0f530ddd22301cdd12cf9dc0.zip |
Merge branch 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (454 commits)
[POWERPC] Cell IOMMU fixed mapping support
[POWERPC] Split out the ioid fetching/checking logic
[POWERPC] Add support to cell_iommu_setup_page_tables() for multiple windows
[POWERPC] Split out the IOMMU logic from cell_dma_dev_setup()
[POWERPC] Split cell_iommu_setup_hardware() into two parts
[POWERPC] Split out the logic that allocates struct iommus
[POWERPC] Allocate the hash table under 1G on cell
[POWERPC] Add set_dma_ops() to match get_dma_ops()
[POWERPC] 83xx: Clean up / convert mpc83xx board DTS files to v1 format.
[POWERPC] 85xx: Only invalidate TLB0 and TLB1
[POWERPC] 83xx: Fix typo in mpc837x compatible entries
[POWERPC] 85xx: convert sbc85* boards to use machine_device_initcall
[POWERPC] 83xx: rework platform Kconfig
[POWERPC] 85xx: rework platform Kconfig
[POWERPC] 86xx: Remove unused IRQ defines
[POWERPC] QE: Explicitly set address-cells and size cells for muram
[POWERPC] Convert StorCenter DTS file to /dts-v1/ format.
[POWERPC] 86xx: Convert all 86xx DTS files to /dts-v1/ format.
[PPC] Remove 85xx from arch/ppc
[PPC] Remove 83xx from arch/ppc
...
Diffstat (limited to 'arch/powerpc/platforms/ps3')
-rw-r--r-- | arch/powerpc/platforms/ps3/Kconfig | 24 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/device-init.c | 531 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/mm.c | 24 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/platform.h | 34 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/repository.c | 320 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/spu.c | 27 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/system-bus.c | 19 |
7 files changed, 613 insertions, 366 deletions
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index 298f1c9679fb..a5f4e95dfc3d 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -61,17 +61,6 @@ config PS3_DYNAMIC_DMA This support is mainly for Linux kernel development. If unsure, say N. -config PS3_USE_LPAR_ADDR - depends on PPC_PS3 && EXPERIMENTAL - bool "PS3 use lpar address space" - default y - help - This option is solely for experimentation by experts. Disables - translation of lpar addresses. SPE support currently won't work - without this set to y. - - If you have any doubt, choose the default y. - config PS3_VUART depends on PPC_PS3 tristate @@ -138,4 +127,17 @@ config PS3_FLASH be disabled on the kernel command line using "ps3flash=off", to not allocate this fixed buffer. +config PS3_LPM + tristate "PS3 Logical Performance Monitor support" + depends on PPC_PS3 + help + Include support for the PS3 Logical Performance Monitor. + + This support is required to use the logical performance monitor + of the PS3's LV1 hypervisor. + + If you intend to use the advanced performance monitoring and + profiling support of the Cell processor with programs like + oprofile and perfmon2, then say Y or M, otherwise say N. + endmenu diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c index fd063fe0c9b3..9d251d0ca8c6 100644 --- a/arch/powerpc/platforms/ps3/device-init.c +++ b/arch/powerpc/platforms/ps3/device-init.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/kthread.h> #include <linux/init.h> +#include <linux/reboot.h> #include <asm/firmware.h> #include <asm/lv1call.h> @@ -30,6 +31,89 @@ #include "platform.h" +static int __init ps3_register_lpm_devices(void) +{ + int result; + u64 tmp1; + u64 tmp2; + struct ps3_system_bus_device *dev; + + pr_debug(" -> %s:%d\n", __func__, __LINE__); + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->match_id = PS3_MATCH_ID_LPM; + dev->dev_type = PS3_DEVICE_TYPE_LPM; + + /* The current lpm driver only supports a single BE processor. */ + + result = ps3_repository_read_be_node_id(0, &dev->lpm.node_id); + + if (result) { + pr_debug("%s:%d: ps3_repository_read_be_node_id failed \n", + __func__, __LINE__); + goto fail_read_repo; + } + + result = ps3_repository_read_lpm_privileges(dev->lpm.node_id, &tmp1, + &dev->lpm.rights); + + if (result) { + pr_debug("%s:%d: ps3_repository_read_lpm_privleges failed \n", + __func__, __LINE__); + goto fail_read_repo; + } + + lv1_get_logical_partition_id(&tmp2); + + if (tmp1 != tmp2) { + pr_debug("%s:%d: wrong lpar\n", + __func__, __LINE__); + result = -ENODEV; + goto fail_rights; + } + + if (!(dev->lpm.rights & PS3_LPM_RIGHTS_USE_LPM)) { + pr_debug("%s:%d: don't have rights to use lpm\n", + __func__, __LINE__); + result = -EPERM; + goto fail_rights; + } + + pr_debug("%s:%d: pu_id %lu, rights %lu(%lxh)\n", + __func__, __LINE__, dev->lpm.pu_id, dev->lpm.rights, + dev->lpm.rights); + + result = ps3_repository_read_pu_id(0, &dev->lpm.pu_id); + + if (result) { + pr_debug("%s:%d: ps3_repository_read_pu_id failed \n", + __func__, __LINE__); + goto fail_read_repo; + } + + result = ps3_system_bus_device_register(dev); + + if (result) { + pr_debug("%s:%d ps3_system_bus_device_register failed\n", + __func__, __LINE__); + goto fail_register; + } + + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return 0; + + +fail_register: +fail_rights: +fail_read_repo: + kfree(dev); + pr_debug(" <- %s:%d: failed\n", __func__, __LINE__); + return result; +} + /** * ps3_setup_gelic_device - Setup and register a gelic device instance. * @@ -238,166 +322,6 @@ static int __init ps3_setup_vuart_device(enum ps3_match_id match_id, return result; } -static int ps3stor_wait_for_completion(u64 dev_id, u64 tag, - unsigned int timeout) -{ - int result = -1; - unsigned int retries = 0; - u64 status; - - for (retries = 0; retries < timeout; retries++) { - result = lv1_storage_check_async_status(dev_id, tag, &status); - if (!result) - break; - - msleep(1); - } - - if (result) - pr_debug("%s:%u: check_async_status: %s, status %lx\n", - __func__, __LINE__, ps3_result(result), status); - - return result; -} - -/** - * ps3_storage_wait_for_device - Wait for a storage device to become ready. - * @repo: The repository device to wait for. - * - * Uses the hypervisor's storage device notification mechanism to wait until - * a storage device is ready. The device notification mechanism uses a - * psuedo device (id = -1) to asynchronously notify the guest when storage - * devices become ready. The notification device has a block size of 512 - * bytes. - */ - -static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo) -{ - int error = -ENODEV; - int result; - const u64 notification_dev_id = (u64)-1LL; - const unsigned int timeout = HZ; - u64 lpar; - u64 tag; - void *buf; - enum ps3_notify_type { - notify_device_ready = 0, - notify_region_probe = 1, - notify_region_update = 2, - }; - struct { - u64 operation_code; /* must be zero */ - u64 event_mask; /* OR of 1UL << enum ps3_notify_type */ - } *notify_cmd; - struct { - u64 event_type; /* enum ps3_notify_type */ - u64 bus_id; - u64 dev_id; - u64 dev_type; - u64 dev_port; - } *notify_event; - - pr_debug(" -> %s:%u: (%u:%u:%u)\n", __func__, __LINE__, repo->bus_id, - repo->dev_id, repo->dev_type); - - buf = kzalloc(512, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - lpar = ps3_mm_phys_to_lpar(__pa(buf)); - notify_cmd = buf; - notify_event = buf; - - result = lv1_open_device(repo->bus_id, notification_dev_id, 0); - if (result) { - printk(KERN_ERR "%s:%u: lv1_open_device %s\n", __func__, - __LINE__, ps3_result(result)); - goto fail_free; - } - - /* Setup and write the request for device notification. */ - - notify_cmd->operation_code = 0; /* must be zero */ - notify_cmd->event_mask = 1UL << notify_region_probe; - - result = lv1_storage_write(notification_dev_id, 0, 0, 1, 0, lpar, - &tag); - if (result) { - printk(KERN_ERR "%s:%u: write failed %s\n", __func__, __LINE__, - ps3_result(result)); - goto fail_close; - } - - /* Wait for the write completion */ - - result = ps3stor_wait_for_completion(notification_dev_id, tag, - timeout); - if (result) { - printk(KERN_ERR "%s:%u: write not completed %s\n", __func__, - __LINE__, ps3_result(result)); - goto fail_close; - } - - /* Loop here processing the requested notification events. */ - - while (1) { - memset(notify_event, 0, sizeof(*notify_event)); - - result = lv1_storage_read(notification_dev_id, 0, 0, 1, 0, - lpar, &tag); - if (result) { - printk(KERN_ERR "%s:%u: write failed %s\n", __func__, - __LINE__, ps3_result(result)); - break; - } - - result = ps3stor_wait_for_completion(notification_dev_id, tag, - timeout); - if (result) { - printk(KERN_ERR "%s:%u: read not completed %s\n", - __func__, __LINE__, ps3_result(result)); - break; - } - - pr_debug("%s:%d: notify event (%u:%u:%u): event_type 0x%lx, " - "port %lu\n", __func__, __LINE__, repo->bus_index, - repo->dev_index, repo->dev_type, - notify_event->event_type, notify_event->dev_port); - - if (notify_event->event_type != notify_region_probe || - notify_event->bus_id != repo->bus_id) { - pr_debug("%s:%u: bad notify_event: event %lu, " - "dev_id %lu, dev_type %lu\n", - __func__, __LINE__, notify_event->event_type, - notify_event->dev_id, notify_event->dev_type); - break; - } - - if (notify_event->dev_id == repo->dev_id && - notify_event->dev_type == repo->dev_type) { - pr_debug("%s:%u: device ready (%u:%u:%u)\n", __func__, - __LINE__, repo->bus_index, repo->dev_index, - repo->dev_type); - error = 0; - break; - } - - if (notify_event->dev_id == repo->dev_id && - notify_event->dev_type == PS3_DEV_TYPE_NOACCESS) { - pr_debug("%s:%u: no access: dev_id %u\n", __func__, - __LINE__, repo->dev_id); - break; - } - } - -fail_close: - lv1_close_device(repo->bus_id, notification_dev_id); -fail_free: - kfree(buf); - pr_debug(" <- %s:%u\n", __func__, __LINE__); - return error; -} - static int ps3_setup_storage_dev(const struct ps3_repository_device *repo, enum ps3_match_id match_id) { @@ -449,16 +373,6 @@ static int ps3_setup_storage_dev(const struct ps3_repository_device *repo, goto fail_find_interrupt; } - /* FIXME: Arrange to only do this on a 'cold' boot */ - - result = ps3_storage_wait_for_device(repo); - if (result) { - printk(KERN_ERR "%s:%u: storage_notification failed %d\n", - __func__, __LINE__, result); - result = -ENODEV; - goto fail_probe_notification; - } - for (i = 0; i < num_regions; i++) { unsigned int id; u64 start, size; @@ -494,7 +408,6 @@ static int ps3_setup_storage_dev(const struct ps3_repository_device *repo, fail_device_register: fail_read_region: -fail_probe_notification: fail_find_interrupt: kfree(p); fail_malloc: @@ -659,62 +572,268 @@ static int ps3_register_repository_device( return result; } +static void ps3_find_and_add_device(u64 bus_id, u64 dev_id) +{ + struct ps3_repository_device repo; + int res; + unsigned int retries; + unsigned long rem; + + /* + * On some firmware versions (e.g. 1.90), the device may not show up + * in the repository immediately + */ + for (retries = 0; retries < 10; retries++) { + res = ps3_repository_find_device_by_id(&repo, bus_id, dev_id); + if (!res) + goto found; + + rem = msleep_interruptible(100); + if (rem) + break; + } + pr_warning("%s:%u: device %lu:%lu not found\n", __func__, __LINE__, + bus_id, dev_id); + return; + +found: + if (retries) + pr_debug("%s:%u: device %lu:%lu found after %u retries\n", + __func__, __LINE__, bus_id, dev_id, retries); + + ps3_register_repository_device(&repo); + return; +} + +#define PS3_NOTIFICATION_DEV_ID ULONG_MAX +#define PS3_NOTIFICATION_INTERRUPT_ID 0 + +struct ps3_notification_device { + struct ps3_system_bus_device sbd; + spinlock_t lock; + u64 tag; + u64 lv1_status; + struct completion done; +}; + +enum ps3_notify_type { + notify_device_ready = 0, + notify_region_probe = 1, + notify_region_update = 2, +}; + +struct ps3_notify_cmd { + u64 operation_code; /* must be zero */ + u64 event_mask; /* OR of 1UL << enum ps3_notify_type */ +}; + +struct ps3_notify_event { + u64 event_type; /* enum ps3_notify_type */ + u64 bus_id; + u64 dev_id; + u64 dev_type; + u64 dev_port; +}; + +static irqreturn_t ps3_notification_interrupt(int irq, void *data) +{ + struct ps3_notification_device *dev = data; + int res; + u64 tag, status; + + spin_lock(&dev->lock); + res = lv1_storage_get_async_status(PS3_NOTIFICATION_DEV_ID, &tag, + &status); + if (tag != dev->tag) + pr_err("%s:%u: tag mismatch, got %lx, expected %lx\n", + __func__, __LINE__, tag, dev->tag); + + if (res) { + pr_err("%s:%u: res %d status 0x%lx\n", __func__, __LINE__, res, + status); + } else { + pr_debug("%s:%u: completed, status 0x%lx\n", __func__, + __LINE__, status); + dev->lv1_status = status; + complete(&dev->done); + } + spin_unlock(&dev->lock); + return IRQ_HANDLED; +} + +static int ps3_notification_read_write(struct ps3_notification_device *dev, + u64 lpar, int write) +{ + const char *op = write ? "write" : "read"; + unsigned long flags; + int res; + + init_completion(&dev->done); + spin_lock_irqsave(&dev->lock, flags); + res = write ? lv1_storage_write(dev->sbd.dev_id, 0, 0, 1, 0, lpar, + &dev->tag) + : lv1_storage_read(dev->sbd.dev_id, 0, 0, 1, 0, lpar, + &dev->tag); + spin_unlock_irqrestore(&dev->lock, flags); + if (res) { + pr_err("%s:%u: %s failed %d\n", __func__, __LINE__, op, res); + return -EPERM; + } + pr_debug("%s:%u: notification %s issued\n", __func__, __LINE__, op); + + res = wait_event_interruptible(dev->done.wait, + dev->done.done || kthread_should_stop()); + if (kthread_should_stop()) + res = -EINTR; + if (res) { + pr_debug("%s:%u: interrupted %s\n", __func__, __LINE__, op); + return res; + } + + if (dev->lv1_status) { + pr_err("%s:%u: %s not completed, status 0x%lx\n", __func__, + __LINE__, op, dev->lv1_status); + return -EIO; + } + pr_debug("%s:%u: notification %s completed\n", __func__, __LINE__, op); + + return 0; +} + +static struct task_struct *probe_task; + /** * ps3_probe_thread - Background repository probing at system startup. * * This implementation only supports background probing on a single bus. + * It uses the hypervisor's storage device notification mechanism to wait until + * a storage device is ready. The device notification mechanism uses a + * pseudo device to asynchronously notify the guest when storage devices become + * ready. The notification device has a block size of 512 bytes. */ static int ps3_probe_thread(void *data) { - struct ps3_repository_device *repo = data; - int result; - unsigned int ms = 250; + struct ps3_notification_device dev; + int res; + unsigned int irq; + u64 lpar; + void *buf; + struct ps3_notify_cmd *notify_cmd; + struct ps3_notify_event *notify_event; pr_debug(" -> %s:%u: kthread started\n", __func__, __LINE__); + buf = kzalloc(512, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + lpar = ps3_mm_phys_to_lpar(__pa(buf)); + notify_cmd = buf; + notify_event = buf; + + /* dummy system bus device */ + dev.sbd.bus_id = (u64)data; + dev.sbd.dev_id = PS3_NOTIFICATION_DEV_ID; + dev.sbd.interrupt_id = PS3_NOTIFICATION_INTERRUPT_ID; + + res = lv1_open_device(dev.sbd.bus_id, dev.sbd.dev_id, 0); + if (res) { + pr_err("%s:%u: lv1_open_device failed %s\n", __func__, + __LINE__, ps3_result(res)); + goto fail_free; + } + + res = ps3_sb_event_receive_port_setup(&dev.sbd, PS3_BINDING_CPU_ANY, + &irq); + if (res) { + pr_err("%s:%u: ps3_sb_event_receive_port_setup failed %d\n", + __func__, __LINE__, res); + goto fail_close_device; + } + + spin_lock_init(&dev.lock); + + res = request_irq(irq, ps3_notification_interrupt, IRQF_DISABLED, + "ps3_notification", &dev); + if (res) { + pr_err("%s:%u: request_irq failed %d\n", __func__, __LINE__, + res); + goto fail_sb_event_receive_port_destroy; + } + + /* Setup and write the request for device notification. */ + notify_cmd->operation_code = 0; /* must be zero */ + notify_cmd->event_mask = 1UL << notify_region_probe; + + res = ps3_notification_read_write(&dev, lpar, 1); + if (res) + goto fail_free_irq; + + /* Loop here processing the requested notification events. */ do { try_to_freeze(); - pr_debug("%s:%u: probing...\n", __func__, __LINE__); - - do { - result = ps3_repository_find_device(repo); - - if (result == -ENODEV) - pr_debug("%s:%u: nothing new\n", __func__, - __LINE__); - else if (result) - pr_debug("%s:%u: find device error.\n", - __func__, __LINE__); - else { - pr_debug("%s:%u: found device (%u:%u:%u)\n", - __func__, __LINE__, repo->bus_index, - repo->dev_index, repo->dev_type); - ps3_register_repository_device(repo); - ps3_repository_bump_device(repo); - ms = 250; - } - } while (!result); - - pr_debug("%s:%u: ms %u\n", __func__, __LINE__, ms); - - if ( ms > 60000) + memset(notify_event, 0, sizeof(*notify_event)); + + res = ps3_notification_read_write(&dev, lpar, 0); + if (res) break; - msleep_interruptible(ms); + pr_debug("%s:%u: notify event type 0x%lx bus id %lu dev id %lu" + " type %lu port %lu\n", __func__, __LINE__, + notify_event->event_type, notify_event->bus_id, + notify_event->dev_id, notify_event->dev_type, + notify_event->dev_port); - /* An exponential backoff. */ - ms <<= 1; + if (notify_event->event_type != notify_region_probe || + notify_event->bus_id != dev.sbd.bus_id) { + pr_warning("%s:%u: bad notify_event: event %lu, " + "dev_id %lu, dev_type %lu\n", + __func__, __LINE__, notify_event->event_type, + notify_event->dev_id, + notify_event->dev_type); + continue; + } + + ps3_find_and_add_device(dev.sbd.bus_id, notify_event->dev_id); } while (!kthread_should_stop()); +fail_free_irq: + free_irq(irq, &dev); +fail_sb_event_receive_port_destroy: + ps3_sb_event_receive_port_destroy(&dev.sbd, irq); +fail_close_device: + lv1_close_device(dev.sbd.bus_id, dev.sbd.dev_id); +fail_free: + kfree(buf); + + probe_task = NULL; + pr_debug(" <- %s:%u: kthread finished\n", __func__, __LINE__); return 0; } /** + * ps3_stop_probe_thread - Stops the background probe thread. + * + */ + +static int ps3_stop_probe_thread(struct notifier_block *nb, unsigned long code, + void *data) +{ + if (probe_task) + kthread_stop(probe_task); + return 0; +} + +static struct notifier_block nb = { + .notifier_call = ps3_stop_probe_thread +}; + +/** * ps3_start_probe_thread - Starts the background probe thread. * */ @@ -723,7 +842,7 @@ static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type) { int result; struct task_struct *task; - static struct ps3_repository_device repo; /* must be static */ + struct ps3_repository_device repo; pr_debug(" -> %s:%d\n", __func__, __LINE__); @@ -746,7 +865,8 @@ static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type) return -ENODEV; } - task = kthread_run(ps3_probe_thread, &repo, "ps3-probe-%u", bus_type); + task = kthread_run(ps3_probe_thread, (void *)repo.bus_id, + "ps3-probe-%u", bus_type); if (IS_ERR(task)) { result = PTR_ERR(task); @@ -755,6 +875,9 @@ static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type) return result; } + probe_task = task; + register_reboot_notifier(&nb); + pr_debug(" <- %s:%d\n", __func__, __LINE__); return 0; } @@ -787,6 +910,8 @@ static int __init ps3_register_devices(void) ps3_register_sound_devices(); + ps3_register_lpm_devices(); + pr_debug(" <- %s:%d\n", __func__, __LINE__); return 0; } diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 7bb3e1620974..68900476c842 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -36,11 +36,6 @@ #endif enum { -#if defined(CONFIG_PS3_USE_LPAR_ADDR) - USE_LPAR_ADDR = 1, -#else - USE_LPAR_ADDR = 0, -#endif #if defined(CONFIG_PS3_DYNAMIC_DMA) USE_DYNAMIC_DMA = 1, #else @@ -137,11 +132,8 @@ static struct map map; unsigned long ps3_mm_phys_to_lpar(unsigned long phys_addr) { BUG_ON(is_kernel_addr(phys_addr)); - if (USE_LPAR_ADDR) - return phys_addr; - else - return (phys_addr < map.rm.size || phys_addr >= map.total) - ? phys_addr : phys_addr + map.r1.offset; + return (phys_addr < map.rm.size || phys_addr >= map.total) + ? phys_addr : phys_addr + map.r1.offset; } EXPORT_SYMBOL(ps3_mm_phys_to_lpar); @@ -309,7 +301,7 @@ static int __init ps3_mm_add_memory(void) BUG_ON(!mem_init_done); - start_addr = USE_LPAR_ADDR ? map.r1.base : map.rm.size; + start_addr = map.rm.size; start_pfn = start_addr >> PAGE_SHIFT; nr_pages = (map.r1.size + PAGE_SIZE - 1) >> PAGE_SHIFT; @@ -359,7 +351,7 @@ static unsigned long dma_sb_lpar_to_bus(struct ps3_dma_region *r, static void __maybe_unused _dma_dump_region(const struct ps3_dma_region *r, const char *func, int line) { - DBG("%s:%d: dev %u:%u\n", func, line, r->dev->bus_id, + DBG("%s:%d: dev %lu:%lu\n", func, line, r->dev->bus_id, r->dev->dev_id); DBG("%s:%d: page_size %u\n", func, line, r->page_size); DBG("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); @@ -394,7 +386,7 @@ struct dma_chunk { static void _dma_dump_chunk (const struct dma_chunk* c, const char* func, int line) { - DBG("%s:%d: r.dev %u:%u\n", func, line, + DBG("%s:%d: r.dev %lu:%lu\n", func, line, c->region->dev->bus_id, c->region->dev->dev_id); DBG("%s:%d: r.bus_addr %lxh\n", func, line, c->region->bus_addr); DBG("%s:%d: r.page_size %u\n", func, line, c->region->page_size); @@ -658,7 +650,7 @@ static int dma_sb_region_create(struct ps3_dma_region *r) BUG_ON(!r); if (!r->dev->bus_id) { - pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__, + pr_info("%s:%d: %lu:%lu no dma\n", __func__, __LINE__, r->dev->bus_id, r->dev->dev_id); return 0; } @@ -724,7 +716,7 @@ static int dma_sb_region_free(struct ps3_dma_region *r) BUG_ON(!r); if (!r->dev->bus_id) { - pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__, + pr_info("%s:%d: %lu:%lu no dma\n", __func__, __LINE__, r->dev->bus_id, r->dev->dev_id); return 0; } @@ -1007,7 +999,7 @@ static int dma_sb_region_create_linear(struct ps3_dma_region *r) if (r->offset + r->len > map.rm.size) { /* Map (part of) 2nd RAM chunk */ - virt_addr = USE_LPAR_ADDR ? map.r1.base : map.rm.size; + virt_addr = map.rm.size; len = r->len; if (r->offset >= map.rm.size) virt_addr += r->offset - map.rm.size; diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 01f0c9506e11..235c13ebacd9 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -89,13 +89,11 @@ enum ps3_dev_type { PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */ PS3_DEV_TYPE_SB_GPIO = 6, PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */ - PS3_DEV_TYPE_STOR_DUMMY = 32, - PS3_DEV_TYPE_NOACCESS = 255, }; int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, u64 *value); -int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id); +int ps3_repository_read_bus_id(unsigned int bus_index, u64 *bus_id); int ps3_repository_read_bus_type(unsigned int bus_index, enum ps3_bus_type *bus_type); int ps3_repository_read_bus_num_dev(unsigned int bus_index, @@ -119,7 +117,7 @@ enum ps3_reg_type { int ps3_repository_read_dev_str(unsigned int bus_index, unsigned int dev_index, const char *dev_str, u64 *value); int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index, - unsigned int *dev_id); + u64 *dev_id); int ps3_repository_read_dev_type(unsigned int bus_index, unsigned int dev_index, enum ps3_dev_type *dev_type); int ps3_repository_read_dev_intr(unsigned int bus_index, @@ -138,21 +136,17 @@ int ps3_repository_read_dev_reg(unsigned int bus_index, /* repository bus enumerators */ struct ps3_repository_device { - enum ps3_bus_type bus_type; unsigned int bus_index; - unsigned int bus_id; - enum ps3_dev_type dev_type; unsigned int dev_index; - unsigned int dev_id; + enum ps3_bus_type bus_type; + enum ps3_dev_type dev_type; + u64 bus_id; + u64 dev_id; }; -static inline struct ps3_repository_device *ps3_repository_bump_device( - struct ps3_repository_device *repo) -{ - repo->dev_index++; - return repo; -} int ps3_repository_find_device(struct ps3_repository_device *repo); +int ps3_repository_find_device_by_id(struct ps3_repository_device *repo, + u64 bus_id, u64 dev_id); int ps3_repository_find_devices(enum ps3_bus_type bus_type, int (*callback)(const struct ps3_repository_device *repo)); int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from, @@ -186,10 +180,10 @@ int ps3_repository_read_stor_dev_region(unsigned int bus_index, unsigned int dev_index, unsigned int region_index, unsigned int *region_id, u64 *region_start, u64 *region_size); -/* repository pu and memory info */ +/* repository logical pu and memory info */ -int ps3_repository_read_num_pu(unsigned int *num_pu); -int ps3_repository_read_ppe_id(unsigned int *pu_index, unsigned int *ppe_id); +int ps3_repository_read_num_pu(u64 *num_pu); +int ps3_repository_read_pu_id(unsigned int pu_index, u64 *pu_id); int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base); int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size); int ps3_repository_read_region_total(u64 *region_total); @@ -200,9 +194,15 @@ int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, int ps3_repository_read_num_be(unsigned int *num_be); int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id); +int ps3_repository_read_be_id(u64 node_id, u64 *be_id); int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq); int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq); +/* repository performance monitor info */ + +int ps3_repository_read_lpm_privileges(unsigned int be_index, u64 *lpar, + u64 *rights); + /* repository 'Other OS' area */ int ps3_repository_read_boot_dat_addr(u64 *lpar_addr); diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index 1c94824f7b63..22063adeb38b 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c @@ -33,7 +33,7 @@ enum ps3_lpar_id { }; #define dump_field(_a, _b) _dump_field(_a, _b, __func__, __LINE__) -static void _dump_field(const char *hdr, u64 n, const char* func, int line) +static void _dump_field(const char *hdr, u64 n, const char *func, int line) { #if defined(DEBUG) char s[16]; @@ -50,8 +50,8 @@ static void _dump_field(const char *hdr, u64 n, const char* func, int line) #define dump_node_name(_a, _b, _c, _d, _e) \ _dump_node_name(_a, _b, _c, _d, _e, __func__, __LINE__) -static void _dump_node_name (unsigned int lpar_id, u64 n1, u64 n2, u64 n3, - u64 n4, 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); _dump_field("n1: ", n1, func, line); @@ -63,7 +63,7 @@ static void _dump_node_name (unsigned int lpar_id, u64 n1, u64 n2, u64 n3, #define dump_node(_a, _b, _c, _d, _e, _f, _g) \ _dump_node(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__) 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) + u64 v1, u64 v2, const char *func, int line) { pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id); _dump_field("n1: ", n1, func, line); @@ -165,21 +165,18 @@ int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, make_first_field("bus", bus_index), make_field(bus_str, 0), 0, 0, - value, 0); + value, NULL); } -int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id) +int ps3_repository_read_bus_id(unsigned int bus_index, u64 *bus_id) { int result; - u64 v1; - u64 v2; /* unused */ result = read_node(PS3_LPAR_ID_PME, make_first_field("bus", bus_index), make_field("id", 0), 0, 0, - &v1, &v2); - *bus_id = v1; + bus_id, NULL); return result; } @@ -193,7 +190,7 @@ int ps3_repository_read_bus_type(unsigned int bus_index, make_first_field("bus", bus_index), make_field("type", 0), 0, 0, - &v1, 0); + &v1, NULL); *bus_type = v1; return result; } @@ -208,7 +205,7 @@ int ps3_repository_read_bus_num_dev(unsigned int bus_index, make_first_field("bus", bus_index), make_field("num_dev", 0), 0, 0, - &v1, 0); + &v1, NULL); *num_dev = v1; return result; } @@ -221,22 +218,20 @@ int ps3_repository_read_dev_str(unsigned int bus_index, make_field("dev", dev_index), make_field(dev_str, 0), 0, - value, 0); + value, NULL); } int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index, - unsigned int *dev_id) + u64 *dev_id) { int result; - u64 v1; result = read_node(PS3_LPAR_ID_PME, make_first_field("bus", bus_index), make_field("dev", dev_index), make_field("id", 0), 0, - &v1, 0); - *dev_id = v1; + dev_id, NULL); return result; } @@ -251,14 +246,14 @@ int ps3_repository_read_dev_type(unsigned int bus_index, make_field("dev", dev_index), make_field("type", 0), 0, - &v1, 0); + &v1, NULL); *dev_type = v1; return result; } int ps3_repository_read_dev_intr(unsigned int bus_index, unsigned int dev_index, unsigned int intr_index, - enum ps3_interrupt_type *intr_type, unsigned int* interrupt_id) + enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id) { int result; u64 v1; @@ -287,7 +282,7 @@ int ps3_repository_read_dev_reg_type(unsigned int bus_index, make_field("dev", dev_index), make_field("reg", reg_index), make_field("type", 0), - &v1, 0); + &v1, NULL); *reg_type = v1; return result; } @@ -332,7 +327,7 @@ int ps3_repository_find_device(struct ps3_repository_device *repo) return result; } - pr_debug("%s:%d: bus_type %u, bus_index %u, bus_id %u, num_dev %u\n", + pr_debug("%s:%d: bus_type %u, bus_index %u, bus_id %lu, num_dev %u\n", __func__, __LINE__, tmp.bus_type, tmp.bus_index, tmp.bus_id, num_dev); @@ -349,47 +344,95 @@ int ps3_repository_find_device(struct ps3_repository_device *repo) return result; } - if (tmp.bus_type == PS3_BUS_TYPE_STORAGE) { - /* - * A storage device may show up in the repository before the - * hypervisor has finished probing its type and regions - */ - unsigned int num_regions; - - if (tmp.dev_type == PS3_DEV_TYPE_STOR_DUMMY) { - pr_debug("%s:%u storage device not ready\n", __func__, - __LINE__); - return -ENODEV; - } + result = ps3_repository_read_dev_id(tmp.bus_index, tmp.dev_index, + &tmp.dev_id); - result = ps3_repository_read_stor_dev_num_regions(tmp.bus_index, - tmp.dev_index, - &num_regions); + if (result) { + pr_debug("%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 %lu\n", + __func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id); + + *repo = tmp; + return 0; +} + +int ps3_repository_find_device_by_id(struct ps3_repository_device *repo, + u64 bus_id, u64 dev_id) +{ + int result = -ENODEV; + struct ps3_repository_device tmp; + unsigned int num_dev; + + pr_debug(" -> %s:%u: find device by id %lu:%lu\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:%d read_stor_dev_num_regions failed\n", - __func__, __LINE__); + pr_debug("%s:%u read_bus_id(%u) failed\n", __func__, + __LINE__, tmp.bus_index); return result; } - if (!num_regions) { - pr_debug("%s:%u storage device has no regions yet\n", - __func__, __LINE__); - return -ENODEV; - } + if (tmp.bus_id == bus_id) + goto found_bus; + + pr_debug("%s:%u: skip, bus_id %lu\n", __func__, __LINE__, + tmp.bus_id); } + pr_debug(" <- %s:%u: bus not found\n", __func__, __LINE__); + return result; - result = ps3_repository_read_dev_id(tmp.bus_index, tmp.dev_index, - &tmp.dev_id); +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__, + __LINE__, tmp.bus_index); + return result; + } + result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev); if (result) { - pr_debug("%s:%d ps3_repository_read_dev_id failed\n", __func__, - __LINE__); + pr_debug("%s:%u read_bus_num_dev failed\n", __func__, + __LINE__); return result; } - pr_debug("%s:%d: found: dev_type %u, dev_index %u, dev_id %u\n", - __func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id); + for (tmp.dev_index = 0; tmp.dev_index < num_dev; tmp.dev_index++) { + result = ps3_repository_read_dev_id(tmp.bus_index, + tmp.dev_index, + &tmp.dev_id); + if (result) { + pr_debug("%s:%u read_dev_id(%u:%u) failed\n", __func__, + __LINE__, tmp.bus_index, tmp.dev_index); + return result; + } + if (tmp.dev_id == dev_id) + goto found_dev; + + pr_debug("%s:%u: skip, dev_id %lu\n", __func__, __LINE__, + tmp.dev_id); + } + pr_debug(" <- %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__); + return result; + } + + pr_debug(" <- %s:%u: found: type (%u:%u) index (%u:%u) id (%lu:%lu)\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; } @@ -402,50 +445,34 @@ int __devinit ps3_repository_find_devices(enum ps3_bus_type bus_type, pr_debug(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type); - for (repo.bus_index = 0; repo.bus_index < 10; repo.bus_index++) { + 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__); + return result; + } - result = ps3_repository_read_bus_type(repo.bus_index, - &repo.bus_type); + 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__, + repo.bus_index); + return result; + } - if (result) { - pr_debug("%s:%d read_bus_type(%u) failed\n", - __func__, __LINE__, repo.bus_index); + for (repo.dev_index = 0; ; repo.dev_index++) { + result = ps3_repository_find_device(&repo); + if (result == -ENODEV) { + result = 0; + break; + } else if (result) break; - } - - if (repo.bus_type != bus_type) { - pr_debug("%s:%d: skip, bus_type %u\n", __func__, - __LINE__, repo.bus_type); - continue; - } - - result = ps3_repository_read_bus_id(repo.bus_index, - &repo.bus_id); + result = callback(&repo); if (result) { - pr_debug("%s:%d read_bus_id(%u) failed\n", - __func__, __LINE__, repo.bus_index); - continue; - } - - for (repo.dev_index = 0; ; repo.dev_index++) { - result = ps3_repository_find_device(&repo); - - if (result == -ENODEV) { - result = 0; - break; - } else if (result) - break; - - result = callback(&repo); - - if (result) { - pr_debug("%s:%d: abort at callback\n", __func__, - __LINE__); - break; - } + pr_debug("%s:%d: abort at callback\n", __func__, + __LINE__); + break; } - break; } pr_debug(" <- %s:%d\n", __func__, __LINE__); @@ -561,7 +588,7 @@ int ps3_repository_read_stor_dev_port(unsigned int bus_index, make_first_field("bus", bus_index), make_field("dev", dev_index), make_field("port", 0), - 0, port, 0); + 0, port, NULL); } int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index, @@ -571,7 +598,7 @@ int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index, make_first_field("bus", bus_index), make_field("dev", dev_index), make_field("blk_size", 0), - 0, blk_size, 0); + 0, blk_size, NULL); } int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index, @@ -581,7 +608,7 @@ int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index, make_first_field("bus", bus_index), make_field("dev", dev_index), make_field("n_blocks", 0), - 0, num_blocks, 0); + 0, num_blocks, NULL); } int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index, @@ -594,7 +621,7 @@ int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index, make_first_field("bus", bus_index), make_field("dev", dev_index), make_field("n_regs", 0), - 0, &v1, 0); + 0, &v1, NULL); *num_regions = v1; return result; } @@ -611,7 +638,7 @@ int ps3_repository_read_stor_dev_region_id(unsigned int bus_index, make_field("dev", dev_index), make_field("region", region_index), make_field("id", 0), - &v1, 0); + &v1, NULL); *region_id = v1; return result; } @@ -624,7 +651,7 @@ int ps3_repository_read_stor_dev_region_size(unsigned int bus_index, make_field("dev", dev_index), make_field("region", region_index), make_field("size", 0), - region_size, 0); + region_size, NULL); } int ps3_repository_read_stor_dev_region_start(unsigned int bus_index, @@ -635,7 +662,7 @@ int ps3_repository_read_stor_dev_region_start(unsigned int bus_index, make_field("dev", dev_index), make_field("region", region_index), make_field("start", 0), - region_start, 0); + region_start, NULL); } int ps3_repository_read_stor_dev_info(unsigned int bus_index, @@ -684,6 +711,35 @@ int ps3_repository_read_stor_dev_region(unsigned int bus_index, return result; } +/** + * ps3_repository_read_num_pu - Number of logical PU processors for this lpar. + */ + +int ps3_repository_read_num_pu(u64 *num_pu) +{ + *num_pu = 0; + return read_node(PS3_LPAR_ID_CURRENT, + make_first_field("bi", 0), + make_field("pun", 0), + 0, 0, + num_pu, NULL); +} + +/** + * ps3_repository_read_pu_id - Read the logical PU id. + * @pu_index: Zero based index. + * @pu_id: The logical PU id. + */ + +int ps3_repository_read_pu_id(unsigned int pu_index, u64 *pu_id) +{ + return read_node(PS3_LPAR_ID_CURRENT, + make_first_field("bi", 0), + make_field("pu", pu_index), + 0, 0, + pu_id, NULL); +} + int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size) { return read_node(PS3_LPAR_ID_CURRENT, @@ -691,7 +747,7 @@ int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size) make_field("pu", 0), ppe_id, make_field("rm_size", 0), - rm_size, 0); + rm_size, NULL); } int ps3_repository_read_region_total(u64 *region_total) @@ -700,7 +756,7 @@ int ps3_repository_read_region_total(u64 *region_total) make_first_field("bi", 0), make_field("rgntotal", 0), 0, 0, - region_total, 0); + region_total, NULL); } /** @@ -736,7 +792,7 @@ int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved) make_first_field("bi", 0), make_field("spun", 0), 0, 0, - &v1, 0); + &v1, NULL); *num_spu_reserved = v1; return result; } @@ -755,7 +811,7 @@ int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id) make_first_field("bi", 0), make_field("spursvn", 0), 0, 0, - &v1, 0); + &v1, NULL); *num_resource_id = v1; return result; } @@ -768,7 +824,7 @@ int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id) */ int ps3_repository_read_spu_resource_id(unsigned int res_index, - enum ps3_spu_resource_type* resource_type, unsigned int *resource_id) + enum ps3_spu_resource_type *resource_type, unsigned int *resource_id) { int result; u64 v1; @@ -785,14 +841,14 @@ int ps3_repository_read_spu_resource_id(unsigned int res_index, return result; } -int ps3_repository_read_boot_dat_address(u64 *address) +static int ps3_repository_read_boot_dat_address(u64 *address) { return read_node(PS3_LPAR_ID_CURRENT, make_first_field("bi", 0), make_field("boot_dat", 0), make_field("address", 0), 0, - address, 0); + address, NULL); } int ps3_repository_read_boot_dat_size(unsigned int *size) @@ -805,7 +861,7 @@ int ps3_repository_read_boot_dat_size(unsigned int *size) make_field("boot_dat", 0), make_field("size", 0), 0, - &v1, 0); + &v1, NULL); *size = v1; return result; } @@ -820,7 +876,7 @@ int ps3_repository_read_vuart_av_port(unsigned int *port) make_field("vir_uart", 0), make_field("port", 0), make_field("avset", 0), - &v1, 0); + &v1, NULL); *port = v1; return result; } @@ -835,7 +891,7 @@ int ps3_repository_read_vuart_sysmgr_port(unsigned int *port) make_field("vir_uart", 0), make_field("port", 0), make_field("sysmgr", 0), - &v1, 0); + &v1, NULL); *port = v1; return result; } @@ -856,6 +912,10 @@ int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size) : ps3_repository_read_boot_dat_size(size); } +/** + * ps3_repository_read_num_be - Number of physical BE processors in the system. + */ + int ps3_repository_read_num_be(unsigned int *num_be) { int result; @@ -866,11 +926,17 @@ int ps3_repository_read_num_be(unsigned int *num_be) 0, 0, 0, - &v1, 0); + &v1, NULL); *num_be = v1; return result; } +/** + * ps3_repository_read_be_node_id - Read the physical BE processor node id. + * @be_index: Zero based index. + * @node_id: The BE processor node id. + */ + int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id) { return read_node(PS3_LPAR_ID_PME, @@ -878,7 +944,23 @@ int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id) 0, 0, 0, - node_id, 0); + node_id, NULL); +} + +/** + * ps3_repository_read_be_id - Read the physical BE processor id. + * @node_id: The BE processor node id. + * @be_id: The BE processor id. + */ + +int ps3_repository_read_be_id(u64 node_id, u64 *be_id) +{ + return read_node(PS3_LPAR_ID_PME, + make_first_field("be", 0), + node_id, + 0, + 0, + be_id, NULL); } int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq) @@ -888,7 +970,7 @@ int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq) node_id, make_field("clock", 0), 0, - tb_freq, 0); + tb_freq, NULL); } int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq) @@ -897,11 +979,29 @@ int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq) u64 node_id; *tb_freq = 0; - result = ps3_repository_read_be_node_id(0, &node_id); + result = ps3_repository_read_be_node_id(be_index, &node_id); return result ? result : ps3_repository_read_tb_freq(node_id, tb_freq); } +int ps3_repository_read_lpm_privileges(unsigned int be_index, u64 *lpar, + u64 *rights) +{ + int result; + u64 node_id; + + *lpar = 0; + *rights = 0; + result = ps3_repository_read_be_node_id(be_index, &node_id); + return result ? result + : read_node(PS3_LPAR_ID_PME, + make_first_field("be", 0), + node_id, + make_field("lpm", 0), + make_field("priv", 0), + lpar, rights); +} + #if defined(DEBUG) int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo) @@ -1034,7 +1134,7 @@ static int dump_device_info(struct ps3_repository_device *repo, continue; } - pr_debug("%s:%d (%u:%u): dev_type %u, dev_id %u\n", __func__, + pr_debug("%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); @@ -1091,7 +1191,7 @@ int ps3_repository_dump_bus_info(void) continue; } - pr_debug("%s:%d bus_%u: bus_type %u, bus_id %u, num_dev %u\n", + pr_debug("%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); diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index d1630a074acf..5ad41189b494 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -28,6 +28,7 @@ #include <asm/spu_priv1.h> #include <asm/lv1call.h> +#include "../cell/spufs/spufs.h" #include "platform.h" /* spu_management_ops */ @@ -419,10 +420,34 @@ static int ps3_init_affinity(void) return 0; } +/** + * ps3_enable_spu - Enable SPU run control. + * + * An outstanding enhancement for the PS3 would be to add a guard to check + * for incorrect access to the spu problem state when the spu context is + * disabled. This check could be implemented with a flag added to the spu + * context that would inhibit mapping problem state pages, and a routine + * to unmap spu problem state pages. When the spu is enabled with + * ps3_enable_spu() the flag would be set allowing pages to be mapped, + * and when the spu is disabled with ps3_disable_spu() the flag would be + * cleared and the mapped problem state pages would be unmapped. + */ + +static void ps3_enable_spu(struct spu_context *ctx) +{ +} + +static void ps3_disable_spu(struct spu_context *ctx) +{ + ctx->ops->runcntl_stop(ctx); +} + const struct spu_management_ops spu_management_ps3_ops = { .enumerate_spus = ps3_enumerate_spus, .create_spu = ps3_create_spu, .destroy_spu = ps3_destroy_spu, + .enable_spu = ps3_enable_spu, + .disable_spu = ps3_disable_spu, .init_affinity = ps3_init_affinity, }; @@ -505,8 +530,6 @@ static void mfc_sr1_set(struct spu *spu, u64 sr1) static const u64 allowed = ~(MFC_STATE1_LOCAL_STORAGE_DECODE_MASK | MFC_STATE1_PROBLEM_STATE_MASK); - sr1 |= MFC_STATE1_MASTER_RUN_CONTROL_MASK; - BUG_ON((sr1 & allowed) != (spu_pdata(spu)->cache.sr1 & allowed)); spu_pdata(spu)->cache.sr1 = sr1; diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 6405f4a36763..43c493fca2d0 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -42,8 +42,8 @@ struct { int gpu; } static usage_hack; -static int ps3_is_device(struct ps3_system_bus_device *dev, - unsigned int bus_id, unsigned int dev_id) +static int ps3_is_device(struct ps3_system_bus_device *dev, u64 bus_id, + u64 dev_id) { return dev->bus_id == bus_id && dev->dev_id == dev_id; } @@ -182,8 +182,8 @@ int ps3_open_hv_device(struct ps3_system_bus_device *dev) case PS3_MATCH_ID_SYSTEM_MANAGER: pr_debug("%s:%d: unsupported match_id: %u\n", __func__, __LINE__, dev->match_id); - pr_debug("%s:%d: bus_id: %u\n", __func__, - __LINE__, dev->bus_id); + pr_debug("%s:%d: bus_id: %lu\n", __func__, __LINE__, + dev->bus_id); BUG(); return -EINVAL; @@ -220,8 +220,8 @@ int ps3_close_hv_device(struct ps3_system_bus_device *dev) case PS3_MATCH_ID_SYSTEM_MANAGER: pr_debug("%s:%d: unsupported match_id: %u\n", __func__, __LINE__, dev->match_id); - pr_debug("%s:%d: bus_id: %u\n", __func__, - __LINE__, dev->bus_id); + pr_debug("%s:%d: bus_id: %lu\n", __func__, __LINE__, + dev->bus_id); BUG(); return -EINVAL; @@ -240,7 +240,7 @@ EXPORT_SYMBOL_GPL(ps3_close_hv_device); static void _dump_mmio_region(const struct ps3_mmio_region* r, const char* func, int line) { - pr_debug("%s:%d: dev %u:%u\n", func, line, r->dev->bus_id, + pr_debug("%s:%d: dev %lu:%lu\n", func, line, r->dev->bus_id, r->dev->dev_id); pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); pr_debug("%s:%d: len %lxh\n", func, line, r->len); @@ -715,6 +715,7 @@ int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) static unsigned int dev_ioc0_count; static unsigned int dev_sb_count; static unsigned int dev_vuart_count; + static unsigned int dev_lpm_count; if (!dev->core.parent) dev->core.parent = &ps3_system_bus; @@ -737,6 +738,10 @@ int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x", ++dev_vuart_count); break; + case PS3_DEVICE_TYPE_LPM: + snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), + "lpm_%02x", ++dev_lpm_count); + break; default: BUG(); }; |