From: Geoff Levand <geoffrey.levand@am.sony.com>
To: linuxppc-dev@ozlabs.org
Cc: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>,
Paul Mackerras <paulus@samba.org>
Subject: [patch 09/18] PS3: System-bus rework
Date: Tue, 05 Jun 2007 20:00:27 -0700 [thread overview]
Message-ID: <4666234B.2020208@am.sony.com> (raw)
In-Reply-To: <20070606024407.786638029@am.sony.com>>
Rework the PS3 system bus to unify device support.
- DMA region sizes must be a power of two
- storage bus DMA updates:
- Small fixes for the PS3 DMA core:
o fix alignment bug
o kill superfluous test
o indentation
o spelling
o export ps3_dma_region_{create,free}()
- ps3_dma_region_init():
o Add `addr' and `len' parameters, so you can create a DMA region that
does not cover all memory (use `NULL' and `0' to cover all memory).
This is needed because there are not sufficient IOMMU resources to have
all DMA regions cover all memory.
o Uninline
- Added remove and shutdown routines to all to all drivers.
- Added loadable module support to all drivers.
- Added HV calls for iopte management (needed by sound driver).
Signed-off-by: MOKUNO Masakazu <mokuno@sm.sony.co.jp>
Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
---
arch/powerpc/platforms/ps3/interrupt.c | 24 -
arch/powerpc/platforms/ps3/mm.c | 621 ++++++++++++++++++++++++++------
arch/powerpc/platforms/ps3/platform.h | 11
arch/powerpc/platforms/ps3/system-bus.c | 525 ++++++++++++++++++++++-----
include/asm-powerpc/lv1call.h | 3
include/asm-powerpc/ps3.h | 150 +++++--
6 files changed, 1081 insertions(+), 253 deletions(-)
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -399,17 +399,15 @@ int ps3_send_event_locally(unsigned int
* ps3_sb_event_receive_port_setup - Setup a system bus event receive port.
* @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
* serviced on.
- * @did: The HV device identifier read from the system repository.
- * @interrupt_id: The device interrupt id read from the system repository.
+ * @dev: The system bus device instance.
* @virq: The assigned Linux virq.
*
* An event irq represents a virtual device interrupt. The interrupt_id
* coresponds to the software interrupt number.
*/
-int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu,
- const struct ps3_device_id *did, unsigned int interrupt_id,
- unsigned int *virq)
+int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev,
+ enum ps3_cpu_binding cpu, unsigned int *virq)
{
/* this should go in system-bus.c */
@@ -420,8 +418,8 @@ int ps3_sb_event_receive_port_setup(enum
if (result)
return result;
- result = lv1_connect_interrupt_event_receive_port(did->bus_id,
- did->dev_id, virq_to_hw(*virq), interrupt_id);
+ result = lv1_connect_interrupt_event_receive_port(dev->bus_id,
+ dev->dev_id, virq_to_hw(*virq), dev->interrupt_id);
if (result) {
pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port"
@@ -433,24 +431,24 @@ int ps3_sb_event_receive_port_setup(enum
}
pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
- interrupt_id, *virq);
+ dev->interrupt_id, *virq);
return 0;
}
EXPORT_SYMBOL(ps3_sb_event_receive_port_setup);
-int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did,
- unsigned int interrupt_id, unsigned int virq)
+int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev,
+ unsigned int virq)
{
/* this should go in system-bus.c */
int result;
pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
- interrupt_id, virq);
+ dev->interrupt_id, virq);
- result = lv1_disconnect_interrupt_event_receive_port(did->bus_id,
- did->dev_id, virq_to_hw(virq), interrupt_id);
+ 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"
--- a/arch/powerpc/platforms/ps3/mm.c
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -17,6 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define DEBUG
#include <linux/kernel.h>
#include <linux/module.h>
@@ -32,7 +33,7 @@
#if defined(DEBUG)
#define DBG(fmt...) udbg_printf(fmt)
#else
-#define DBG(fmt...) do{if(0)printk(fmt);}while(0)
+#define DBG(fmt...) do { if (0) printk(fmt);} while (0)
#endif
enum {
@@ -115,7 +116,8 @@ struct map {
};
#define debug_dump_map(x) _debug_dump_map(x, __func__, __LINE__)
-static void _debug_dump_map(const struct map* m, const char* func, int line)
+static void __maybe_unused _debug_dump_map(const struct map* m,
+ const char* func, int line)
{
DBG("%s:%d: map.total = %lxh\n", func, line, m->total);
DBG("%s:%d: map.rm.size = %lxh\n", func, line, m->rm.size);
@@ -212,9 +214,15 @@ fail:
void ps3_mm_vas_destroy(void)
{
+ int result;
+
+ DBG("%s:%d: map.vas_id = %lu\n", __func__, __LINE__, map.vas_id);
+
if (map.vas_id) {
- lv1_select_virtual_address_space(0);
- lv1_destruct_virtual_address_space(map.vas_id);
+ result = lv1_select_virtual_address_space(0);
+ BUG_ON(result);
+ result = lv1_destruct_virtual_address_space(map.vas_id);
+ BUG_ON(result);
map.vas_id = 0;
}
}
@@ -275,8 +283,12 @@ zero_region:
void ps3_mm_region_destroy(struct mem_region *r)
{
+ int result;
+
+ DBG("%s:%d: r->base = %lxh\n", __func__, __LINE__, r->base);
if (r->base) {
- lv1_release_memory(r->base);
+ result = lv1_release_memory(r->base);
+ BUG_ON(result);
r->size = r->base = r->offset = 0;
map.total = map.rm.size;
}
@@ -329,31 +341,34 @@ core_initcall(ps3_mm_add_memory);
/*============================================================================*/
/**
- * dma_lpar_to_bus - Translate an lpar address to ioc mapped bus address.
+ * dma_sb_lpar_to_bus - Translate an lpar address to ioc mapped bus address.
* @r: pointer to dma region structure
* @lpar_addr: HV lpar address
*/
-static unsigned long dma_lpar_to_bus(struct ps3_dma_region *r,
+static unsigned long dma_sb_lpar_to_bus(struct ps3_dma_region *r,
unsigned long lpar_addr)
{
- BUG_ON(lpar_addr >= map.r1.base + map.r1.size);
- return r->bus_addr + (lpar_addr <= map.rm.size ? lpar_addr
- : lpar_addr - map.r1.offset);
+ if (lpar_addr >= map.rm.size)
+ lpar_addr -= map.r1.offset;
+ BUG_ON(lpar_addr < r->offset);
+ BUG_ON(lpar_addr >= r->offset + r->len);
+ return r->bus_addr + lpar_addr - r->offset;
}
#define dma_dump_region(_a) _dma_dump_region(_a, __func__, __LINE__)
-static void _dma_dump_region(const struct ps3_dma_region *r, const char* func,
- int line)
+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->did.bus_id,
- r->did.dev_id);
+ DBG("%s:%d: dev %u:%u\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);
DBG("%s:%d: len %lxh\n", func, line, r->len);
+ DBG("%s:%d: offset %lxh\n", func, line, r->offset);
}
-
-/**
+
+ /**
* dma_chunk - A chunk of dma pages mapped by the io controller.
* @region - The dma region that owns this chunk.
* @lpar_addr: Starting lpar address of the area to map.
@@ -381,10 +396,11 @@ static void _dma_dump_chunk (const struc
int line)
{
DBG("%s:%d: r.dev %u:%u\n", func, line,
- c->region->did.bus_id, c->region->did.dev_id);
+ 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);
DBG("%s:%d: r.len %lxh\n", func, line, c->region->len);
+ DBG("%s:%d: r.offset %lxh\n", func, line, c->region->offset);
DBG("%s:%d: c.lpar_addr %lxh\n", func, line, c->lpar_addr);
DBG("%s:%d: c.bus_addr %lxh\n", func, line, c->bus_addr);
DBG("%s:%d: c.len %lxh\n", func, line, c->len);
@@ -395,39 +411,68 @@ static struct dma_chunk * dma_find_chunk
{
struct dma_chunk *c;
unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, 1 << r->page_size);
- unsigned long aligned_len = _ALIGN_UP(len, 1 << r->page_size);
+ unsigned long aligned_len = _ALIGN_UP(len+bus_addr-aligned_bus,
+ 1 << r->page_size);
list_for_each_entry(c, &r->chunk_list.head, link) {
/* intersection */
- if (aligned_bus >= c->bus_addr
- && aligned_bus < c->bus_addr + c->len
- && aligned_bus + aligned_len <= c->bus_addr + c->len) {
+ if (aligned_bus >= c->bus_addr &&
+ aligned_bus + aligned_len <= c->bus_addr + c->len)
return c;
- }
+
/* below */
- if (aligned_bus + aligned_len <= c->bus_addr) {
+ if (aligned_bus + aligned_len <= c->bus_addr)
continue;
- }
+
/* above */
- if (aligned_bus >= c->bus_addr + c->len) {
+ if (aligned_bus >= c->bus_addr + c->len)
continue;
- }
/* we don't handle the multi-chunk case for now */
-
dma_dump_chunk(c);
BUG();
}
return NULL;
}
-static int dma_free_chunk(struct dma_chunk *c)
+static struct dma_chunk * dma_find_chunk_lpar(struct ps3_dma_region *r,
+ unsigned long lpar_addr, unsigned long len)
+{
+ struct dma_chunk *c;
+ unsigned long aligned_lpar = _ALIGN_DOWN(lpar_addr, 1 << r->page_size);
+ unsigned long aligned_len = _ALIGN_UP(len + lpar_addr - aligned_lpar,
+ 1 << r->page_size);
+
+ list_for_each_entry(c, &r->chunk_list.head, link) {
+ /* intersection */
+ if (c->lpar_addr <= aligned_lpar &&
+ aligned_lpar < c->lpar_addr + c->len) {
+ if (aligned_lpar + aligned_len <= c->lpar_addr + c->len)
+ return c;
+ else {
+ dma_dump_chunk(c);
+ BUG();
+ }
+ }
+ /* below */
+ if (aligned_lpar + aligned_len <= c->lpar_addr) {
+ continue;
+ }
+ /* above */
+ if (c->lpar_addr + c->len <= aligned_lpar) {
+ continue;
+ }
+ }
+ return NULL;
+}
+
+static int dma_sb_free_chunk(struct dma_chunk *c)
{
int result = 0;
if (c->bus_addr) {
- result = lv1_unmap_device_dma_region(c->region->did.bus_id,
- c->region->did.dev_id, c->bus_addr, c->len);
+ result = lv1_unmap_device_dma_region(c->region->dev->bus_id,
+ c->region->dev->dev_id, c->bus_addr, c->len);
BUG_ON(result);
}
@@ -435,8 +480,39 @@ static int dma_free_chunk(struct dma_chu
return result;
}
+static int dma_ioc0_free_chunk(struct dma_chunk *c)
+{
+ int result = 0;
+ int iopage;
+ unsigned long offset;
+ struct ps3_dma_region * r = c->region;
+
+ DBG("%s:start\n", __func__);
+ for (iopage = 0; iopage < (c->len >> r->page_size); iopage++) {
+ offset = (1 << r->page_size) * iopage;
+ /* put INVALID entry */
+ result = lv1_put_iopte(0,
+ c->bus_addr + offset,
+ c->lpar_addr + offset,
+ r->ioid,
+ 0);
+ DBG("%s: bus=%#lx, lpar=%#lx, ioid=%d\n", __func__,
+ c->bus_addr + offset,
+ c->lpar_addr + offset,
+ r->ioid);
+
+ if (result) {
+ DBG("%s:%d: lv1_put_iopte failed: %s\n", __func__,
+ __LINE__, ps3_result(result));
+ }
+ }
+ kfree(c);
+ DBG("%s:end\n", __func__);
+ return result;
+}
+
/**
- * dma_map_pages - Maps dma pages into the io controller bus address space.
+ * dma_sb_map_pages - Maps dma pages into the io controller bus address space.
* @r: Pointer to a struct ps3_dma_region.
* @phys_addr: Starting physical address of the area to map.
* @len: Length in bytes of the area to map.
@@ -446,8 +522,8 @@ static int dma_free_chunk(struct dma_chu
* make the HV call to add the pages into the io controller address space.
*/
-static int dma_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
- unsigned long len, struct dma_chunk **c_out)
+static int dma_sb_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
+ unsigned long len, struct dma_chunk **c_out, u64 iopte_flag)
{
int result;
struct dma_chunk *c;
@@ -461,13 +537,13 @@ static int dma_map_pages(struct ps3_dma_
c->region = r;
c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr);
- c->bus_addr = dma_lpar_to_bus(r, c->lpar_addr);
+ c->bus_addr = dma_sb_lpar_to_bus(r, c->lpar_addr);
c->len = len;
- result = lv1_map_device_dma_region(c->region->did.bus_id,
- c->region->did.dev_id, c->lpar_addr, c->bus_addr, c->len,
- 0xf800000000000000UL);
-
+ BUG_ON(iopte_flag != 0xf800000000000000UL);
+ result = lv1_map_device_dma_region(c->region->dev->bus_id,
+ c->region->dev->dev_id, c->lpar_addr,
+ c->bus_addr, c->len, iopte_flag);
if (result) {
DBG("%s:%d: lv1_map_device_dma_region failed: %s\n",
__func__, __LINE__, ps3_result(result));
@@ -487,26 +563,119 @@ fail_alloc:
return result;
}
+static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
+ unsigned long len, struct dma_chunk **c_out,
+ u64 iopte_flag)
+{
+ int result;
+ struct dma_chunk *c, *last;
+ int iopage, pages;
+ unsigned long offset;
+
+ DBG(KERN_ERR "%s: phy=%#lx, lpar%#lx, len=%#lx\n", __func__,
+ phys_addr, ps3_mm_phys_to_lpar(phys_addr), len);
+ c = kzalloc(sizeof(struct dma_chunk), GFP_ATOMIC);
+
+ if (!c) {
+ result = -ENOMEM;
+ goto fail_alloc;
+ }
+
+ c->region = r;
+ c->len = len;
+ c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr);
+ /* allocate IO address */
+ if (list_empty(&r->chunk_list.head)) {
+ /* first one */
+ c->bus_addr = r->bus_addr;
+ } else {
+ /* derive from last bus addr*/
+ last = list_entry(r->chunk_list.head.next,
+ struct dma_chunk, link);
+ c->bus_addr = last->bus_addr + last->len;
+ DBG("%s: last bus=%#lx, len=%#lx\n", __func__,
+ last->bus_addr, last->len);
+ }
+
+ /* FIXME: check whether length exceeds region size */
+
+ /* build ioptes for the area */
+ pages = len >> r->page_size;
+ DBG("%s: pgsize=%#x len=%#lx pages=%#x iopteflag=%#lx\n", __func__,
+ r->page_size, r->len, pages, iopte_flag);
+ for (iopage = 0; iopage < pages; iopage++) {
+ offset = (1 << r->page_size) * iopage;
+ result = lv1_put_iopte(0,
+ c->bus_addr + offset,
+ c->lpar_addr + offset,
+ r->ioid,
+ iopte_flag);
+ if (result) {
+ printk("%s:%d: lv1_map_device_dma_region failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ goto fail_map;
+ }
+ DBG("%s: pg=%d bus=%#lx, lpar=%#lx, ioid=%#x\n", __func__,
+ iopage, c->bus_addr + offset, c->lpar_addr + offset,
+ r->ioid);
+ }
+
+ /* be sure that last allocated one is inserted at head */
+ list_add(&c->link, &r->chunk_list.head);
+
+ *c_out = c;
+ DBG("%s: end\n", __func__);
+ return 0;
+
+fail_map:
+ for (iopage--; 0 <= iopage; iopage--) {
+ lv1_put_iopte(0,
+ c->bus_addr + offset,
+ c->lpar_addr + offset,
+ r->ioid,
+ 0);
+ }
+ kfree(c);
+fail_alloc:
+ *c_out = NULL;
+ return result;
+}
+
/**
- * dma_region_create - Create a device dma region.
+ * dma_sb_region_create - Create a device dma region.
* @r: Pointer to a struct ps3_dma_region.
*
* This is the lowest level dma region create routine, and is the one that
* will make the HV call to create the region.
*/
-static int dma_region_create(struct ps3_dma_region* r)
+static int dma_sb_region_create(struct ps3_dma_region* r)
{
int result;
- r->len = _ALIGN_UP(map.total, 1 << r->page_size);
+ pr_info(" -> %s:%d:\n", __func__, __LINE__);
+
+ BUG_ON(!r);
+
+ if(!r->dev->bus_id) {
+ pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__,
+ r->dev->bus_id, r->dev->dev_id);
+ return 0;
+ }
+
+ DBG("%s:%u: len = 0x%lx, page_size = %u, offset = 0x%lx\n", __func__,
+ __LINE__, r->len, r->page_size, r->offset);
+
+ BUG_ON(!r->len);
+ BUG_ON(!r->page_size);
+ BUG_ON(!r->region_ops);
+
INIT_LIST_HEAD(&r->chunk_list.head);
spin_lock_init(&r->chunk_list.lock);
- result = lv1_allocate_device_dma_region(r->did.bus_id, r->did.dev_id,
- r->len, r->page_size, r->region_type, &r->bus_addr);
-
- dma_dump_region(r);
+ result = lv1_allocate_device_dma_region(r->dev->bus_id, r->dev->dev_id,
+ roundup_pow_of_two(r->len), r->page_size, r->region_type,
+ &r->bus_addr);
if (result) {
DBG("%s:%d: lv1_allocate_device_dma_region failed: %s\n",
@@ -517,6 +686,27 @@ static int dma_region_create(struct ps3_
return result;
}
+static int dma_ioc0_region_create(struct ps3_dma_region* r)
+{
+ int result;
+
+ INIT_LIST_HEAD(&r->chunk_list.head);
+ spin_lock_init(&r->chunk_list.lock);
+
+ result = lv1_allocate_io_segment(0,
+ r->len,
+ r->page_size,
+ &r->bus_addr);
+ if (result) {
+ DBG("%s:%d: lv1_allocate_io_segment failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ r->len = r->bus_addr = 0;
+ }
+ DBG("%s: len=%#lx, pg=%d, bus=%#lx\n", __func__,
+ r->len, r->page_size, r->bus_addr);
+ return result;
+}
+
/**
* dma_region_free - Free a device dma region.
* @r: Pointer to a struct ps3_dma_region.
@@ -525,31 +715,62 @@ static int dma_region_create(struct ps3_
* will make the HV call to free the region.
*/
-static int dma_region_free(struct ps3_dma_region* r)
+static int dma_sb_region_free(struct ps3_dma_region* r)
{
int result;
struct dma_chunk *c;
struct dma_chunk *tmp;
+ BUG_ON(!r);
+
+ if(!r->dev->bus_id) {
+ pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__,
+ r->dev->bus_id, r->dev->dev_id);
+ return 0;
+ }
+
list_for_each_entry_safe(c, tmp, &r->chunk_list.head, link) {
list_del(&c->link);
- dma_free_chunk(c);
+ dma_sb_free_chunk(c);
}
- result = lv1_free_device_dma_region(r->did.bus_id, r->did.dev_id,
+ result = lv1_free_device_dma_region(r->dev->bus_id, r->dev->dev_id,
r->bus_addr);
if (result)
DBG("%s:%d: lv1_free_device_dma_region failed: %s\n",
__func__, __LINE__, ps3_result(result));
- r->len = r->bus_addr = 0;
+ r->bus_addr = 0;
+
+ return result;
+}
+
+static int dma_ioc0_region_free(struct ps3_dma_region* r)
+{
+ int result;
+ struct dma_chunk *c, *n;
+
+ DBG("%s: start\n", __func__);
+ list_for_each_entry_safe(c, n, &r->chunk_list.head, link) {
+ list_del(&c->link);
+ dma_ioc0_free_chunk(c);
+ }
+
+ result = lv1_release_io_segment(0, r->bus_addr);
+
+ if (result)
+ DBG("%s:%d: lv1_free_device_dma_region failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+
+ r->bus_addr = 0;
+ DBG("%s: end\n", __func__);
return result;
}
/**
- * dma_map_area - Map an area of memory into a device dma region.
+ * dma_sb_map_area - Map an area of memory into a device dma region.
* @r: Pointer to a struct ps3_dma_region.
* @virt_addr: Starting virtual address of the area to map.
* @len: Length in bytes of the area to map.
@@ -559,16 +780,19 @@ static int dma_region_free(struct ps3_dm
* This is the common dma mapping routine.
*/
-static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
- unsigned long len, unsigned long *bus_addr)
+static int dma_sb_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
+ unsigned long len, unsigned long *bus_addr,
+ u64 iopte_flag)
{
int result;
unsigned long flags;
struct dma_chunk *c;
unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr)
: virt_addr;
-
- *bus_addr = dma_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr));
+ unsigned long aligned_phys = _ALIGN_DOWN(phys_addr, 1 << r->page_size);
+ unsigned long aligned_len = _ALIGN_UP(len + phys_addr - aligned_phys,
+ 1 << r->page_size);
+ *bus_addr = dma_sb_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr));
if (!USE_DYNAMIC_DMA) {
unsigned long lpar_addr = ps3_mm_phys_to_lpar(phys_addr);
@@ -588,17 +812,18 @@ static int dma_map_area(struct ps3_dma_r
c = dma_find_chunk(r, *bus_addr, len);
if (c) {
+ DBG("%s:%d: reusing mapped chunk", __func__, __LINE__);
+ dma_dump_chunk(c);
c->usage_count++;
spin_unlock_irqrestore(&r->chunk_list.lock, flags);
return 0;
}
- result = dma_map_pages(r, _ALIGN_DOWN(phys_addr, 1 << r->page_size),
- _ALIGN_UP(len, 1 << r->page_size), &c);
+ result = dma_sb_map_pages(r, aligned_phys, aligned_len, &c, iopte_flag);
if (result) {
*bus_addr = 0;
- DBG("%s:%d: dma_map_pages failed (%d)\n",
+ DBG("%s:%d: dma_sb_map_pages failed (%d)\n",
__func__, __LINE__, result);
spin_unlock_irqrestore(&r->chunk_list.lock, flags);
return result;
@@ -610,8 +835,57 @@ static int dma_map_area(struct ps3_dma_r
return result;
}
+static int dma_ioc0_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
+ unsigned long len, unsigned long *bus_addr,
+ u64 iopte_flag)
+{
+ int result;
+ unsigned long flags;
+ struct dma_chunk *c;
+ unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr)
+ : virt_addr;
+ unsigned long aligned_phys = _ALIGN_DOWN(phys_addr, 1 << r->page_size);
+ unsigned long aligned_len = _ALIGN_UP(len + phys_addr - aligned_phys,
+ 1 << r->page_size);
+
+ DBG(KERN_ERR "%s: vaddr=%#lx, len=%#lx\n", __func__,
+ virt_addr, len);
+ DBG(KERN_ERR "%s: ph=%#lx a_ph=%#lx a_l=%#lx\n", __func__,
+ phys_addr, aligned_phys, aligned_len);
+
+ spin_lock_irqsave(&r->chunk_list.lock, flags);
+ c = dma_find_chunk_lpar(r, ps3_mm_phys_to_lpar(phys_addr), len);
+
+ if (c) {
+ /* FIXME */
+ BUG();
+ *bus_addr = c->bus_addr + phys_addr - aligned_phys;
+ c->usage_count++;
+ spin_unlock_irqrestore(&r->chunk_list.lock, flags);
+ return 0;
+ }
+
+ result = dma_ioc0_map_pages(r, aligned_phys, aligned_len, &c,
+ iopte_flag);
+
+ if (result) {
+ *bus_addr = 0;
+ DBG("%s:%d: dma_ioc0_map_pages failed (%d)\n",
+ __func__, __LINE__, result);
+ spin_unlock_irqrestore(&r->chunk_list.lock, flags);
+ return result;
+ }
+ *bus_addr = c->bus_addr + phys_addr - aligned_phys;
+ DBG("%s: va=%#lx pa=%#lx a_pa=%#lx bus=%#lx\n", __func__,
+ virt_addr, phys_addr, aligned_phys, *bus_addr);
+ c->usage_count = 1;
+
+ spin_unlock_irqrestore(&r->chunk_list.lock, flags);
+ return result;
+}
+
/**
- * dma_unmap_area - Unmap an area of memory from a device dma region.
+ * dma_sb_unmap_area - Unmap an area of memory from a device dma region.
* @r: Pointer to a struct ps3_dma_region.
* @bus_addr: The starting ioc bus address of the area to unmap.
* @len: Length in bytes of the area to unmap.
@@ -619,7 +893,7 @@ static int dma_map_area(struct ps3_dma_r
* This is the common dma unmap routine.
*/
-int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr,
+int dma_sb_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr,
unsigned long len)
{
unsigned long flags;
@@ -631,7 +905,8 @@ int dma_unmap_area(struct ps3_dma_region
if (!c) {
unsigned long aligned_bus = _ALIGN_DOWN(bus_addr,
1 << r->page_size);
- unsigned long aligned_len = _ALIGN_UP(len, 1 << r->page_size);
+ unsigned long aligned_len = _ALIGN_UP(len + bus_addr - aligned_bus,
+ 1 << r->page_size);
DBG("%s:%d: not found: bus_addr %lxh\n",
__func__, __LINE__, bus_addr);
DBG("%s:%d: not found: len %lxh\n",
@@ -647,94 +922,165 @@ int dma_unmap_area(struct ps3_dma_region
if (!c->usage_count) {
list_del(&c->link);
- dma_free_chunk(c);
+ dma_sb_free_chunk(c);
+ }
+
+ spin_unlock_irqrestore(&r->chunk_list.lock, flags);
+ return 0;
+}
+
+int dma_ioc0_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr,
+ unsigned long len)
+{
+ unsigned long flags;
+ struct dma_chunk *c;
+
+ DBG("%s: start a=%#lx l=%#lx\n", __func__, bus_addr, len);
+ spin_lock_irqsave(&r->chunk_list.lock, flags);
+ c = dma_find_chunk(r, bus_addr, len);
+
+ if (!c) {
+ unsigned long aligned_bus = _ALIGN_DOWN(bus_addr,
+ 1 << r->page_size);
+ unsigned long aligned_len = _ALIGN_UP(len + bus_addr - aligned_bus,
+ 1 << r->page_size);
+ DBG("%s:%d: not found: bus_addr %lxh\n",
+ __func__, __LINE__, bus_addr);
+ DBG("%s:%d: not found: len %lxh\n",
+ __func__, __LINE__, len);
+ DBG("%s:%d: not found: aligned_bus %lxh\n",
+ __func__, __LINE__, aligned_bus);
+ DBG("%s:%d: not found: aligned_len %lxh\n",
+ __func__, __LINE__, aligned_len);
+ BUG();
+ }
+
+ c->usage_count--;
+
+ if (!c->usage_count) {
+ list_del(&c->link);
+ dma_ioc0_free_chunk(c);
}
spin_unlock_irqrestore(&r->chunk_list.lock, flags);
+ DBG("%s: end\n", __func__);
return 0;
}
/**
- * dma_region_create_linear - Setup a linear dma maping for a device.
+ * dma_sb_region_create_linear - Setup a linear dma mapping for a device.
* @r: Pointer to a struct ps3_dma_region.
*
* This routine creates an HV dma region for the device and maps all available
* ram into the io controller bus address space.
*/
-static int dma_region_create_linear(struct ps3_dma_region *r)
+static int dma_sb_region_create_linear(struct ps3_dma_region *r)
{
int result;
- unsigned long tmp;
-
- /* force 16M dma pages for linear mapping */
+ unsigned long virt_addr, len, tmp;
- if (r->page_size != PS3_DMA_16M) {
- pr_info("%s:%d: forcing 16M pages for linear map\n",
- __func__, __LINE__);
- r->page_size = PS3_DMA_16M;
+ if (r->len > 16*1024*1024) { // FIXME
+ /* force 16M dma pages for linear mapping */
+ if (r->page_size != PS3_DMA_16M) {
+ pr_info("%s:%d: forcing 16M pages for linear map\n",
+ __func__, __LINE__);
+ r->page_size = PS3_DMA_16M;
+ r->len = _ALIGN_UP(r->len, 1 << r->page_size);
+ }
}
- result = dma_region_create(r);
+ result = dma_sb_region_create(r);
BUG_ON(result);
- result = dma_map_area(r, map.rm.base, map.rm.size, &tmp);
- BUG_ON(result);
-
- if (USE_LPAR_ADDR)
- result = dma_map_area(r, map.r1.base, map.r1.size,
- &tmp);
- else
- result = dma_map_area(r, map.rm.size, map.r1.size,
- &tmp);
+ if (r->offset < map.rm.size) {
+ /* Map (part of) 1st RAM chunk */
+ virt_addr = map.rm.base + r->offset;
+ len = map.rm.size - r->offset;
+ if (len > r->len)
+ len = r->len;
+ result = dma_sb_map_area(r, virt_addr, len, &tmp,
+ IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
+ BUG_ON(result);
+ }
- BUG_ON(result);
+ 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;
+ len = r->len;
+ if (r->offset >= map.rm.size)
+ virt_addr += r->offset - map.rm.size;
+ else
+ len -= map.rm.size - r->offset;
+ result = dma_sb_map_area(r, virt_addr, len, &tmp,
+ IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
+ BUG_ON(result);
+ }
return result;
}
/**
- * dma_region_free_linear - Free a linear dma mapping for a device.
+ * dma_sb_region_free_linear - Free a linear dma mapping for a device.
* @r: Pointer to a struct ps3_dma_region.
*
* This routine will unmap all mapped areas and free the HV dma region.
*/
-static int dma_region_free_linear(struct ps3_dma_region *r)
+static int dma_sb_region_free_linear(struct ps3_dma_region *r)
{
int result;
+ unsigned long bus_addr, len, lpar_addr;
- result = dma_unmap_area(r, dma_lpar_to_bus(r, 0), map.rm.size);
- BUG_ON(result);
+ if (r->offset < map.rm.size) {
+ /* Unmap (part of) 1st RAM chunk */
+ lpar_addr = map.rm.base + r->offset;
+ len = map.rm.size - r->offset;
+ if (len > r->len)
+ len = r->len;
+ bus_addr = dma_sb_lpar_to_bus(r, lpar_addr);
+ result = dma_sb_unmap_area(r, bus_addr, len);
+ BUG_ON(result);
+ }
- result = dma_unmap_area(r, dma_lpar_to_bus(r, map.r1.base),
- map.r1.size);
- BUG_ON(result);
+ if (r->offset + r->len > map.rm.size) {
+ /* Unmap (part of) 2nd RAM chunk */
+ lpar_addr = map.r1.base;
+ len = r->len;
+ if (r->offset >= map.rm.size)
+ lpar_addr += r->offset - map.rm.size;
+ else
+ len -= map.rm.size - r->offset;
+ bus_addr = dma_sb_lpar_to_bus(r, lpar_addr);
+ result = dma_sb_unmap_area(r, bus_addr, len);
+ BUG_ON(result);
+ }
- result = dma_region_free(r);
+ result = dma_sb_region_free(r);
BUG_ON(result);
return result;
}
/**
- * dma_map_area_linear - Map an area of memory into a device dma region.
+ * dma_sb_map_area_linear - Map an area of memory into a device dma region.
* @r: Pointer to a struct ps3_dma_region.
* @virt_addr: Starting virtual address of the area to map.
* @len: Length in bytes of the area to map.
* @bus_addr: A pointer to return the starting ioc bus address of the area to
* map.
*
- * This routine just returns the coresponding bus address. Actual mapping
+ * This routine just returns the corresponding bus address. Actual mapping
* occurs in dma_region_create_linear().
*/
-static int dma_map_area_linear(struct ps3_dma_region *r,
- unsigned long virt_addr, unsigned long len, unsigned long *bus_addr)
+static int dma_sb_map_area_linear(struct ps3_dma_region *r,
+ unsigned long virt_addr, unsigned long len, unsigned long *bus_addr,
+ u64 iopte_flag)
{
unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr)
: virt_addr;
- *bus_addr = dma_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr));
+ *bus_addr = dma_sb_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr));
return 0;
}
@@ -744,42 +1090,98 @@ static int dma_map_area_linear(struct ps
* @bus_addr: The starting ioc bus address of the area to unmap.
* @len: Length in bytes of the area to unmap.
*
- * This routine does nothing. Unmapping occurs in dma_region_free_linear().
+ * This routine does nothing. Unmapping occurs in dma_sb_region_free_linear().
*/
-static int dma_unmap_area_linear(struct ps3_dma_region *r,
+static int dma_sb_unmap_area_linear(struct ps3_dma_region *r,
unsigned long bus_addr, unsigned long len)
{
return 0;
+};
+
+static const struct ps3_dma_region_ops ps3_dma_sb_region_ops = {
+ .create = dma_sb_region_create,
+ .free = dma_sb_region_free,
+ .map = dma_sb_map_area,
+ .unmap = dma_sb_unmap_area
+};
+
+static const struct ps3_dma_region_ops ps3_dma_sb_region_linear_ops = {
+ .create = dma_sb_region_create_linear,
+ .free = dma_sb_region_free_linear,
+ .map = dma_sb_map_area_linear,
+ .unmap = dma_sb_unmap_area_linear
+};
+
+static const struct ps3_dma_region_ops ps3_dma_ioc0_region_ops = {
+ .create = dma_ioc0_region_create,
+ .free = dma_ioc0_region_free,
+ .map = dma_ioc0_map_area,
+ .unmap = dma_ioc0_unmap_area
+};
+
+int ps3_dma_region_init(struct ps3_system_bus_device *dev,
+ struct ps3_dma_region *r, enum ps3_dma_page_size page_size,
+ enum ps3_dma_region_type region_type, void *addr, unsigned long len)
+{
+ unsigned long lpar_addr;
+
+ lpar_addr = addr ? ps3_mm_phys_to_lpar(__pa(addr)) : 0;
+
+ r->dev = dev;
+ r->page_size = page_size;
+ r->region_type = region_type;
+ r->offset = lpar_addr;
+ if (r->offset >= map.rm.size)
+ r->offset -= map.r1.offset;
+ r->len = len ? len : _ALIGN_UP(map.total, 1 << r->page_size);
+
+ switch (dev->dev_type) {
+ case PS3_DEVICE_TYPE_SB:
+ r->region_ops = (USE_DYNAMIC_DMA)
+ ? &ps3_dma_sb_region_ops
+ : &ps3_dma_sb_region_linear_ops;
+ break;
+ case PS3_DEVICE_TYPE_IOC0:
+ r->region_ops = &ps3_dma_ioc0_region_ops;
+ break;
+ default:
+ BUG();
+ return -EINVAL;
+ }
+ return 0;
}
+EXPORT_SYMBOL(ps3_dma_region_init);
int ps3_dma_region_create(struct ps3_dma_region *r)
{
- return (USE_DYNAMIC_DMA)
- ? dma_region_create(r)
- : dma_region_create_linear(r);
+ BUG_ON(!r);
+ BUG_ON(!r->region_ops);
+ BUG_ON(!r->region_ops->create);
+ return r->region_ops->create(r);
}
+EXPORT_SYMBOL(ps3_dma_region_create);
int ps3_dma_region_free(struct ps3_dma_region *r)
{
- return (USE_DYNAMIC_DMA)
- ? dma_region_free(r)
- : dma_region_free_linear(r);
+ BUG_ON(!r);
+ BUG_ON(!r->region_ops);
+ BUG_ON(!r->region_ops->free);
+ return r->region_ops->free(r);
}
+EXPORT_SYMBOL(ps3_dma_region_free);
int ps3_dma_map(struct ps3_dma_region *r, unsigned long virt_addr,
- unsigned long len, unsigned long *bus_addr)
+ unsigned long len, unsigned long *bus_addr,
+ u64 iopte_flag)
{
- return (USE_DYNAMIC_DMA)
- ? dma_map_area(r, virt_addr, len, bus_addr)
- : dma_map_area_linear(r, virt_addr, len, bus_addr);
+ return r->region_ops->map(r, virt_addr, len, bus_addr, iopte_flag);
}
int ps3_dma_unmap(struct ps3_dma_region *r, unsigned long bus_addr,
unsigned long len)
{
- return (USE_DYNAMIC_DMA) ? dma_unmap_area(r, bus_addr, len)
- : dma_unmap_area_linear(r, bus_addr, len);
+ return r->region_ops->unmap(r, bus_addr, len);
}
/*============================================================================*/
@@ -816,6 +1218,9 @@ void __init ps3_mm_init(void)
/* arrange to do this in ps3_mm_add_memory */
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;
+
DBG(" <- %s:%d\n", __func__, __LINE__);
}
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -82,6 +82,7 @@ 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_NOACCESS = 255,
};
int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
@@ -216,4 +217,14 @@ int ps3_repository_read_num_spu_resource
int ps3_repository_read_spu_resource_id(unsigned int res_index,
enum ps3_spu_resource_type* resource_type, unsigned int *resource_id);
+/* Page table entries */
+#define IOPTE_PP_W 0x8000000000000000ul /* protection: write */
+#define IOPTE_PP_R 0x4000000000000000ul /* protection: read */
+#define IOPTE_M 0x2000000000000000ul /* coherency required */
+#define IOPTE_SO_R 0x1000000000000000ul /* ordering: writes */
+#define IOPTE_SO_RW 0x1800000000000000ul /* ordering: r & w */
+#define IOPTE_RPN_Mask 0x07fffffffffff000ul /* RPN */
+#define IOPTE_H 0x0000000000000800ul /* cache hint */
+#define IOPTE_IOID_Mask 0x00000000000007fful /* ioid */
+
#endif
--- a/arch/powerpc/platforms/ps3/system-bus.c
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -18,6 +18,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define DEBUG
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -30,22 +32,222 @@
#include "platform.h"
+static struct device ps3_system_bus = {
+ .bus_id = "ps3_system",
+};
+
+// FIXME: need device usage counters!
+struct {
+ struct mutex mutex;
+ int sb_11; // usb 0
+ int sb_12; // usb 1
+ int gpu;
+} static usage_hack;
+
+static int ps3_open_hv_device_sb(struct ps3_system_bus_device *dev)
+{
+ int result;
+
+ BUG_ON(!dev->bus_id);
+ mutex_lock(&usage_hack.mutex);
+
+ if(dev->bus_id == 1 && dev->dev_id == 1) {
+ usage_hack.sb_11++;
+ if (usage_hack.sb_11 > 1) {
+ result = 0;
+ goto done;
+ }
+ }
+
+ if(dev->bus_id == 1 && dev->dev_id == 2) {
+ usage_hack.sb_12++;
+ if (usage_hack.sb_12 > 1) {
+ result = 0;
+ goto done;
+ }
+ }
+
+ result = lv1_open_device(dev->bus_id, dev->dev_id, 0);
+
+ if (result) {
+ pr_debug("%s:%d: lv1_open_device failed: %s\n", __func__,
+ __LINE__, ps3_result(result));
+ result = -EPERM;
+ }
+
+done:
+ mutex_unlock(&usage_hack.mutex);
+ return result;
+}
+
+static int ps3_close_hv_device_sb(struct ps3_system_bus_device *dev)
+{
+ int result;
+
+ BUG_ON(!dev->bus_id);
+ mutex_lock(&usage_hack.mutex);
+
+ if(dev->bus_id == 1 && dev->dev_id == 1) {
+ usage_hack.sb_11--;
+ if (usage_hack.sb_11) {
+ result = 0;
+ goto done;
+ }
+ }
+
+ if(dev->bus_id == 1 && dev->dev_id == 2) {
+ usage_hack.sb_12--;
+ if (usage_hack.sb_12) {
+ result = 0;
+ goto done;
+ }
+ }
+
+ result = lv1_close_device(dev->bus_id, dev->dev_id);
+ BUG_ON(result);
+
+done:
+ mutex_unlock(&usage_hack.mutex);
+ return result;
+}
+
+static int ps3_open_hv_device_gpu(struct ps3_system_bus_device *dev)
+{
+ int result;
+
+ mutex_lock(&usage_hack.mutex);
+
+ usage_hack.gpu++;
+ if (usage_hack.gpu > 1) {
+ result = 0;
+ goto done;
+ }
+
+ result = lv1_gpu_open(0);
+
+ if (result) {
+ pr_debug("%s:%d: lv1_gpu_open failed: %s\n", __func__,
+ __LINE__, ps3_result(result));
+ result = -EPERM;
+ }
+
+done:
+ mutex_unlock(&usage_hack.mutex);
+ return result;
+}
+
+static int ps3_close_hv_device_gpu(struct ps3_system_bus_device *dev)
+{
+ int result;
+
+ mutex_lock(&usage_hack.mutex);
+
+ usage_hack.gpu--;
+ if (usage_hack.gpu) {
+ result = 0;
+ goto done;
+ }
+
+ result = lv1_gpu_close();
+ BUG_ON(result);
+
+done:
+ mutex_unlock(&usage_hack.mutex);
+ return result;
+}
+
+int ps3_open_hv_device(struct ps3_system_bus_device *dev)
+{
+ BUG_ON(!dev);
+ pr_debug("%s:%d: match_id: %u\n", __func__, __LINE__, dev->match_id);
+
+ switch(dev->match_id) {
+ case PS3_MATCH_ID_EHCI:
+ case PS3_MATCH_ID_OHCI:
+ case PS3_MATCH_ID_GELIC:
+ case PS3_MATCH_ID_STOR_DISK:
+ case PS3_MATCH_ID_STOR_ROM:
+ case PS3_MATCH_ID_STOR_FLASH:
+ return ps3_open_hv_device_sb(dev);
+
+ case PS3_MATCH_ID_SOUND:
+ case PS3_MATCH_ID_GRAPHICS:
+ return ps3_open_hv_device_gpu(dev);
+
+ case PS3_MATCH_ID_AV_SETTINGS:
+ 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);
+ BUG();
+ return -EINVAL;
+
+ default:
+ break;
+ }
+
+ pr_debug("%s:%d: unknown match_id: %u\n", __func__, __LINE__,
+ dev->match_id);
+ BUG();
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(ps3_open_hv_device);
+
+int ps3_close_hv_device(struct ps3_system_bus_device *dev)
+{
+ BUG_ON(!dev);
+ pr_debug("%s:%d: match_id: %u\n", __func__, __LINE__, dev->match_id);
+
+ switch(dev->match_id) {
+ case PS3_MATCH_ID_EHCI:
+ case PS3_MATCH_ID_OHCI:
+ case PS3_MATCH_ID_GELIC:
+ case PS3_MATCH_ID_STOR_DISK:
+ case PS3_MATCH_ID_STOR_ROM:
+ case PS3_MATCH_ID_STOR_FLASH:
+ return ps3_close_hv_device_sb(dev);
+
+ case PS3_MATCH_ID_SOUND:
+ case PS3_MATCH_ID_GRAPHICS:
+ return ps3_close_hv_device_gpu(dev);
+
+ case PS3_MATCH_ID_AV_SETTINGS:
+ 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);
+ BUG();
+ return -EINVAL;
+
+ default:
+ break;
+ }
+
+ pr_debug("%s:%d: unknown match_id: %u\n", __func__, __LINE__,
+ dev->match_id);
+ BUG();
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(ps3_close_hv_device);
+
#define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__)
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->did.bus_id,
- r->did.dev_id);
+ pr_debug("%s:%d: dev %u:%u\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);
pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr);
}
-int ps3_mmio_region_create(struct ps3_mmio_region *r)
+static int ps3_sb_mmio_region_create(struct ps3_mmio_region *r)
{
int result;
- result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id,
+ result = lv1_map_device_mmio_region(r->dev->bus_id, r->dev->dev_id,
r->bus_addr, r->len, r->page_size, &r->lpar_addr);
if (result) {
@@ -57,13 +259,26 @@ int ps3_mmio_region_create(struct ps3_mm
dump_mmio_region(r);
return result;
}
+
+static int ps3_ioc0_mmio_region_create(struct ps3_mmio_region *r)
+{
+ /* device specific; do nothing currently */
+ return 0;
+}
+
+int ps3_mmio_region_create(struct ps3_mmio_region *r)
+{
+ return r->mmio_ops->create(r);
+}
EXPORT_SYMBOL_GPL(ps3_mmio_region_create);
-int ps3_free_mmio_region(struct ps3_mmio_region *r)
+static int ps3_sb_free_mmio_region(struct ps3_mmio_region *r)
{
int result;
- result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id,
+ dump_mmio_region(r);
+;
+ result = lv1_unmap_device_mmio_region(r->dev->bus_id, r->dev->dev_id,
r->lpar_addr);
if (result)
@@ -73,14 +288,60 @@ int ps3_free_mmio_region(struct ps3_mmio
r->lpar_addr = 0;
return result;
}
+
+static int ps3_ioc0_free_mmio_region(struct ps3_mmio_region *r)
+{
+ /* device specific; do nothing currently */
+ return 0;
+}
+
+
+int ps3_free_mmio_region(struct ps3_mmio_region *r)
+{
+ return r->mmio_ops->free(r);
+}
+
EXPORT_SYMBOL_GPL(ps3_free_mmio_region);
+static const struct ps3_mmio_region_ops ps3_mmio_sb_region_ops = {
+ .create = ps3_sb_mmio_region_create,
+ .free = ps3_sb_free_mmio_region
+};
+
+static const struct ps3_mmio_region_ops ps3_mmio_ioc0_region_ops = {
+ .create = ps3_ioc0_mmio_region_create,
+ .free = ps3_ioc0_free_mmio_region
+};
+
+int ps3_mmio_region_init(struct ps3_system_bus_device *dev,
+ struct ps3_mmio_region *r, unsigned long bus_addr, unsigned long len,
+ enum ps3_mmio_page_size page_size)
+{
+ r->dev = dev;
+ r->bus_addr = bus_addr;
+ r->len = len;
+ r->page_size = page_size;
+ switch (dev->dev_type) {
+ case PS3_DEVICE_TYPE_SB:
+ r->mmio_ops = &ps3_mmio_sb_region_ops;
+ break;
+ case PS3_DEVICE_TYPE_IOC0:
+ r->mmio_ops = &ps3_mmio_ioc0_region_ops;
+ break;
+ default:
+ BUG();
+ return -EINVAL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_mmio_region_init);
+
static int ps3_system_bus_match(struct device *_dev,
struct device_driver *_drv)
{
int result;
- struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv);
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ struct ps3_system_bus_driver *drv = ps3_drv_to_system_bus_drv(_drv);
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
result = dev->match_id == drv->match_id;
@@ -92,72 +353,84 @@ static int ps3_system_bus_match(struct d
static int ps3_system_bus_probe(struct device *_dev)
{
- int result;
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- struct ps3_system_bus_driver *drv =
- to_ps3_system_bus_driver(_dev->driver);
+ int result = 0;
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
+ struct ps3_system_bus_driver *drv;
- result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0);
-
- if (result) {
- pr_debug("%s:%d: lv1_open_device failed (%d)\n",
- __func__, __LINE__, result);
- result = -EACCES;
- goto clean_none;
- }
-
- if (dev->d_region->did.bus_id) {
- result = ps3_dma_region_create(dev->d_region);
-
- if (result) {
- pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n",
- __func__, __LINE__, result);
- BUG_ON("check region type");
- result = -EINVAL;
- goto clean_device;
- }
- }
+ BUG_ON(!dev);
+ pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id);
+ drv = ps3_system_bus_dev_to_system_bus_drv(dev);
BUG_ON(!drv);
- if (drv->probe)
+ if(drv->probe)
result = drv->probe(dev);
else
pr_info("%s:%d: %s no probe method\n", __func__, __LINE__,
dev->core.bus_id);
- if (result) {
- pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__);
- goto clean_dma;
- }
-
- return result;
-
-clean_dma:
- ps3_dma_region_free(dev->d_region);
-clean_device:
- lv1_close_device(dev->did.bus_id, dev->did.dev_id);
-clean_none:
+ pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id);
return result;
}
static int ps3_system_bus_remove(struct device *_dev)
{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- struct ps3_system_bus_driver *drv =
- to_ps3_system_bus_driver(_dev->driver);
+ int result = 0;
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
+ struct ps3_system_bus_driver *drv;
+
+ BUG_ON(!dev);
+ pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id);
+
+ drv = ps3_system_bus_dev_to_system_bus_drv(dev);
+ BUG_ON(!drv);
if (drv->remove)
- drv->remove(dev);
+ result = drv->remove(dev);
else
- pr_info("%s:%d: %s no remove method\n", __func__, __LINE__,
- dev->core.bus_id);
+ dev_dbg(&dev->core, "%s:%d %s: no remove method\n",
+ __func__, __LINE__, drv->core.name);
- ps3_dma_region_free(dev->d_region);
- ps3_free_mmio_region(dev->m_region);
- lv1_close_device(dev->did.bus_id, dev->did.dev_id);
+ pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id);
+ return result;
+}
- return 0;
+static void ps3_system_bus_shutdown(struct device *_dev)
+{
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
+ struct ps3_system_bus_driver *drv;
+
+ BUG_ON(!dev);
+
+ dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,
+ dev->match_id);
+
+ if (!dev->core.driver) {
+ dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,
+ __LINE__);
+ return;
+ }
+
+ drv = ps3_system_bus_dev_to_system_bus_drv(dev);
+
+ BUG_ON(!drv);
+
+ dev_dbg(&dev->core, "%s:%d: %s -> %s\n", __func__, __LINE__,
+ dev->core.bus_id, drv->core.name);
+
+ if (drv->shutdown)
+ drv->shutdown(dev);
+ else if (drv->remove) {
+ dev_dbg(&dev->core, "%s:%d %s: no shutdown, calling remove\n",
+ __func__, __LINE__, drv->core.name);
+ drv->remove(dev);
+ } else {
+ dev_dbg(&dev->core, "%s:%d %s: no shutdown method\n",
+ __func__, __LINE__, drv->core.name);
+ BUG();
+ }
+
+ dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
}
struct bus_type ps3_system_bus_type = {
@@ -165,17 +438,27 @@ struct bus_type ps3_system_bus_type = {
.match = ps3_system_bus_match,
.probe = ps3_system_bus_probe,
.remove = ps3_system_bus_remove,
+ .shutdown = ps3_system_bus_shutdown,
};
-int __init ps3_system_bus_init(void)
+static int __init ps3_system_bus_init(void)
{
int result;
if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
return -ENODEV;
+ printk(" -> %s:%d\n", __func__, __LINE__);
+
+ mutex_init(&usage_hack.mutex);
+
+ result = device_register(&ps3_system_bus);
+ BUG_ON(result);
+
result = bus_register(&ps3_system_bus_type);
BUG_ON(result);
+
+ printk(" <- %s:%d\n", __func__, __LINE__);
return result;
}
@@ -185,16 +468,13 @@ core_initcall(ps3_system_bus_init);
* Returns the virtual address of the buffer and sets dma_handle
* 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)
{
int result;
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
unsigned long virt_addr;
- BUG_ON(!dev->d_region->bus_addr);
-
flag &= ~(__GFP_DMA | __GFP_HIGHMEM);
flag |= __GFP_ZERO;
@@ -205,7 +485,8 @@ static void * ps3_alloc_coherent(struct
goto clean_none;
}
- result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle);
+ result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle,
+ IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
if (result) {
pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
@@ -226,7 +507,7 @@ clean_none:
static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
dma_addr_t dma_handle)
{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
ps3_dma_unmap(dev->d_region, dma_handle, size);
free_pages((unsigned long)vaddr, get_order(size));
@@ -239,15 +520,16 @@ static void ps3_free_coherent(struct dev
* byte within the page as vaddr.
*/
-static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size,
+static dma_addr_t ps3_sb_map_single(struct device *_dev, void *ptr, size_t size,
enum dma_data_direction direction)
{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
int result;
unsigned long bus_addr;
result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
- &bus_addr);
+ &bus_addr,
+ IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW | IOPTE_M);
if (result) {
pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
@@ -257,10 +539,43 @@ static dma_addr_t ps3_map_single(struct
return bus_addr;
}
+static dma_addr_t ps3_ioc0_map_single(struct device *_dev, void *ptr, size_t size,
+ enum dma_data_direction direction)
+{
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
+ int result;
+ unsigned long bus_addr;
+ u64 iopte_flag;
+
+ iopte_flag = IOPTE_M;
+ switch (direction) {
+ case DMA_BIDIRECTIONAL:
+ iopte_flag |= IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW;
+ break;
+ case DMA_TO_DEVICE:
+ iopte_flag |= IOPTE_PP_R | IOPTE_SO_R;
+ break;
+ case DMA_FROM_DEVICE:
+ iopte_flag |= IOPTE_PP_W | IOPTE_SO_RW;
+ break;
+ default:
+ /* not happned */
+ BUG();
+ };
+ result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
+ &bus_addr, iopte_flag);
+
+ if (result) {
+ pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
+ __func__, __LINE__, result);
+ }
+ return bus_addr;
+}
+
static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr,
size_t size, enum dma_data_direction direction)
{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
int result;
result = ps3_dma_unmap(dev->d_region, dma_addr, size);
@@ -271,20 +586,20 @@ static void ps3_unmap_single(struct devi
}
}
-static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
+static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
enum dma_data_direction direction)
{
#if defined(CONFIG_PS3_DYNAMIC_DMA)
BUG_ON("do");
return -EPERM;
#else
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
int i;
for (i = 0; i < nents; i++, sg++) {
int result = ps3_dma_map(dev->d_region,
page_to_phys(sg->page) + sg->offset, sg->length,
- &sg->dma_address);
+ &sg->dma_address, 0);
if (result) {
pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
@@ -299,7 +614,14 @@ static int ps3_map_sg(struct device *_de
#endif
}
-static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg,
+static int ps3_ioc0_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
+{
+ BUG();
+ return 0;
+}
+
+static void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg,
int nents, enum dma_data_direction direction)
{
#if defined(CONFIG_PS3_DYNAMIC_DMA)
@@ -307,18 +629,34 @@ static void ps3_unmap_sg(struct device *
#endif
}
+static void ps3_ioc0_unmap_sg(struct device *_dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction)
+{
+ BUG();
+}
+
static int ps3_dma_supported(struct device *_dev, u64 mask)
{
return mask >= DMA_32BIT_MASK;
}
-static struct dma_mapping_ops ps3_dma_ops = {
+static struct dma_mapping_ops ps3_sb_dma_ops = {
+ .alloc_coherent = ps3_alloc_coherent,
+ .free_coherent = ps3_free_coherent,
+ .map_single = ps3_sb_map_single,
+ .unmap_single = ps3_unmap_single,
+ .map_sg = ps3_sb_map_sg,
+ .unmap_sg = ps3_sb_unmap_sg,
+ .dma_supported = ps3_dma_supported
+};
+
+static struct dma_mapping_ops ps3_ioc0_dma_ops = {
.alloc_coherent = ps3_alloc_coherent,
.free_coherent = ps3_free_coherent,
- .map_single = ps3_map_single,
+ .map_single = ps3_ioc0_map_single,
.unmap_single = ps3_unmap_single,
- .map_sg = ps3_map_sg,
- .unmap_sg = ps3_unmap_sg,
+ .map_sg = ps3_ioc0_map_sg,
+ .unmap_sg = ps3_ioc0_unmap_sg,
.dma_supported = ps3_dma_supported
};
@@ -328,7 +666,7 @@ static struct dma_mapping_ops ps3_dma_op
static void ps3_system_bus_release_device(struct device *_dev)
{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
kfree(dev);
}
@@ -343,19 +681,38 @@ static void ps3_system_bus_release_devic
int ps3_system_bus_device_register(struct ps3_system_bus_device *dev)
{
int result;
- static unsigned int dev_count = 1;
+ static unsigned int dev_ioc0_count;
+ static unsigned int dev_sb_count;
+ static unsigned int dev_vuart_count;
- dev->core.parent = NULL;
+ if (!dev->core.parent)
+ dev->core.parent = &ps3_system_bus;
dev->core.bus = &ps3_system_bus_type;
dev->core.release = ps3_system_bus_release_device;
+ switch (dev->dev_type) {
+ case PS3_DEVICE_TYPE_IOC0:
+ dev->core.archdata.dma_ops = &ps3_ioc0_dma_ops;
+ snprintf(dev->core.bus_id, sizeof(dev->core.bus_id),
+ "ioc0_%02x", ++dev_ioc0_count);
+ break;
+ case PS3_DEVICE_TYPE_SB:
+ dev->core.archdata.dma_ops = &ps3_sb_dma_ops;
+ snprintf(dev->core.bus_id, sizeof(dev->core.bus_id),
+ "sb_%02x", ++dev_sb_count);
+
+ break;
+ case PS3_DEVICE_TYPE_VUART:
+ snprintf(dev->core.bus_id, sizeof(dev->core.bus_id),
+ "vuart_%02x", ++dev_vuart_count);
+ break;
+ default:
+ BUG();
+ };
+
dev->core.archdata.of_node = NULL;
- dev->core.archdata.dma_ops = &ps3_dma_ops;
dev->core.archdata.numa_node = 0;
- snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x",
- dev_count++);
-
pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id);
result = device_register(&dev->core);
@@ -368,9 +725,11 @@ int ps3_system_bus_driver_register(struc
{
int result;
+ printk(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name);
drv->core.bus = &ps3_system_bus_type;
result = driver_register(&drv->core);
+ printk(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name);
return result;
}
@@ -378,7 +737,9 @@ EXPORT_SYMBOL_GPL(ps3_system_bus_driver_
void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv)
{
+ printk(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name);
driver_unregister(&drv->core);
+ printk(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name);
}
EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister);
--- a/include/asm-powerpc/lv1call.h
+++ b/include/asm-powerpc/lv1call.h
@@ -238,6 +238,7 @@ LV1_CALL(destruct_virtual_address_space,
LV1_CALL(configure_irq_state_bitmap, 3, 0, 11 )
LV1_CALL(connect_irq_plug_ext, 5, 0, 12 )
LV1_CALL(release_memory, 1, 0, 13 )
+LV1_CALL(put_iopte, 5, 0, 15 )
LV1_CALL(disconnect_irq_plug_ext, 3, 0, 17 )
LV1_CALL(construct_event_receive_port, 0, 1, 18 )
LV1_CALL(destruct_event_receive_port, 1, 0, 19 )
@@ -268,6 +269,8 @@ LV1_CALL(remove_repository_node,
LV1_CALL(read_htab_entries, 2, 5, 95 )
LV1_CALL(set_dabr, 2, 0, 96 )
LV1_CALL(get_total_execution_time, 2, 1, 103 )
+LV1_CALL(allocate_io_segment, 3, 1, 116 )
+LV1_CALL(release_io_segment, 2, 0, 117 )
LV1_CALL(construct_io_irq_outlet, 1, 1, 120 )
LV1_CALL(destruct_io_irq_outlet, 1, 0, 121 )
LV1_CALL(map_htab, 1, 1, 122 )
--- a/include/asm-powerpc/ps3.h
+++ b/include/asm-powerpc/ps3.h
@@ -49,18 +49,6 @@ enum ps3_param_av_multi_out {
enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void);
-/**
- * struct ps3_device_id - HV bus device identifier from the system repository
- * @bus_id: HV bus id, {1..} (zero invalid)
- * @dev_id: HV device id, {0..}
- */
-
-struct ps3_device_id {
- unsigned int bus_id;
- unsigned int dev_id;
-};
-
-
/* dma routines */
enum ps3_dma_page_size {
@@ -75,6 +63,8 @@ enum ps3_dma_region_type {
PS3_DMA_INTERNAL = 2,
};
+struct ps3_dma_region_ops;
+
/**
* struct ps3_dma_region - A per device dma state variables structure
* @did: The HV device id.
@@ -82,21 +72,43 @@ enum ps3_dma_region_type {
* @region_type: The HV region type.
* @bus_addr: The 'translated' bus address of the region.
* @len: The length in bytes of the region.
+ * @offset: The offset from the start of memory of the region.
+ * @ioid: The IOID of the device who owns this region
* @chunk_list: Opaque variable used by the ioc page manager.
+ * @region_ops: struct ps3_dma_region_ops - dma region operations
*/
struct ps3_dma_region {
- struct ps3_device_id did;
+ struct ps3_system_bus_device *dev;
+ /* device variables */
+ const struct ps3_dma_region_ops *region_ops;
+ unsigned char ioid;
enum ps3_dma_page_size page_size;
enum ps3_dma_region_type region_type;
- unsigned long bus_addr;
unsigned long len;
+ unsigned long offset;
+ //unsigned long iopte_flag;
+
+ /* driver variables (set by ps3_dma_region_create) */
+ unsigned long bus_addr;
struct {
spinlock_t lock;
struct list_head head;
} chunk_list;
};
+struct ps3_dma_region_ops {
+ int (*create)(struct ps3_dma_region *);
+ int (*free)(struct ps3_dma_region *);
+ int (*map)(struct ps3_dma_region *,
+ unsigned long virt_addr,
+ unsigned long len,
+ unsigned long * bus_addr,
+ u64 iopte_pp);
+ int (*unmap)(struct ps3_dma_region *,
+ unsigned long bus_addr,
+ unsigned long len);
+};
/**
* struct ps3_dma_region_init - Helper to initialize structure variables
*
@@ -104,18 +116,16 @@ struct ps3_dma_region {
* ps3_system_bus_device_register.
*/
-static inline void ps3_dma_region_init(struct ps3_dma_region *r,
- const struct ps3_device_id* did, enum ps3_dma_page_size page_size,
- enum ps3_dma_region_type region_type)
-{
- r->did = *did;
- r->page_size = page_size;
- r->region_type = region_type;
-}
+struct ps3_system_bus_device;
+
+int ps3_dma_region_init(struct ps3_system_bus_device *dev,
+ struct ps3_dma_region *r, enum ps3_dma_page_size page_size,
+ enum ps3_dma_region_type region_type, void *addr, unsigned long len);
int ps3_dma_region_create(struct ps3_dma_region *r);
int ps3_dma_region_free(struct ps3_dma_region *r);
int ps3_dma_map(struct ps3_dma_region *r, unsigned long virt_addr,
- unsigned long len, unsigned long *bus_addr);
+ unsigned long len, unsigned long *bus_addr,
+ u64 iopte_pp);
int ps3_dma_unmap(struct ps3_dma_region *r, unsigned long bus_addr,
unsigned long len);
@@ -126,6 +136,7 @@ enum ps3_mmio_page_size {
PS3_MMIO_64K = 16U
};
+struct ps3_mmio_region_ops;
/**
* struct ps3_mmio_region - a per device mmio state variables structure
*
@@ -133,13 +144,18 @@ enum ps3_mmio_page_size {
*/
struct ps3_mmio_region {
- struct ps3_device_id did;
+ struct ps3_system_bus_device *dev;
+ const struct ps3_mmio_region_ops * mmio_ops;
unsigned long bus_addr;
unsigned long len;
enum ps3_mmio_page_size page_size;
unsigned long lpar_addr;
};
+struct ps3_mmio_region_ops {
+ int (*create)(struct ps3_mmio_region *);
+ int (*free)(struct ps3_mmio_region *);
+};
/**
* struct ps3_mmio_region_init - Helper to initialize structure variables
*
@@ -147,15 +163,9 @@ struct ps3_mmio_region {
* ps3_system_bus_device_register.
*/
-static inline void ps3_mmio_region_init(struct ps3_mmio_region *r,
- const struct ps3_device_id* did, unsigned long bus_addr,
- unsigned long len, enum ps3_mmio_page_size page_size)
-{
- r->did = *did;
- r->bus_addr = bus_addr;
- r->len = len;
- r->page_size = page_size;
-}
+int ps3_mmio_region_init(struct ps3_system_bus_device *dev,
+ struct ps3_mmio_region *r, unsigned long bus_addr, unsigned long len,
+ enum ps3_mmio_page_size page_size);
int ps3_mmio_region_create(struct ps3_mmio_region *r);
int ps3_free_mmio_region(struct ps3_mmio_region *r);
unsigned long ps3_mm_phys_to_lpar(unsigned long phys_addr);
@@ -188,11 +198,10 @@ int ps3_spe_irq_setup(enum ps3_cpu_bindi
unsigned int class, unsigned int *virq);
int ps3_spe_irq_destroy(unsigned int virq);
-int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu,
- const struct ps3_device_id *did, unsigned int interrupt_id,
- unsigned int *virq);
-int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did,
- unsigned int interrupt_id, unsigned int virq);
+int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev,
+ enum ps3_cpu_binding cpu, unsigned int *virq);
+int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev,
+ unsigned int virq);
/* lv1 result codes */
@@ -290,11 +299,33 @@ static inline const char* ps3_result(int
/* system bus routines */
enum ps3_match_id {
- PS3_MATCH_ID_EHCI = 1,
- PS3_MATCH_ID_OHCI,
- PS3_MATCH_ID_GELIC,
- PS3_MATCH_ID_AV_SETTINGS,
- PS3_MATCH_ID_SYSTEM_MANAGER,
+ PS3_MATCH_ID_EHCI = 1,
+ PS3_MATCH_ID_OHCI = 2,
+ PS3_MATCH_ID_GELIC = 3,
+ PS3_MATCH_ID_AV_SETTINGS = 4,
+ PS3_MATCH_ID_SYSTEM_MANAGER = 5,
+ PS3_MATCH_ID_STOR_DISK = 6,
+ PS3_MATCH_ID_STOR_ROM = 7,
+ PS3_MATCH_ID_STOR_FLASH = 8,
+ PS3_MATCH_ID_SOUND = 9,
+ PS3_MATCH_ID_GRAPHICS = 10,
+};
+
+#define PS3_MODULE_ALIAS_EHCI "ps3:1"
+#define PS3_MODULE_ALIAS_OHCI "ps3:2"
+#define PS3_MODULE_ALIAS_GELIC "ps3:3"
+#define PS3_MODULE_ALIAS_AV_SETTINGS "ps3:4"
+#define PS3_MODULE_ALIAS_SYSTEM_MANAGER "ps3:5"
+#define PS3_MODULE_ALIAS_STOR_DISK "ps3:6"
+#define PS3_MODULE_ALIAS_STOR_ROM "ps3:7"
+#define PS3_MODULE_ALIAS_STOR_FLASH "ps3:8"
+#define PS3_MODULE_ALIAS_SOUND "ps3:9"
+#define PS3_MODULE_ALIAS_GRAPHICS "ps3:10"
+
+enum ps3_system_bus_device_type {
+ PS3_DEVICE_TYPE_IOC0 = 1,
+ PS3_DEVICE_TYPE_SB,
+ PS3_DEVICE_TYPE_VUART,
};
/**
@@ -303,14 +334,23 @@ enum ps3_match_id {
struct ps3_system_bus_device {
enum ps3_match_id match_id;
- struct ps3_device_id did;
- unsigned int interrupt_id;
-/* struct iommu_table *iommu_table; -- waiting for Ben's cleanups */
- struct ps3_dma_region *d_region;
- struct ps3_mmio_region *m_region;
+ enum ps3_system_bus_device_type dev_type;
+
+ unsigned int bus_id; /* SB */
+ unsigned int dev_id; /* SB */
+ unsigned int interrupt_id; /* SB */
+ struct ps3_dma_region *d_region; /* SB, IOC0 */
+ struct ps3_mmio_region *m_region; /* SB, IOC0*/
+ unsigned int port_number; /* VUART */
+
+/* struct iommu_table *iommu_table; -- waiting for BenH's cleanups */
struct device core;
+ void* driver_priv; /* private driver variables */
};
+int ps3_open_hv_device(struct ps3_system_bus_device *dev);
+int ps3_close_hv_device(struct ps3_system_bus_device *dev);
+
/**
* struct ps3_system_bus_driver - a driver for a device on the system bus
*/
@@ -320,6 +361,7 @@ struct ps3_system_bus_driver {
struct device_driver core;
int (*probe)(struct ps3_system_bus_device *);
int (*remove)(struct ps3_system_bus_device *);
+ int (*shutdown)(struct ps3_system_bus_device *);
/* int (*suspend)(struct ps3_system_bus_device *, pm_message_t); */
/* int (*resume)(struct ps3_system_bus_device *); */
};
@@ -327,16 +369,24 @@ struct ps3_system_bus_driver {
int ps3_system_bus_device_register(struct ps3_system_bus_device *dev);
int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv);
void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv);
-static inline struct ps3_system_bus_driver *to_ps3_system_bus_driver(
+
+static inline struct ps3_system_bus_driver *ps3_drv_to_system_bus_drv(
struct device_driver *_drv)
{
return container_of(_drv, struct ps3_system_bus_driver, core);
}
-static inline struct ps3_system_bus_device *to_ps3_system_bus_device(
+static inline struct ps3_system_bus_device *ps3_dev_to_system_bus_dev(
struct device *_dev)
{
return container_of(_dev, struct ps3_system_bus_device, core);
}
+static inline struct ps3_system_bus_driver *
+ ps3_system_bus_dev_to_system_bus_drv(struct ps3_system_bus_device *_dev)
+{
+ BUG_ON(!_dev);
+ BUG_ON(!_dev->core.driver);
+ return ps3_drv_to_system_bus_drv(_dev->core.driver);
+}
/**
* ps3_system_bus_set_drvdata -
--
next prev parent reply other threads:[~2007-06-06 3:06 UTC|newest]
Thread overview: 60+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20070606024407.786638029@am.sony.com>
2007-06-06 2:59 ` [patch 01/18] Cell: Add spu shutdown method Geoff Levand
2007-06-06 4:08 ` Michael Ellerman
2007-06-06 14:41 ` André Detsch
2007-06-06 2:59 ` [patch 02/18] PS3: Rename IPI symbols Geoff Levand
2007-06-06 3:11 ` Stephen Rothwell
2007-06-06 14:48 ` Will Schmidt
2007-06-06 20:47 ` Geoff Levand
2007-06-06 20:49 ` Geoff Levand
2007-06-06 2:59 ` [patch 03/18] PS3: Use __maybe_unused Geoff Levand
2007-06-06 4:05 ` Michael Ellerman
2007-06-06 22:37 ` Geoff Levand
2007-06-06 2:59 ` [patch 04/18] PS3: Compare firmware version Geoff Levand
2007-06-06 2:59 ` [patch 05/18] PS3: Fix sparse warnings Geoff Levand
2007-06-06 14:21 ` Arnd Bergmann
2007-06-07 14:34 ` Geoff Levand
2007-06-08 5:59 ` Takao Shinohara
2007-06-06 2:59 ` [patch 06/18] PS3: Add support for HDMI RGB Full Range mode Geoff Levand
2007-06-06 3:00 ` [patch 07/18] PS3: Make ps3av.h usable from user space Geoff Levand
2007-06-06 7:46 ` Christoph Hellwig
2007-06-06 11:27 ` Geert Uytterhoeven
2007-06-06 16:44 ` Geoff Levand
2007-06-07 19:15 ` Christoph Hellwig
2007-06-06 3:00 ` [patch 08/18] PS3: Kexec support Geoff Levand
2007-06-06 4:01 ` Michael Ellerman
2007-06-06 21:55 ` Geoff Levand
2007-06-07 1:25 ` Stephen Rothwell
2007-06-07 1:33 ` Geoff Levand
2007-06-07 2:48 ` Stephen Rothwell
2007-06-07 2:31 ` Michael Ellerman
2007-06-07 2:54 ` Benjamin Herrenschmidt
2007-06-10 0:13 ` Geoff Levand
2007-06-09 8:17 ` [patch 08/18] PS3: Kexec support (and a tutoral on the kexec flow for 64 bit powerpc) Milton Miller
2007-06-09 22:47 ` Geoff Levand
2007-06-06 3:00 ` Geoff Levand [this message]
2007-06-06 6:43 ` [patch 09/18] PS3: System-bus rework Geert Uytterhoeven
2007-06-11 7:07 ` Milton Miller
2007-06-11 15:39 ` Geoff Levand
2007-06-11 15:45 ` Geert Uytterhoeven
2007-06-06 3:00 ` [patch 10/18] PS3: System-bus uevent Geoff Levand
2007-06-06 3:00 ` [patch 11/18] PS3: System-bus modinfo attribute Geoff Levand
2007-06-06 3:17 ` Stephen Rothwell
2007-06-06 3:00 ` [patch 12/18] PS3: Repository probe cleanups Geoff Levand
2007-06-06 3:01 ` [patch 13/18] PS3: USB system-bus rework Geoff Levand
2007-06-06 3:01 ` [patch 14/18] PS3: Vuart rework Geoff Levand
2007-06-06 3:01 ` [patch 15/18] PS3: System manager re-work Geoff Levand
2007-06-06 6:51 ` Geert Uytterhoeven
2007-06-06 3:01 ` [patch 16/18] PS3: Rework AV settings driver Geoff Levand
2007-06-06 6:49 ` Geert Uytterhoeven
2007-06-06 3:01 ` [patch 17/18] PS3: Frame buffer system-bus rework Geoff Levand
2007-06-06 6:51 ` Geert Uytterhoeven
2007-06-06 6:51 ` Geert Uytterhoeven
2007-06-06 15:56 ` [Linux-fbdev-devel] " Antonino A. Daplas
2007-06-06 23:08 ` Geoff Levand
2007-06-06 23:37 ` Antonino A. Daplas
2007-06-06 3:01 ` [patch 18/18] PS3: Device registration routines Geoff Levand
2007-06-06 6:57 ` Geert Uytterhoeven
2007-06-06 12:21 ` Geert Uytterhoeven
2007-06-06 3:04 ` [patch 13/18] PS3: USB system-bus rework Geoff Levand
2007-06-08 23:22 ` [patch] PS3: Fix USB return value Geoff Levand
2007-06-25 7:30 ` Greg KH
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4666234B.2020208@am.sony.com \
--to=geoffrey.levand@am.sony.com \
--cc=Geert.Uytterhoeven@sonycom.com \
--cc=linuxppc-dev@ozlabs.org \
--cc=paulus@samba.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.