From 6bb5cf1025414fe00b20f3bef56135849e4ed3b8 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 07:52:02 +1000 Subject: [POWERPC] PS3: System-bus rework 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 drivers. - Added loadable module support to all drivers. - Added HV calls for iopte management (needed by sound driver). Signed-off-by: MOKUNO Masakazu Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- include/asm-powerpc/lv1call.h | 3 + include/asm-powerpc/ps3.h | 148 ++++++++++++++++++++++++++++-------------- 2 files changed, 101 insertions(+), 50 deletions(-) (limited to 'include/asm-powerpc') diff --git a/include/asm-powerpc/lv1call.h b/include/asm-powerpc/lv1call.h index f733beeea63..81713acf752 100644 --- a/include/asm-powerpc/lv1call.h +++ b/include/asm-powerpc/lv1call.h @@ -238,6 +238,7 @@ LV1_CALL(destruct_virtual_address_space, 1, 0, 10 ) 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, 4, 0, 93 ) 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 ) diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h index ac85d729f14..4f753907bbf 100644 --- 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,42 @@ 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; + + /* 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 +115,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 +135,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 +143,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 +162,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 +197,10 @@ int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id, 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 +298,33 @@ static inline const char* ps3_result(int result) /* 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 +333,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 +359,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 +367,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 - -- cgit v1.2.3