Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc

* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (38 commits)
  ps3flash: Always read chunks of 256 KiB, and cache them
  ps3flash: Cache the last accessed FLASH chunk
  ps3: Replace direct file operations by callback
  ps3: Switch ps3_os_area_[gs]et_rtc_diff to EXPORT_SYMBOL_GPL()
  ps3: Correct debug message in dma_ioc0_map_pages()
  drivers/ps3: Add missing annotations
  ps3fb: Use ps3_system_bus_[gs]et_drvdata() instead of direct access
  ps3flash: Use ps3_system_bus_[gs]et_drvdata() instead of direct access
  ps3: shorten ps3_system_bus_[gs]et_driver_data to ps3_system_bus_[gs]et_drvdata
  ps3: Use dev_[gs]et_drvdata() instead of direct access for system bus devices
  block/ps3: remove driver_data direct access of struct device
  ps3vram: Make ps3vram_priv.reports a void *
  ps3vram: Remove no longer used ps3vram_priv.ddr_base
  ps3vram: Replace mutex by spinlock + bio_list
  block: Add bio_list_peek()
  powerpc: Use generic atomic64_t implementation on 32-bit processors
  lib: Provide generic atomic64_t implementation
  powerpc: Add compiler memory barrier to mtmsr macro
  powerpc/iseries: Mark signal_vsp_instruction() as maybe unused
  powerpc/iseries: Fix unused function warning in iSeries DT code
  ...
This commit is contained in:
Linus Torvalds 2009-06-16 11:30:37 -07:00
commit 609106b9ac
37 changed files with 914 additions and 568 deletions

View File

@ -93,10 +93,6 @@ config GENERIC_HWEIGHT
bool
default y
config GENERIC_CALIBRATE_DELAY
bool
default y
config GENERIC_FIND_NEXT_BIT
bool
default y
@ -129,6 +125,7 @@ config PPC
select USE_GENERIC_SMP_HELPERS if SMP
select HAVE_OPROFILE
select HAVE_SYSCALL_WRAPPERS if PPC64
select GENERIC_ATOMIC64 if PPC32
config EARLY_PRINTK
bool

View File

@ -18,6 +18,9 @@
# $5 and more - kernel boot files; zImage*, uImage, cuImage.*, etc.
#
# Bail with error code if anything goes wrong
set -e
# User may have a custom install script
if [ -x ~/bin/${CROSS_COMPILE}installkernel ]; then exec ~/bin/${CROSS_COMPILE}installkernel "$@"; fi

View File

@ -470,6 +470,9 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
#else /* __powerpc64__ */
#include <asm-generic/atomic64.h>
#endif /* __powerpc64__ */
#include <asm-generic/atomic-long.h>

View File

@ -80,7 +80,7 @@ static inline void local_irq_disable(void)
__asm__ __volatile__("wrteei 0": : :"memory");
#else
unsigned long msr;
__asm__ __volatile__("": : :"memory");
msr = mfmsr();
SET_MSR_EE(msr & ~MSR_EE);
#endif
@ -92,7 +92,7 @@ static inline void local_irq_enable(void)
__asm__ __volatile__("wrteei 1": : :"memory");
#else
unsigned long msr;
__asm__ __volatile__("": : :"memory");
msr = mfmsr();
SET_MSR_EE(msr | MSR_EE);
#endif
@ -108,7 +108,6 @@ static inline void local_irq_save_ptr(unsigned long *flags)
#else
SET_MSR_EE(msr & ~MSR_EE);
#endif
__asm__ __volatile__("": : :"memory");
}
#define local_save_flags(flags) ((flags) = mfmsr())

View File

@ -35,6 +35,16 @@
#define IOMMU_PAGE_MASK (~((1 << IOMMU_PAGE_SHIFT) - 1))
#define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE)
/* Cell page table entries */
#define CBE_IOPTE_PP_W 0x8000000000000000ul /* protection: write */
#define CBE_IOPTE_PP_R 0x4000000000000000ul /* protection: read */
#define CBE_IOPTE_M 0x2000000000000000ul /* coherency required */
#define CBE_IOPTE_SO_R 0x1000000000000000ul /* ordering: writes */
#define CBE_IOPTE_SO_RW 0x1800000000000000ul /* ordering: r & w */
#define CBE_IOPTE_RPN_Mask 0x07fffffffffff000ul /* RPN */
#define CBE_IOPTE_H 0x0000000000000800ul /* cache hint */
#define CBE_IOPTE_IOID_Mask 0x00000000000007fful /* ioid */
/* Boot time flags */
extern int iommu_is_off;
extern int iommu_force_on;

View File

@ -53,6 +53,13 @@ enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void);
extern u64 ps3_os_area_get_rtc_diff(void);
extern void ps3_os_area_set_rtc_diff(u64 rtc_diff);
struct ps3_os_area_flash_ops {
ssize_t (*read)(void *buf, size_t count, loff_t pos);
ssize_t (*write)(const void *buf, size_t count, loff_t pos);
};
extern void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops);
/* dma routines */
enum ps3_dma_page_size {
@ -418,15 +425,15 @@ static inline struct ps3_system_bus_driver *
* @data: Data to set
*/
static inline void ps3_system_bus_set_driver_data(
static inline void ps3_system_bus_set_drvdata(
struct ps3_system_bus_device *dev, void *data)
{
dev->core.driver_data = data;
dev_set_drvdata(&dev->core, data);
}
static inline void *ps3_system_bus_get_driver_data(
static inline void *ps3_system_bus_get_drvdata(
struct ps3_system_bus_device *dev)
{
return dev->core.driver_data;
return dev_get_drvdata(&dev->core);
}
/* These two need global scope for get_dma_ops(). */
@ -520,7 +527,4 @@ void ps3_sync_irq(int node);
u32 ps3_get_hw_thread_id(int cpu);
u64 ps3_get_spe_id(void *arg);
/* mutex synchronizing GPU accesses and video mode changes */
extern struct mutex ps3_gpu_mutex;
#endif

View File

@ -0,0 +1,86 @@
/*
* PS3 GPU declarations.
*
* Copyright 2009 Sony Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _ASM_POWERPC_PS3GPU_H
#define _ASM_POWERPC_PS3GPU_H
#include <linux/mutex.h>
#include <asm/lv1call.h>
#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101
#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102
#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600
#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601
#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC 0x602
#define L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE 0x603
#define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION (1ULL << 32)
#define L1GPU_DISPLAY_SYNC_HSYNC 1
#define L1GPU_DISPLAY_SYNC_VSYNC 2
/* mutex synchronizing GPU accesses and video mode changes */
extern struct mutex ps3_gpu_mutex;
static inline int lv1_gpu_display_sync(u64 context_handle, u64 head,
u64 ddr_offset)
{
return lv1_gpu_context_attribute(context_handle,
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
head, ddr_offset, 0, 0);
}
static inline int lv1_gpu_display_flip(u64 context_handle, u64 head,
u64 ddr_offset)
{
return lv1_gpu_context_attribute(context_handle,
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
head, ddr_offset, 0, 0);
}
static inline int lv1_gpu_fb_setup(u64 context_handle, u64 xdr_lpar,
u64 xdr_size, u64 ioif_offset)
{
return lv1_gpu_context_attribute(context_handle,
L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
xdr_lpar, xdr_size, ioif_offset, 0);
}
static inline int lv1_gpu_fb_blit(u64 context_handle, u64 ddr_offset,
u64 ioif_offset, u64 sync_width, u64 pitch)
{
return lv1_gpu_context_attribute(context_handle,
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
ddr_offset, ioif_offset, sync_width,
pitch);
}
static inline int lv1_gpu_fb_close(u64 context_handle)
{
return lv1_gpu_context_attribute(context_handle,
L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE, 0,
0, 0, 0);
}
#endif /* _ASM_POWERPC_PS3GPU_H */

View File

@ -745,11 +745,11 @@
asm volatile("mfmsr %0" : "=r" (rval)); rval;})
#ifdef CONFIG_PPC64
#define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \
: : "r" (v))
: : "r" (v) : "memory")
#define mtmsrd(v) __mtmsrd((v), 0)
#define mtmsr(v) mtmsrd(v)
#else
#define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v))
#define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v) : "memory")
#endif
#define mfspr(rn) ({unsigned long rval; \

View File

@ -325,3 +325,4 @@ SYSCALL(inotify_init1)
SYSCALL_SPU(perf_counter_open)
COMPAT_SYS_SPU(preadv)
COMPAT_SYS_SPU(pwritev)
COMPAT_SYS(rt_tgsigqueueinfo)

View File

@ -344,10 +344,11 @@
#define __NR_perf_counter_open 319
#define __NR_preadv 320
#define __NR_pwritev 321
#define __NR_rt_tgsigqueueinfo 322
#ifdef __KERNEL__
#define __NR_syscalls 322
#define __NR_syscalls 323
#define __NR__exit __NR_exit
#define NR_syscalls __NR_syscalls

View File

@ -125,6 +125,7 @@ PHONY += systbl_chk
systbl_chk: $(src)/systbl_chk.sh $(obj)/systbl_chk.i
$(call cmd,systbl_chk)
ifeq ($(CONFIG_PPC_OF_BOOT_TRAMPOLINE),y)
$(obj)/built-in.o: prom_init_check
quiet_cmd_prom_init_check = CALL $<
@ -133,5 +134,6 @@ quiet_cmd_prom_init_check = CALL $<
PHONY += prom_init_check
prom_init_check: $(src)/prom_init_check.sh $(obj)/prom_init.o
$(call cmd,prom_init_check)
endif
clean-files := vmlinux.lds

View File

@ -424,8 +424,8 @@ void __init setup_system(void)
printk("htab_hash_mask = 0x%lx\n", htab_hash_mask);
#endif /* CONFIG_PPC_STD_MMU_64 */
if (PHYSICAL_START > 0)
printk("physical_start = 0x%lx\n",
PHYSICAL_START);
printk("physical_start = 0x%llx\n",
(unsigned long long)PHYSICAL_START);
printk("-----------------------------------------------------\n");
DBG(" <- setup_system()\n");

View File

@ -52,6 +52,7 @@
#include <linux/jiffies.h>
#include <linux/posix-timers.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/processor.h>
@ -1143,6 +1144,15 @@ void div128_by_32(u64 dividend_high, u64 dividend_low,
}
/* We don't need to calibrate delay, we use the CPU timebase for that */
void calibrate_delay(void)
{
/* Some generic code (such as spinlock debug) use loops_per_jiffy
* as the number of __delay(1) in a jiffy, so make it so
*/
loops_per_jiffy = tb_ticks_per_jiffy;
}
static int __init rtc_init(void)
{
struct platform_device *pdev;

View File

@ -329,7 +329,7 @@ static struct irq_host_ops msic_host_ops = {
static int axon_msi_shutdown(struct of_device *device)
{
struct axon_msic *msic = device->dev.platform_data;
struct axon_msic *msic = dev_get_drvdata(&device->dev);
u32 tmp;
pr_debug("axon_msi: disabling %s\n",
@ -416,7 +416,7 @@ static int axon_msi_probe(struct of_device *device,
msic->read_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG)
& MSIC_FIFO_SIZE_MASK;
device->dev.platform_data = msic;
dev_set_drvdata(&device->dev, msic);
ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;

View File

@ -100,16 +100,6 @@
#define IOSTE_PS_1M 0x0000000000000005ul /* - 1MB */
#define IOSTE_PS_16M 0x0000000000000007ul /* - 16MB */
/* 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 */
/* IOMMU sizing */
#define IO_SEGMENT_SHIFT 28
@ -193,19 +183,21 @@ static int tce_build_cell(struct iommu_table *tbl, long index, long npages,
*/
const unsigned long prot = 0xc48;
base_pte =
((prot << (52 + 4 * direction)) & (IOPTE_PP_W | IOPTE_PP_R))
| IOPTE_M | IOPTE_SO_RW | (window->ioid & IOPTE_IOID_Mask);
((prot << (52 + 4 * direction)) &
(CBE_IOPTE_PP_W | CBE_IOPTE_PP_R)) |
CBE_IOPTE_M | CBE_IOPTE_SO_RW |
(window->ioid & CBE_IOPTE_IOID_Mask);
#else
base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW |
(window->ioid & IOPTE_IOID_Mask);
base_pte = CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_M |
CBE_IOPTE_SO_RW | (window->ioid & CBE_IOPTE_IOID_Mask);
#endif
if (unlikely(dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)))
base_pte &= ~IOPTE_SO_RW;
base_pte &= ~CBE_IOPTE_SO_RW;
io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
for (i = 0; i < npages; i++, uaddr += IOMMU_PAGE_SIZE)
io_pte[i] = base_pte | (__pa(uaddr) & IOPTE_RPN_Mask);
io_pte[i] = base_pte | (__pa(uaddr) & CBE_IOPTE_RPN_Mask);
mb();
@ -231,8 +223,9 @@ static void tce_free_cell(struct iommu_table *tbl, long index, long npages)
#else
/* spider bridge does PCI reads after freeing - insert a mapping
* to a scratch page instead of an invalid entry */
pte = IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | __pa(window->iommu->pad_page)
| (window->ioid & IOPTE_IOID_Mask);
pte = CBE_IOPTE_PP_R | CBE_IOPTE_M | CBE_IOPTE_SO_RW |
__pa(window->iommu->pad_page) |
(window->ioid & CBE_IOPTE_IOID_Mask);
#endif
io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
@ -1001,7 +994,7 @@ static void insert_16M_pte(unsigned long addr, unsigned long *ptab,
pr_debug("iommu: addr %lx ptab %p segment %lx offset %lx\n",
addr, ptab, segment, offset);
ptab[offset] = base_pte | (__pa(addr) & IOPTE_RPN_Mask);
ptab[offset] = base_pte | (__pa(addr) & CBE_IOPTE_RPN_Mask);
}
static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu,
@ -1016,14 +1009,14 @@ static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu,
pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase);
base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M
| (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask);
base_pte = CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_M |
(cell_iommu_get_ioid(np) & CBE_IOPTE_IOID_Mask);
if (iommu_fixed_is_weak)
pr_info("IOMMU: Using weak ordering for fixed mapping\n");
else {
pr_info("IOMMU: Using strong ordering for fixed mapping\n");
base_pte |= IOPTE_SO_RW;
base_pte |= CBE_IOPTE_SO_RW;
}
for (uaddr = 0; uaddr < fsize; uaddr += (1 << 24)) {

View File

@ -204,7 +204,8 @@ static void __init dt_prop_u32(struct iseries_flat_dt *dt, const char *name,
dt_prop(dt, name, &data, sizeof(u32));
}
static void __init dt_prop_u64(struct iseries_flat_dt *dt, const char *name,
static void __init __maybe_unused dt_prop_u64(struct iseries_flat_dt *dt,
const char *name,
u64 data)
{
dt_prop(dt, name, &data, sizeof(u64));

View File

@ -267,7 +267,8 @@ static struct pending_event *new_pending_event(void)
return ev;
}
static int signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)
static int __maybe_unused
signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)
{
struct pending_event *ev = new_pending_event();
int rc;

View File

@ -24,6 +24,7 @@
#include <linux/lmb.h>
#include <asm/firmware.h>
#include <asm/iommu.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/lv1call.h>
@ -605,9 +606,8 @@ static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
r->ioid,
iopte_flag);
if (result) {
printk(KERN_WARNING "%s:%d: lv1_map_device_dma_region "
"failed: %s\n", __func__, __LINE__,
ps3_result(result));
pr_warning("%s:%d: lv1_put_iopte failed: %s\n",
__func__, __LINE__, ps3_result(result));
goto fail_map;
}
DBG("%s: pg=%d bus=%#lx, lpar=%#lx, ioid=%#x\n", __func__,
@ -1001,7 +1001,8 @@ static int dma_sb_region_create_linear(struct ps3_dma_region *r)
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);
CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_SO_RW |
CBE_IOPTE_M);
BUG_ON(result);
}
@ -1014,7 +1015,8 @@ static int dma_sb_region_create_linear(struct ps3_dma_region *r)
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);
CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_SO_RW |
CBE_IOPTE_M);
BUG_ON(result);
}

View File

@ -226,6 +226,44 @@ static struct property property_av_multi_out = {
.value = &saved_params.av_multi_out,
};
static DEFINE_MUTEX(os_area_flash_mutex);
static const struct ps3_os_area_flash_ops *os_area_flash_ops;
void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops)
{
mutex_lock(&os_area_flash_mutex);
os_area_flash_ops = ops;
mutex_unlock(&os_area_flash_mutex);
}
EXPORT_SYMBOL_GPL(ps3_os_area_flash_register);
static ssize_t os_area_flash_read(void *buf, size_t count, loff_t pos)
{
ssize_t res = -ENODEV;
mutex_lock(&os_area_flash_mutex);
if (os_area_flash_ops)
res = os_area_flash_ops->read(buf, count, pos);
mutex_unlock(&os_area_flash_mutex);
return res;
}
static ssize_t os_area_flash_write(const void *buf, size_t count, loff_t pos)
{
ssize_t res = -ENODEV;
mutex_lock(&os_area_flash_mutex);
if (os_area_flash_ops)
res = os_area_flash_ops->write(buf, count, pos);
mutex_unlock(&os_area_flash_mutex);
return res;
}
/**
* os_area_set_property - Add or overwrite a saved_params value to the device tree.
*
@ -352,12 +390,12 @@ static int db_verify(const struct os_area_db *db)
if (memcmp(db->magic_num, OS_AREA_DB_MAGIC_NUM,
sizeof(db->magic_num))) {
pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
return -1;
return -EINVAL;
}
if (db->version != 1) {
pr_debug("%s:%d version failed\n", __func__, __LINE__);
return -1;
return -EINVAL;
}
return 0;
@ -578,59 +616,48 @@ static void os_area_db_init(struct os_area_db *db)
*
*/
static void __maybe_unused update_flash_db(void)
static int update_flash_db(void)
{
int result;
int file;
off_t offset;
const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
struct os_area_header *header;
ssize_t count;
static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
const struct os_area_header *header;
int error;
loff_t pos;
struct os_area_db* db;
/* Read in header and db from flash. */
file = sys_open("/dev/ps3flash", O_RDWR, 0);
if (file < 0) {
pr_debug("%s:%d sys_open failed\n", __func__, __LINE__);
goto fail_open;
}
header = kmalloc(buf_len, GFP_KERNEL);
if (!header) {
pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__);
goto fail_malloc;
pr_debug("%s: kmalloc failed\n", __func__);
return -ENOMEM;
}
offset = sys_lseek(file, 0, SEEK_SET);
if (offset != 0) {
pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
goto fail_header_seek;
count = os_area_flash_read(header, buf_len, 0);
if (count < 0) {
pr_debug("%s: os_area_flash_read failed %zd\n", __func__,
count);
error = count;
goto fail;
}
count = sys_read(file, (char __user *)header, buf_len);
result = count < OS_AREA_SEGMENT_SIZE || verify_header(header)
|| count < header->db_area_offset * OS_AREA_SEGMENT_SIZE;
if (result) {
pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
pos = header->db_area_offset * OS_AREA_SEGMENT_SIZE;
if (count < OS_AREA_SEGMENT_SIZE || verify_header(header) ||
count < pos) {
pr_debug("%s: verify_header failed\n", __func__);
dump_header(header);
goto fail_header;
error = -EINVAL;
goto fail;
}
/* Now got a good db offset and some maybe good db data. */
db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE;
db = (void *)header + pos;
result = db_verify(db);
if (result) {
printk(KERN_NOTICE "%s:%d: Verify of flash database failed, "
"formatting.\n", __func__, __LINE__);
error = db_verify(db);
if (error) {
pr_notice("%s: Verify of flash database failed, formatting.\n",
__func__);
dump_db(db);
os_area_db_init(db);
}
@ -639,29 +666,16 @@ static void __maybe_unused update_flash_db(void)
db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff);
offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE,
SEEK_SET);
if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) {
pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
goto fail_db_seek;
}
count = sys_write(file, (const char __user *)db,
sizeof(struct os_area_db));
count = os_area_flash_write(db, sizeof(struct os_area_db), pos);
if (count < sizeof(struct os_area_db)) {
pr_debug("%s:%d sys_write failed\n", __func__, __LINE__);
pr_debug("%s: os_area_flash_write failed %zd\n", __func__,
count);
error = count < 0 ? count : -EIO;
}
fail_db_seek:
fail_header:
fail_header_seek:
fail:
kfree(header);
fail_malloc:
sys_close(file);
fail_open:
return;
return error;
}
/**
@ -674,11 +688,11 @@ fail_open:
static void os_area_queue_work_handler(struct work_struct *work)
{
struct device_node *node;
int error;
pr_debug(" -> %s:%d\n", __func__, __LINE__);
node = of_find_node_by_path("/");
if (node) {
os_area_set_property(node, &property_rtc_diff);
of_node_put(node);
@ -686,12 +700,10 @@ static void os_area_queue_work_handler(struct work_struct *work)
pr_debug("%s:%d of_find_node_by_path failed\n",
__func__, __LINE__);
#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
update_flash_db();
#else
printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n",
__func__, __LINE__);
#endif
error = update_flash_db();
if (error)
pr_warning("%s: Could not update FLASH ROM\n", __func__);
pr_debug(" <- %s:%d\n", __func__, __LINE__);
}
@ -808,7 +820,7 @@ u64 ps3_os_area_get_rtc_diff(void)
{
return saved_params.rtc_diff;
}
EXPORT_SYMBOL(ps3_os_area_get_rtc_diff);
EXPORT_SYMBOL_GPL(ps3_os_area_get_rtc_diff);
/**
* ps3_os_area_set_rtc_diff - Set the rtc diff value.
@ -824,7 +836,7 @@ void ps3_os_area_set_rtc_diff(u64 rtc_diff)
os_area_queue_work();
}
}
EXPORT_SYMBOL(ps3_os_area_set_rtc_diff);
EXPORT_SYMBOL_GPL(ps3_os_area_set_rtc_diff);
/**
* ps3_os_area_get_av_multi_out - Returns the default video mode.

View File

@ -232,14 +232,4 @@ int ps3_repository_read_spu_resource_id(unsigned int res_index,
int ps3_repository_read_vuart_av_port(unsigned int *port);
int ps3_repository_read_vuart_sysmgr_port(unsigned int *port);
/* 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

View File

@ -32,6 +32,7 @@
#include <asm/udbg.h>
#include <asm/prom.h>
#include <asm/lv1call.h>
#include <asm/ps3gpu.h>
#include "platform.h"

View File

@ -27,6 +27,7 @@
#include <asm/udbg.h>
#include <asm/lv1call.h>
#include <asm/firmware.h>
#include <asm/iommu.h>
#include "platform.h"
@ -531,7 +532,8 @@ static void * ps3_alloc_coherent(struct device *_dev, size_t size,
}
result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle,
IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
CBE_IOPTE_PP_W | CBE_IOPTE_PP_R |
CBE_IOPTE_SO_RW | CBE_IOPTE_M);
if (result) {
pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
@ -575,7 +577,8 @@ static dma_addr_t ps3_sb_map_page(struct device *_dev, struct page *page,
result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
&bus_addr,
IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW | IOPTE_M);
CBE_IOPTE_PP_R | CBE_IOPTE_PP_W |
CBE_IOPTE_SO_RW | CBE_IOPTE_M);
if (result) {
pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
@ -596,16 +599,16 @@ static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page,
u64 iopte_flag;
void *ptr = page_address(page) + offset;
iopte_flag = IOPTE_M;
iopte_flag = CBE_IOPTE_M;
switch (direction) {
case DMA_BIDIRECTIONAL:
iopte_flag |= IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW;
iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW;
break;
case DMA_TO_DEVICE:
iopte_flag |= IOPTE_PP_R | IOPTE_SO_R;
iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_SO_R;
break;
case DMA_FROM_DEVICE:
iopte_flag |= IOPTE_PP_W | IOPTE_SO_RW;
iopte_flag |= CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW;
break;
default:
/* not happned */

View File

@ -120,7 +120,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
struct request *req)
{
struct ps3disk_private *priv = dev->sbd.core.driver_data;
struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
int write = rq_data_dir(req), res;
const char *op = write ? "write" : "read";
u64 start_sector, sectors;
@ -168,7 +168,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
struct request *req)
{
struct ps3disk_private *priv = dev->sbd.core.driver_data;
struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
u64 res;
dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__);
@ -213,7 +213,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev,
static void ps3disk_request(struct request_queue *q)
{
struct ps3_storage_device *dev = q->queuedata;
struct ps3disk_private *priv = dev->sbd.core.driver_data;
struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
if (priv->req) {
dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__);
@ -245,7 +245,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
priv = dev->sbd.core.driver_data;
priv = ps3_system_bus_get_drvdata(&dev->sbd);
req = priv->req;
if (!req) {
dev_dbg(&dev->sbd.core,
@ -364,7 +364,7 @@ static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs,
static int ps3disk_identify(struct ps3_storage_device *dev)
{
struct ps3disk_private *priv = dev->sbd.core.driver_data;
struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
struct lv1_ata_cmnd_block ata_cmnd;
u16 *id = dev->bounce_buf;
u64 res;
@ -445,7 +445,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
goto fail;
}
dev->sbd.core.driver_data = priv;
ps3_system_bus_set_drvdata(_dev, priv);
spin_lock_init(&priv->lock);
dev->bounce_size = BOUNCE_SIZE;
@ -523,7 +523,7 @@ fail_free_bounce:
kfree(dev->bounce_buf);
fail_free_priv:
kfree(priv);
dev->sbd.core.driver_data = NULL;
ps3_system_bus_set_drvdata(_dev, NULL);
fail:
mutex_lock(&ps3disk_mask_mutex);
__clear_bit(devidx, &ps3disk_mask);
@ -534,7 +534,7 @@ fail:
static int ps3disk_remove(struct ps3_system_bus_device *_dev)
{
struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
struct ps3disk_private *priv = dev->sbd.core.driver_data;
struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
mutex_lock(&ps3disk_mask_mutex);
__clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS,
@ -548,7 +548,7 @@ static int ps3disk_remove(struct ps3_system_bus_device *_dev)
ps3stor_teardown(dev);
kfree(dev->bounce_buf);
kfree(priv);
dev->sbd.core.driver_data = NULL;
ps3_system_bus_set_drvdata(_dev, NULL);
return 0;
}

View File

@ -14,8 +14,10 @@
#include <linux/seq_file.h>
#include <asm/firmware.h>
#include <asm/iommu.h>
#include <asm/lv1call.h>
#include <asm/ps3.h>
#include <asm/ps3gpu.h>
#define DEVICE_NAME "ps3vram"
@ -45,8 +47,6 @@
#define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c
#define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104
#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601
#define CACHE_PAGE_PRESENT 1
#define CACHE_PAGE_DIRTY 2
@ -72,8 +72,7 @@ struct ps3vram_priv {
u64 memory_handle;
u64 context_handle;
u32 *ctrl;
u32 *reports;
u8 __iomem *ddr_base;
void *reports;
u8 *xdr_buf;
u32 *fifo_base;
@ -81,8 +80,8 @@ struct ps3vram_priv {
struct ps3vram_cache cache;
/* Used to serialize cache/DMA operations */
struct mutex lock;
spinlock_t lock; /* protecting list of bios */
struct bio_list list;
};
@ -103,15 +102,15 @@ static char *size = "256M";
module_param(size, charp, 0);
MODULE_PARM_DESC(size, "memory size");
static u32 *ps3vram_get_notifier(u32 *reports, int notifier)
static u32 *ps3vram_get_notifier(void *reports, int notifier)
{
return (void *)reports + DMA_NOTIFIER_OFFSET_BASE +
return reports + DMA_NOTIFIER_OFFSET_BASE +
DMA_NOTIFIER_SIZE * notifier;
}
static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
int i;
@ -122,7 +121,7 @@ static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev)
static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev,
unsigned int timeout_ms)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
@ -137,7 +136,7 @@ static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev,
static void ps3vram_init_ring(struct ps3_system_bus_device *dev)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET;
@ -146,7 +145,7 @@ static void ps3vram_init_ring(struct ps3_system_bus_device *dev)
static int ps3vram_wait_ring(struct ps3_system_bus_device *dev,
unsigned int timeout_ms)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
do {
@ -175,7 +174,7 @@ static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan, u32 tag,
static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
int status;
ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET));
@ -183,20 +182,17 @@ static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev)
priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
/* asking the HV for a blit will kick the FIFO */
status = lv1_gpu_context_attribute(priv->context_handle,
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0,
0, 0, 0);
status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0);
if (status)
dev_err(&dev->core,
"%s: lv1_gpu_context_attribute failed %d\n", __func__,
status);
dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n",
__func__, status);
priv->fifo_ptr = priv->fifo_base;
}
static void ps3vram_fire_ring(struct ps3_system_bus_device *dev)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
int status;
mutex_lock(&ps3_gpu_mutex);
@ -205,13 +201,10 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev)
(priv->fifo_ptr - priv->fifo_base) * sizeof(u32);
/* asking the HV for a blit will kick the FIFO */
status = lv1_gpu_context_attribute(priv->context_handle,
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0,
0, 0, 0);
status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0);
if (status)
dev_err(&dev->core,
"%s: lv1_gpu_context_attribute failed %d\n", __func__,
status);
dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n",
__func__, status);
if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) >
FIFO_SIZE - 1024) {
@ -225,7 +218,7 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev)
static void ps3vram_bind(struct ps3_system_bus_device *dev)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1);
ps3vram_out_ring(priv, 0x31337303);
@ -248,7 +241,7 @@ static int ps3vram_upload(struct ps3_system_bus_device *dev,
unsigned int src_offset, unsigned int dst_offset,
int len, int count)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
ps3vram_begin_ring(priv, UPLOAD_SUBCH,
NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
@ -280,7 +273,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev,
unsigned int src_offset, unsigned int dst_offset,
int len, int count)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
@ -310,7 +303,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev,
static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
struct ps3vram_cache *cache = &priv->cache;
if (!(cache->tags[entry].flags & CACHE_PAGE_DIRTY))
@ -332,7 +325,7 @@ static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry)
static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry,
unsigned int address)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
struct ps3vram_cache *cache = &priv->cache;
dev_dbg(&dev->core, "Fetching %d: 0x%08x\n", entry, address);
@ -352,7 +345,7 @@ static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry,
static void ps3vram_cache_flush(struct ps3_system_bus_device *dev)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
struct ps3vram_cache *cache = &priv->cache;
int i;
@ -366,7 +359,7 @@ static void ps3vram_cache_flush(struct ps3_system_bus_device *dev)
static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev,
loff_t address)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
struct ps3vram_cache *cache = &priv->cache;
unsigned int base;
unsigned int offset;
@ -400,7 +393,7 @@ static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev,
static int ps3vram_cache_init(struct ps3_system_bus_device *dev)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
priv->cache.page_count = CACHE_PAGE_COUNT;
priv->cache.page_size = CACHE_PAGE_SIZE;
@ -419,7 +412,7 @@ static int ps3vram_cache_init(struct ps3_system_bus_device *dev)
static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
ps3vram_cache_flush(dev);
kfree(priv->cache.tags);
@ -428,7 +421,7 @@ static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev)
static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
size_t len, size_t *retlen, u_char *buf)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
unsigned int cached, count;
dev_dbg(&dev->core, "%s: from=0x%08x len=0x%zx\n", __func__,
@ -449,8 +442,6 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
offset = (unsigned int) (from & (priv->cache.page_size - 1));
avail = priv->cache.page_size - offset;
mutex_lock(&priv->lock);
entry = ps3vram_cache_match(dev, from);
cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
@ -462,8 +453,6 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
avail = count;
memcpy(buf, priv->xdr_buf + cached, avail);
mutex_unlock(&priv->lock);
buf += avail;
count -= avail;
from += avail;
@ -476,7 +465,7 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to,
size_t len, size_t *retlen, const u_char *buf)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
unsigned int cached, count;
if (to >= priv->size)
@ -494,8 +483,6 @@ static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to,
offset = (unsigned int) (to & (priv->cache.page_size - 1));
avail = priv->cache.page_size - offset;
mutex_lock(&priv->lock);
entry = ps3vram_cache_match(dev, to);
cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
@ -509,8 +496,6 @@ static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to,
priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY;
mutex_unlock(&priv->lock);
buf += avail;
count -= avail;
to += avail;
@ -543,28 +528,26 @@ static const struct file_operations ps3vram_proc_fops = {
static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
struct proc_dir_entry *pde;
pde = proc_create(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops);
if (!pde) {
pde = proc_create_data(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops,
priv);
if (!pde)
dev_warn(&dev->core, "failed to create /proc entry\n");
return;
}
pde->data = priv;
}
static int ps3vram_make_request(struct request_queue *q, struct bio *bio)
static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev,
struct bio *bio)
{
struct ps3_system_bus_device *dev = q->queuedata;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
int write = bio_data_dir(bio) == WRITE;
const char *op = write ? "write" : "read";
loff_t offset = bio->bi_sector << 9;
int error = 0;
struct bio_vec *bvec;
unsigned int i;
dev_dbg(&dev->core, "%s\n", __func__);
struct bio *next;
bio_for_each_segment(bvec, bio, i) {
/* PS3 is ppc64, so we don't handle highmem */
@ -585,6 +568,7 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio)
if (retlen != len) {
dev_err(&dev->core, "Short %s\n", op);
error = -EIO;
goto out;
}
@ -594,7 +578,35 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio)
dev_dbg(&dev->core, "%s completed\n", op);
out:
spin_lock_irq(&priv->lock);
bio_list_pop(&priv->list);
next = bio_list_peek(&priv->list);
spin_unlock_irq(&priv->lock);
bio_endio(bio, error);
return next;
}
static int ps3vram_make_request(struct request_queue *q, struct bio *bio)
{
struct ps3_system_bus_device *dev = q->queuedata;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
int busy;
dev_dbg(&dev->core, "%s\n", __func__);
spin_lock_irq(&priv->lock);
busy = !bio_list_empty(&priv->list);
bio_list_add(&priv->list, bio);
spin_unlock_irq(&priv->lock);
if (busy)
return 0;
do {
bio = ps3vram_do_bio(dev, bio);
} while (bio);
return 0;
}
@ -604,8 +616,8 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
int error, status;
struct request_queue *queue;
struct gendisk *gendisk;
u64 ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, ddr_size,
reports_size;
u64 ddr_size, ddr_lpar, ctrl_lpar, info_lpar, reports_lpar,
reports_size, xdr_lpar;
char *rest;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@ -614,10 +626,9 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
goto fail;
}
mutex_init(&priv->lock);
dev->core.driver_data = priv;
priv = dev->core.driver_data;
spin_lock_init(&priv->lock);
bio_list_init(&priv->list);
ps3_system_bus_set_drvdata(dev, priv);
/* Allocate XDR buffer (1MiB aligned) */
priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL,
@ -636,7 +647,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
if (ps3_open_hv_device(dev)) {
dev_err(&dev->core, "ps3_open_hv_device failed\n");
error = -EAGAIN;
goto out_close_gpu;
goto out_free_xdr_buf;
}
/* Request memory */
@ -660,7 +671,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
dev_err(&dev->core, "lv1_gpu_memory_allocate failed %d\n",
status);
error = -ENOMEM;
goto out_free_xdr_buf;
goto out_close_gpu;
}
/* Request context */
@ -676,9 +687,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
}
/* Map XDR buffer to RSX */
xdr_lpar = ps3_mm_phys_to_lpar(__pa(priv->xdr_buf));
status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF,
ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)),
XDR_BUF_SIZE, 0);
xdr_lpar, XDR_BUF_SIZE,
CBE_IOPTE_PP_W | CBE_IOPTE_PP_R |
CBE_IOPTE_M);
if (status) {
dev_err(&dev->core, "lv1_gpu_context_iomap failed %d\n",
status);
@ -686,19 +699,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
goto out_free_context;
}
priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE);
if (!priv->ddr_base) {
dev_err(&dev->core, "ioremap DDR failed\n");
error = -ENOMEM;
goto out_free_context;
}
priv->ctrl = ioremap(ctrl_lpar, 64 * 1024);
if (!priv->ctrl) {
dev_err(&dev->core, "ioremap CTRL failed\n");
error = -ENOMEM;
goto out_unmap_vram;
goto out_unmap_context;
}
priv->reports = ioremap(reports_lpar, reports_size);
@ -775,8 +780,9 @@ out_unmap_reports:
iounmap(priv->reports);
out_unmap_ctrl:
iounmap(priv->ctrl);
out_unmap_vram:
iounmap(priv->ddr_base);
out_unmap_context:
lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, xdr_lpar,
XDR_BUF_SIZE, CBE_IOPTE_M);
out_free_context:
lv1_gpu_context_free(priv->context_handle);
out_free_memory:
@ -787,14 +793,14 @@ out_free_xdr_buf:
free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
fail_free_priv:
kfree(priv);
dev->core.driver_data = NULL;
ps3_system_bus_set_drvdata(dev, NULL);
fail:
return error;
}
static int ps3vram_remove(struct ps3_system_bus_device *dev)
{
struct ps3vram_priv *priv = dev->core.driver_data;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
del_gendisk(priv->gendisk);
put_disk(priv->gendisk);
@ -803,13 +809,15 @@ static int ps3vram_remove(struct ps3_system_bus_device *dev)
ps3vram_cache_cleanup(dev);
iounmap(priv->reports);
iounmap(priv->ctrl);
iounmap(priv->ddr_base);
lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF,
ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)),
XDR_BUF_SIZE, CBE_IOPTE_M);
lv1_gpu_context_free(priv->context_handle);
lv1_gpu_memory_free(priv->memory_handle);
ps3_close_hv_device(dev);
free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
kfree(priv);
dev->core.driver_data = NULL;
ps3_system_bus_set_drvdata(dev, NULL);
return 0;
}

View File

@ -33,48 +33,64 @@
struct ps3flash_private {
struct mutex mutex; /* Bounce buffer mutex */
u64 chunk_sectors;
int tag; /* Start sector of buffer, -1 if invalid */
bool dirty;
};
static struct ps3_storage_device *ps3flash_dev;
static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev,
u64 lpar, u64 start_sector,
u64 sectors, int write)
static int ps3flash_read_write_sectors(struct ps3_storage_device *dev,
u64 start_sector, int write)
{
u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors,
struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
u64 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar,
start_sector, priv->chunk_sectors,
write);
if (res) {
dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
__LINE__, write ? "write" : "read", res);
return -EIO;
}
return sectors;
return 0;
}
static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev,
u64 start_sector, u64 sectors,
unsigned int sector_offset)
static int ps3flash_writeback(struct ps3_storage_device *dev)
{
u64 max_sectors, lpar;
struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
int res;
max_sectors = dev->bounce_size / dev->blk_size;
if (sectors > max_sectors) {
dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %llu\n",
__func__, __LINE__, max_sectors);
sectors = max_sectors;
}
if (!priv->dirty || priv->tag < 0)
return 0;
lpar = dev->bounce_lpar + sector_offset * dev->blk_size;
return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors,
0);
res = ps3flash_read_write_sectors(dev, priv->tag, 1);
if (res)
return res;
priv->dirty = false;
return 0;
}
static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev,
u64 start_sector)
static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector)
{
u64 sectors = dev->bounce_size / dev->blk_size;
return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector,
sectors, 1);
struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
int res;
if (start_sector == priv->tag)
return 0;
res = ps3flash_writeback(dev);
if (res)
return res;
priv->tag = -1;
res = ps3flash_read_write_sectors(dev, start_sector, 0);
if (res)
return res;
priv->tag = start_sector;
return 0;
}
static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
@ -104,18 +120,19 @@ out:
return res;
}
static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
loff_t *pos)
static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
size_t count, loff_t *pos)
{
struct ps3_storage_device *dev = ps3flash_dev;
struct ps3flash_private *priv = dev->sbd.core.driver_data;
u64 size, start_sector, end_sector, offset;
ssize_t sectors_read;
struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
u64 size, sector, offset;
int res;
size_t remaining, n;
const void *src;
dev_dbg(&dev->sbd.core,
"%s:%u: Reading %zu bytes at position %lld to user 0x%p\n",
__func__, __LINE__, count, *pos, buf);
"%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n",
__func__, __LINE__, count, *pos, userbuf, kernelbuf);
size = dev->regions[dev->region_idx].size*dev->blk_size;
if (*pos >= size || !count)
@ -128,156 +145,40 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
count = size - *pos;
}
start_sector = *pos / dev->blk_size;
offset = *pos % dev->blk_size;
end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size);
remaining = count;
do {
mutex_lock(&priv->mutex);
sectors_read = ps3flash_read_sectors(dev, start_sector,
end_sector-start_sector,
0);
if (sectors_read < 0) {
mutex_unlock(&priv->mutex);
goto fail;
}
n = min_t(u64, remaining, sectors_read*dev->blk_size-offset);
dev_dbg(&dev->sbd.core,
"%s:%u: copy %lu bytes from 0x%p to user 0x%p\n",
__func__, __LINE__, n, dev->bounce_buf+offset, buf);
if (copy_to_user(buf, dev->bounce_buf+offset, n)) {
mutex_unlock(&priv->mutex);
sectors_read = -EFAULT;
goto fail;
}
mutex_unlock(&priv->mutex);
*pos += n;
buf += n;
remaining -= n;
start_sector += sectors_read;
offset = 0;
} while (remaining > 0);
return count;
fail:
return sectors_read;
}
static ssize_t ps3flash_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
struct ps3_storage_device *dev = ps3flash_dev;
struct ps3flash_private *priv = dev->sbd.core.driver_data;
u64 size, chunk_sectors, start_write_sector, end_write_sector,
end_read_sector, start_read_sector, head, tail, offset;
ssize_t res;
size_t remaining, n;
unsigned int sec_off;
dev_dbg(&dev->sbd.core,
"%s:%u: Writing %zu bytes at position %lld from user 0x%p\n",
__func__, __LINE__, count, *pos, buf);
size = dev->regions[dev->region_idx].size*dev->blk_size;
if (*pos >= size || !count)
return 0;
if (*pos + count > size) {
dev_dbg(&dev->sbd.core,
"%s:%u Truncating count from %zu to %llu\n", __func__,
__LINE__, count, size - *pos);
count = size - *pos;
}
chunk_sectors = dev->bounce_size / dev->blk_size;
start_write_sector = *pos / dev->bounce_size * chunk_sectors;
sector = *pos / dev->bounce_size * priv->chunk_sectors;
offset = *pos % dev->bounce_size;
end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) *
chunk_sectors;
end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size);
start_read_sector = (*pos + count) / dev->blk_size;
/*
* As we have to write in 256 KiB chunks, while we can read in blk_size
* (usually 512 bytes) chunks, we perform the following steps:
* 1. Read from start_write_sector to end_read_sector ("head")
* 2. Read from start_read_sector to end_write_sector ("tail")
* 3. Copy data to buffer
* 4. Write from start_write_sector to end_write_sector
* All of this is complicated by using only one 256 KiB bounce buffer.
*/
head = end_read_sector - start_write_sector;
tail = end_write_sector - start_read_sector;
remaining = count;
do {
n = min_t(u64, remaining, dev->bounce_size - offset);
src = dev->bounce_buf + offset;
mutex_lock(&priv->mutex);
if (end_read_sector >= start_read_sector) {
/* Merge head and tail */
dev_dbg(&dev->sbd.core,
"Merged head and tail: %llu sectors at %llu\n",
chunk_sectors, start_write_sector);
res = ps3flash_read_sectors(dev, start_write_sector,
chunk_sectors, 0);
if (res < 0)
goto fail;
} else {
if (head) {
/* Read head */
dev_dbg(&dev->sbd.core,
"head: %llu sectors at %llu\n", head,
start_write_sector);
res = ps3flash_read_sectors(dev,
start_write_sector,
head, 0);
if (res < 0)
goto fail;
}
if (start_read_sector <
start_write_sector+chunk_sectors) {
/* Read tail */
dev_dbg(&dev->sbd.core,
"tail: %llu sectors at %llu\n", tail,
start_read_sector);
sec_off = start_read_sector-start_write_sector;
res = ps3flash_read_sectors(dev,
start_read_sector,
tail, sec_off);
if (res < 0)
goto fail;
}
}
res = ps3flash_fetch(dev, sector);
if (res)
goto fail;
n = min_t(u64, remaining, dev->bounce_size-offset);
dev_dbg(&dev->sbd.core,
"%s:%u: copy %lu bytes from user 0x%p to 0x%p\n",
__func__, __LINE__, n, buf, dev->bounce_buf+offset);
if (copy_from_user(dev->bounce_buf+offset, buf, n)) {
res = -EFAULT;
goto fail;
"%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n",
__func__, __LINE__, n, src, userbuf, kernelbuf);
if (userbuf) {
if (copy_to_user(userbuf, src, n)) {
res = -EFAULT;
goto fail;
}
userbuf += n;
}
if (kernelbuf) {
memcpy(kernelbuf, src, n);
kernelbuf += n;
}
res = ps3flash_write_chunk(dev, start_write_sector);
if (res < 0)
goto fail;
mutex_unlock(&priv->mutex);
*pos += n;
buf += n;
remaining -= n;
start_write_sector += chunk_sectors;
head = 0;
sector += priv->chunk_sectors;
offset = 0;
} while (remaining > 0);
@ -288,6 +189,126 @@ fail:
return res;
}
static ssize_t ps3flash_write(const char __user *userbuf,
const void *kernelbuf, size_t count, loff_t *pos)
{
struct ps3_storage_device *dev = ps3flash_dev;
struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
u64 size, sector, offset;
int res = 0;
size_t remaining, n;
void *dst;
dev_dbg(&dev->sbd.core,
"%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n",
__func__, __LINE__, count, *pos, userbuf, kernelbuf);
size = dev->regions[dev->region_idx].size*dev->blk_size;
if (*pos >= size || !count)
return 0;
if (*pos + count > size) {
dev_dbg(&dev->sbd.core,
"%s:%u Truncating count from %zu to %llu\n", __func__,
__LINE__, count, size - *pos);
count = size - *pos;
}
sector = *pos / dev->bounce_size * priv->chunk_sectors;
offset = *pos % dev->bounce_size;
remaining = count;
do {
n = min_t(u64, remaining, dev->bounce_size - offset);
dst = dev->bounce_buf + offset;
mutex_lock(&priv->mutex);
if (n != dev->bounce_size)
res = ps3flash_fetch(dev, sector);
else if (sector != priv->tag)
res = ps3flash_writeback(dev);
if (res)
goto fail;
dev_dbg(&dev->sbd.core,
"%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n",
__func__, __LINE__, n, userbuf, kernelbuf, dst);
if (userbuf) {
if (copy_from_user(dst, userbuf, n)) {
res = -EFAULT;
goto fail;
}
userbuf += n;
}
if (kernelbuf) {
memcpy(dst, kernelbuf, n);
kernelbuf += n;
}
priv->tag = sector;
priv->dirty = true;
mutex_unlock(&priv->mutex);
*pos += n;
remaining -= n;
sector += priv->chunk_sectors;
offset = 0;
} while (remaining > 0);
return count;
fail:
mutex_unlock(&priv->mutex);
return res;
}
static ssize_t ps3flash_user_read(struct file *file, char __user *buf,
size_t count, loff_t *pos)
{
return ps3flash_read(buf, NULL, count, pos);
}
static ssize_t ps3flash_user_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
return ps3flash_write(buf, NULL, count, pos);
}
static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos)
{
return ps3flash_read(NULL, buf, count, &pos);
}
static ssize_t ps3flash_kernel_write(const void *buf, size_t count,
loff_t pos)
{
ssize_t res;
int wb;
res = ps3flash_write(NULL, buf, count, &pos);
if (res < 0)
return res;
/* Make kernel writes synchronous */
wb = ps3flash_writeback(ps3flash_dev);
if (wb)
return wb;
return res;
}
static int ps3flash_flush(struct file *file, fl_owner_t id)
{
return ps3flash_writeback(ps3flash_dev);
}
static int ps3flash_fsync(struct file *file, struct dentry *dentry,
int datasync)
{
return ps3flash_writeback(ps3flash_dev);
}
static irqreturn_t ps3flash_interrupt(int irq, void *data)
{
@ -312,12 +333,18 @@ static irqreturn_t ps3flash_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
static const struct file_operations ps3flash_fops = {
.owner = THIS_MODULE,
.llseek = ps3flash_llseek,
.read = ps3flash_read,
.write = ps3flash_write,
.read = ps3flash_user_read,
.write = ps3flash_user_write,
.flush = ps3flash_flush,
.fsync = ps3flash_fsync,
};
static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = {
.read = ps3flash_kernel_read,
.write = ps3flash_kernel_write,
};
static struct miscdevice ps3flash_misc = {
@ -366,11 +393,13 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
goto fail;
}
dev->sbd.core.driver_data = priv;
ps3_system_bus_set_drvdata(&dev->sbd, priv);
mutex_init(&priv->mutex);
priv->tag = -1;
dev->bounce_size = ps3flash_bounce_buffer.size;
dev->bounce_buf = ps3flash_bounce_buffer.address;
priv->chunk_sectors = dev->bounce_size / dev->blk_size;
error = ps3stor_setup(dev, ps3flash_interrupt);
if (error)
@ -386,13 +415,15 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
__func__, __LINE__, ps3flash_misc.minor);
ps3_os_area_flash_register(&ps3flash_kernel_ops);
return 0;
fail_teardown:
ps3stor_teardown(dev);
fail_free_priv:
kfree(priv);
dev->sbd.core.driver_data = NULL;
ps3_system_bus_set_drvdata(&dev->sbd, NULL);
fail:
ps3flash_dev = NULL;
return error;
@ -402,10 +433,11 @@ static int ps3flash_remove(struct ps3_system_bus_device *_dev)
{
struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
ps3_os_area_flash_register(NULL);
misc_deregister(&ps3flash_misc);
ps3stor_teardown(dev);
kfree(dev->sbd.core.driver_data);
dev->sbd.core.driver_data = NULL;
kfree(ps3_system_bus_get_drvdata(&dev->sbd));
ps3_system_bus_set_drvdata(&dev->sbd, NULL);
ps3flash_dev = NULL;
return 0;
}

View File

@ -1648,7 +1648,7 @@ static int ps3_gelic_driver_probe(struct ps3_system_bus_device *dev)
result = -ENOMEM;
goto fail_alloc_card;
}
ps3_system_bus_set_driver_data(dev, card);
ps3_system_bus_set_drvdata(dev, card);
card->dev = dev;
/* get internal vlan info */
@ -1749,7 +1749,7 @@ fail_alloc_irq:
bus_id(card),
0, 0);
fail_status_indicator:
ps3_system_bus_set_driver_data(dev, NULL);
ps3_system_bus_set_drvdata(dev, NULL);
kfree(netdev_card(netdev)->unalign);
free_netdev(netdev);
fail_alloc_card:
@ -1766,7 +1766,7 @@ fail_open:
static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev)
{
struct gelic_card *card = ps3_system_bus_get_driver_data(dev);
struct gelic_card *card = ps3_system_bus_get_drvdata(dev);
struct net_device *netdev0;
pr_debug("%s: called\n", __func__);
@ -1803,7 +1803,7 @@ static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev)
kfree(netdev_card(netdev0)->unalign);
free_netdev(netdev0);
ps3_system_bus_set_driver_data(dev, NULL);
ps3_system_bus_set_drvdata(dev, NULL);
ps3_dma_region_free(dev->d_region);

View File

@ -706,7 +706,7 @@ static void ps3_sys_manager_work(struct ps3_system_bus_device *dev)
ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN);
}
static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev)
static int __devinit ps3_sys_manager_probe(struct ps3_system_bus_device *dev)
{
int result;
struct ps3_sys_manager_ops ops;

View File

@ -80,12 +80,12 @@ static const struct avset_video_mode {
{ 0, }, /* auto */
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_W, 1280, 720},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_W, 1280, 720},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080},
{YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080},
{ RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768},
@ -937,7 +937,7 @@ int ps3av_audio_mute(int mute)
EXPORT_SYMBOL_GPL(ps3av_audio_mute);
static int ps3av_probe(struct ps3_system_bus_device *dev)
static int __devinit ps3av_probe(struct ps3_system_bus_device *dev)
{
int res;
int id;
@ -1048,7 +1048,7 @@ static struct ps3_vuart_port_driver ps3av_driver = {
.shutdown = ps3av_shutdown,
};
static int ps3av_module_init(void)
static int __init ps3av_module_init(void)
{
int error;

View File

@ -21,9 +21,10 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <asm/ps3av.h>
#include <asm/ps3fb.h>
#include <asm/ps3.h>
#include <asm/ps3gpu.h>
#include "vuart.h"

View File

@ -162,7 +162,7 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__,
(unsigned long)virq);
ps3_system_bus_set_driver_data(dev, hcd);
ps3_system_bus_set_drvdata(dev, hcd);
result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
@ -195,8 +195,7 @@ fail_start:
static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
{
unsigned int tmp;
struct usb_hcd *hcd =
(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev);
BUG_ON(!hcd);
@ -208,7 +207,7 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
ehci_shutdown(hcd);
usb_remove_hcd(hcd);
ps3_system_bus_set_driver_data(dev, NULL);
ps3_system_bus_set_drvdata(dev, NULL);
BUG_ON(!hcd->regs);
iounmap(hcd->regs);

View File

@ -162,7 +162,7 @@ static int ps3_ohci_probe(struct ps3_system_bus_device *dev)
dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__,
(unsigned long)virq);
ps3_system_bus_set_driver_data(dev, hcd);
ps3_system_bus_set_drvdata(dev, hcd);
result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
@ -195,8 +195,7 @@ fail_start:
static int ps3_ohci_remove(struct ps3_system_bus_device *dev)
{
unsigned int tmp;
struct usb_hcd *hcd =
(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev);
BUG_ON(!hcd);
@ -208,7 +207,7 @@ static int ps3_ohci_remove(struct ps3_system_bus_device *dev)
ohci_shutdown(hcd);
usb_remove_hcd(hcd);
ps3_system_bus_set_driver_data(dev, NULL);
ps3_system_bus_set_drvdata(dev, NULL);
BUG_ON(!hcd->regs);
iounmap(hcd->regs);

View File

@ -32,25 +32,16 @@
#include <linux/init.h>
#include <asm/abs_addr.h>
#include <asm/iommu.h>
#include <asm/lv1call.h>
#include <asm/ps3av.h>
#include <asm/ps3fb.h>
#include <asm/ps3.h>
#include <asm/ps3gpu.h>
#define DEVICE_NAME "ps3fb"
#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101
#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102
#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600
#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601
#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC 0x602
#define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION (1ULL << 32)
#define L1GPU_DISPLAY_SYNC_HSYNC 1
#define L1GPU_DISPLAY_SYNC_VSYNC 2
#define GPU_CMD_BUF_SIZE (2 * 1024 * 1024)
#define GPU_FB_START (64 * 1024)
#define GPU_IOIF (0x0d000000UL)
@ -462,33 +453,27 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
src_offset += GPU_FB_START;
mutex_lock(&ps3_gpu_mutex);
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
dst_offset, GPU_IOIF + src_offset,
L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
(width << 16) | height,
line_length);
status = lv1_gpu_fb_blit(ps3fb.context_handle, dst_offset,
GPU_IOIF + src_offset,
L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
(width << 16) | height,
line_length);
mutex_unlock(&ps3_gpu_mutex);
if (status)
dev_err(dev,
"%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
__func__, status);
dev_err(dev, "%s: lv1_gpu_fb_blit failed: %d\n", __func__,
status);
#ifdef HEAD_A
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
0, frame_offset, 0, 0);
status = lv1_gpu_display_flip(ps3fb.context_handle, 0, frame_offset);
if (status)
dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
__func__, status);
dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__,
status);
#endif
#ifdef HEAD_B
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
1, frame_offset, 0, 0);
status = lv1_gpu_display_flip(ps3fb.context_handle, 1, frame_offset);
if (status)
dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
__func__, status);
dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__,
status);
#endif
}
@ -956,73 +941,6 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
}
static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo,
struct device *dev)
{
int error;
dev_dbg(dev, "version_driver:%x\n", dinfo->version_driver);
dev_dbg(dev, "irq outlet:%x\n", dinfo->irq.irq_outlet);
dev_dbg(dev,
"version_gpu: %x memory_size: %x ch: %x core_freq: %d "
"mem_freq:%d\n",
dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel,
dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000);
if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
dev_err(dev, "%s: version_driver err:%x\n", __func__,
dinfo->version_driver);
return -EINVAL;
}
error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
&ps3fb.irq_no);
if (error) {
dev_err(dev, "%s: ps3_alloc_irq failed %d\n", __func__, error);
return error;
}
error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
DEVICE_NAME, dev);
if (error) {
dev_err(dev, "%s: request_irq failed %d\n", __func__, error);
ps3_irq_plug_destroy(ps3fb.irq_no);
return error;
}
dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) |
(1 << GPU_INTR_STATUS_FLIP_1);
return 0;
}
static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev)
{
int status;
status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF,
xdr_lpar, ps3fb_videomemory.size, 0);
if (status) {
dev_err(dev, "%s: lv1_gpu_context_iomap failed: %d\n",
__func__, status);
return -ENXIO;
}
dev_dbg(dev, "video:%p ioif:%lx lpar:%llx size:%lx\n",
ps3fb_videomemory.address, GPU_IOIF, xdr_lpar,
ps3fb_videomemory.size);
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
xdr_lpar, GPU_CMD_BUF_SIZE,
GPU_IOIF, 0);
if (status) {
dev_err(dev,
"%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
__func__, status);
return -ENXIO;
}
return 0;
}
static struct fb_ops ps3fb_ops = {
.fb_open = ps3fb_open,
.fb_release = ps3fb_release,
@ -1048,49 +966,18 @@ static struct fb_fix_screeninfo ps3fb_fix __initdata = {
.accel = FB_ACCEL_NONE,
};
static int ps3fb_set_sync(struct device *dev)
{
int status;
#ifdef HEAD_A
status = lv1_gpu_context_attribute(0x0,
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
if (status) {
dev_err(dev,
"%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: "
"%d\n",
__func__, status);
return -1;
}
#endif
#ifdef HEAD_B
status = lv1_gpu_context_attribute(0x0,
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
if (status) {
dev_err(dev,
"%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: "
"%d\n",
__func__, status);
return -1;
}
#endif
return 0;
}
static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
{
struct fb_info *info;
struct ps3fb_par *par;
int retval = -ENOMEM;
int retval;
u64 ddr_lpar = 0;
u64 lpar_dma_control = 0;
u64 lpar_driver_info = 0;
u64 lpar_reports = 0;
u64 lpar_reports_size = 0;
u64 xdr_lpar;
struct gpu_driver_info *dinfo;
void *fb_start;
int status;
struct task_struct *task;
@ -1101,8 +988,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
return -ENOMEM;
}
status = ps3_open_hv_device(dev);
if (status) {
retval = ps3_open_hv_device(dev);
if (retval) {
dev_err(&dev->core, "%s: ps3_open_hv_device failed\n",
__func__);
goto err;
@ -1116,7 +1003,24 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
init_waitqueue_head(&ps3fb.wait_vsync);
ps3fb_set_sync(&dev->core);
#ifdef HEAD_A
status = lv1_gpu_display_sync(0x0, 0, L1GPU_DISPLAY_SYNC_VSYNC);
if (status) {
dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n",
__func__, status);
retval = -ENODEV;
goto err_close_device;
}
#endif
#ifdef HEAD_B
status = lv1_gpu_display_sync(0x0, 1, L1GPU_DISPLAY_SYNC_VSYNC);
if (status) {
dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n",
__func__, status);
retval = -ENODEV;
goto err_close_device;
}
#endif
max_ps3fb_size = _ALIGN_UP(GPU_IOIF, 256*1024*1024) - GPU_IOIF;
if (ps3fb_videomemory.size > max_ps3fb_size) {
@ -1131,7 +1035,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
if (status) {
dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n",
__func__, status);
goto err;
goto err_close_device;
}
dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar);
@ -1141,33 +1045,85 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
&lpar_reports, &lpar_reports_size);
if (status) {
dev_err(&dev->core,
"%s: lv1_gpu_context_attribute failed: %d\n", __func__,
"%s: lv1_gpu_context_allocate failed: %d\n", __func__,
status);
goto err_gpu_memory_free;
}
/* vsync interrupt */
ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
if (!ps3fb.dinfo) {
dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
if (!dinfo) {
dev_err(&dev->core, "%s: ioremap failed\n", __func__);
goto err_gpu_context_free;
}
retval = ps3fb_vsync_settings(ps3fb.dinfo, &dev->core);
if (retval)
ps3fb.dinfo = dinfo;
dev_dbg(&dev->core, "version_driver:%x\n", dinfo->version_driver);
dev_dbg(&dev->core, "irq outlet:%x\n", dinfo->irq.irq_outlet);
dev_dbg(&dev->core, "version_gpu: %x memory_size: %x ch: %x "
"core_freq: %d mem_freq:%d\n", dinfo->version_gpu,
dinfo->memory_size, dinfo->hardware_channel,
dinfo->nvcore_frequency/1000000,
dinfo->memory_frequency/1000000);
if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
dev_err(&dev->core, "%s: version_driver err:%x\n", __func__,
dinfo->version_driver);
retval = -EINVAL;
goto err_iounmap_dinfo;
}
retval = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
&ps3fb.irq_no);
if (retval) {
dev_err(&dev->core, "%s: ps3_alloc_irq failed %d\n", __func__,
retval);
goto err_iounmap_dinfo;
}
retval = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt,
IRQF_DISABLED, DEVICE_NAME, &dev->core);
if (retval) {
dev_err(&dev->core, "%s: request_irq failed %d\n", __func__,
retval);
goto err_destroy_plug;
}
dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) |
(1 << GPU_INTR_STATUS_FLIP_1);
/* Clear memory to prevent kernel info leakage into userspace */
memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size);
xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address));
retval = ps3fb_xdr_settings(xdr_lpar, &dev->core);
if (retval)
status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF,
xdr_lpar, ps3fb_videomemory.size,
CBE_IOPTE_PP_W | CBE_IOPTE_PP_R |
CBE_IOPTE_M);
if (status) {
dev_err(&dev->core, "%s: lv1_gpu_context_iomap failed: %d\n",
__func__, status);
retval = -ENXIO;
goto err_free_irq;
}
dev_dbg(&dev->core, "video:%p ioif:%lx lpar:%llx size:%lx\n",
ps3fb_videomemory.address, GPU_IOIF, xdr_lpar,
ps3fb_videomemory.size);
status = lv1_gpu_fb_setup(ps3fb.context_handle, xdr_lpar,
GPU_CMD_BUF_SIZE, GPU_IOIF);
if (status) {
dev_err(&dev->core, "%s: lv1_gpu_fb_setup failed: %d\n",
__func__, status);
retval = -ENXIO;
goto err_context_unmap;
}
info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core);
if (!info)
goto err_free_irq;
goto err_context_fb_close;
par = info->par;
par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */
@ -1210,7 +1166,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
if (retval < 0)
goto err_fb_dealloc;
dev->core.driver_data = info;
ps3_system_bus_set_drvdata(dev, info);
dev_info(info->device, "%s %s, using %u KiB of video memory\n",
dev_driver_string(info->dev), dev_name(info->dev),
@ -1232,8 +1188,14 @@ err_fb_dealloc:
fb_dealloc_cmap(&info->cmap);
err_framebuffer_release:
framebuffer_release(info);
err_context_fb_close:
lv1_gpu_fb_close(ps3fb.context_handle);
err_context_unmap:
lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar,
ps3fb_videomemory.size, CBE_IOPTE_M);
err_free_irq:
free_irq(ps3fb.irq_no, &dev->core);
err_destroy_plug:
ps3_irq_plug_destroy(ps3fb.irq_no);
err_iounmap_dinfo:
iounmap((u8 __force __iomem *)ps3fb.dinfo);
@ -1241,14 +1203,16 @@ err_gpu_context_free:
lv1_gpu_context_free(ps3fb.context_handle);
err_gpu_memory_free:
lv1_gpu_memory_free(ps3fb.memory_handle);
err_close_device:
ps3_close_hv_device(dev);
err:
return retval;
}
static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
{
int status;
struct fb_info *info = dev->core.driver_data;
struct fb_info *info = ps3_system_bus_get_drvdata(dev);
u64 xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address));
dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
@ -1268,20 +1232,14 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
unregister_framebuffer(info);
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
info = dev->core.driver_data = NULL;
ps3_system_bus_set_drvdata(dev, NULL);
}
iounmap((u8 __force __iomem *)ps3fb.dinfo);
status = lv1_gpu_context_free(ps3fb.context_handle);
if (status)
dev_dbg(&dev->core, "lv1_gpu_context_free failed: %d\n",
status);
status = lv1_gpu_memory_free(ps3fb.memory_handle);
if (status)
dev_dbg(&dev->core, "lv1_gpu_memory_free failed: %d\n",
status);
lv1_gpu_fb_close(ps3fb.context_handle);
lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar,
ps3fb_videomemory.size, CBE_IOPTE_M);
lv1_gpu_context_free(ps3fb.context_handle);
lv1_gpu_memory_free(ps3fb.memory_handle);
ps3_close_hv_device(dev);
dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);

View File

@ -0,0 +1,42 @@
/*
* Generic implementation of 64-bit atomics using spinlocks,
* useful on processors that don't have 64-bit atomic instructions.
*
* Copyright © 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#ifndef _ASM_GENERIC_ATOMIC64_H
#define _ASM_GENERIC_ATOMIC64_H
typedef struct {
long long counter;
} atomic64_t;
#define ATOMIC64_INIT(i) { (i) }
extern long long atomic64_read(const atomic64_t *v);
extern void atomic64_set(atomic64_t *v, long long i);
extern void atomic64_add(long long a, atomic64_t *v);
extern long long atomic64_add_return(long long a, atomic64_t *v);
extern void atomic64_sub(long long a, atomic64_t *v);
extern long long atomic64_sub_return(long long a, atomic64_t *v);
extern long long atomic64_dec_if_positive(atomic64_t *v);
extern long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n);
extern long long atomic64_xchg(atomic64_t *v, long long new);
extern int atomic64_add_unless(atomic64_t *v, long long a, long long u);
#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0)
#define atomic64_inc(v) atomic64_add(1LL, (v))
#define atomic64_inc_return(v) atomic64_add_return(1LL, (v))
#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
#define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0)
#define atomic64_dec(v) atomic64_sub(1LL, (v))
#define atomic64_dec_return(v) atomic64_sub_return(1LL, (v))
#define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0)
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL)
#endif /* _ASM_GENERIC_ATOMIC64_H */

View File

@ -590,6 +590,11 @@ static inline void bio_list_merge_head(struct bio_list *bl,
bl->head = bl2->head;
}
static inline struct bio *bio_list_peek(struct bio_list *bl)
{
return bl->head;
}
static inline struct bio *bio_list_pop(struct bio_list *bl)
{
struct bio *bio = bl->head;

View File

@ -194,4 +194,10 @@ config DISABLE_OBSOLETE_CPUMASK_FUNCTIONS
config NLATTR
bool
#
# Generic 64-bit atomic support is selected if needed
#
config GENERIC_ATOMIC64
bool
endmenu

View File

@ -95,6 +95,8 @@ obj-$(CONFIG_DMA_API_DEBUG) += dma-debug.o
obj-$(CONFIG_GENERIC_CSUM) += checksum.o
obj-$(CONFIG_GENERIC_ATOMIC64) += atomic64.o
hostprogs-y := gen_crc32table
clean-files := crc32table.h

175
lib/atomic64.c Normal file
View File

@ -0,0 +1,175 @@
/*
* Generic implementation of 64-bit atomics using spinlocks,
* useful on processors that don't have 64-bit atomic instructions.
*
* Copyright © 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/types.h>
#include <linux/cache.h>
#include <linux/spinlock.h>
#include <linux/init.h>
#include <asm/atomic.h>
/*
* We use a hashed array of spinlocks to provide exclusive access
* to each atomic64_t variable. Since this is expected to used on
* systems with small numbers of CPUs (<= 4 or so), we use a
* relatively small array of 16 spinlocks to avoid wasting too much
* memory on the spinlock array.
*/
#define NR_LOCKS 16
/*
* Ensure each lock is in a separate cacheline.
*/
static union {
spinlock_t lock;
char pad[L1_CACHE_BYTES];
} atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp;
static inline spinlock_t *lock_addr(const atomic64_t *v)
{
unsigned long addr = (unsigned long) v;
addr >>= L1_CACHE_SHIFT;
addr ^= (addr >> 8) ^ (addr >> 16);
return &atomic64_lock[addr & (NR_LOCKS - 1)].lock;
}
long long atomic64_read(const atomic64_t *v)
{
unsigned long flags;
spinlock_t *lock = lock_addr(v);
long long val;
spin_lock_irqsave(lock, flags);
val = v->counter;
spin_unlock_irqrestore(lock, flags);
return val;
}
void atomic64_set(atomic64_t *v, long long i)
{
unsigned long flags;
spinlock_t *lock = lock_addr(v);
spin_lock_irqsave(lock, flags);
v->counter = i;
spin_unlock_irqrestore(lock, flags);
}
void atomic64_add(long long a, atomic64_t *v)
{
unsigned long flags;
spinlock_t *lock = lock_addr(v);
spin_lock_irqsave(lock, flags);
v->counter += a;
spin_unlock_irqrestore(lock, flags);
}
long long atomic64_add_return(long long a, atomic64_t *v)
{
unsigned long flags;
spinlock_t *lock = lock_addr(v);
long long val;
spin_lock_irqsave(lock, flags);
val = v->counter += a;
spin_unlock_irqrestore(lock, flags);
return val;
}
void atomic64_sub(long long a, atomic64_t *v)
{
unsigned long flags;
spinlock_t *lock = lock_addr(v);
spin_lock_irqsave(lock, flags);
v->counter -= a;
spin_unlock_irqrestore(lock, flags);
}
long long atomic64_sub_return(long long a, atomic64_t *v)
{
unsigned long flags;
spinlock_t *lock = lock_addr(v);
long long val;
spin_lock_irqsave(lock, flags);
val = v->counter -= a;
spin_unlock_irqrestore(lock, flags);
return val;
}
long long atomic64_dec_if_positive(atomic64_t *v)
{
unsigned long flags;
spinlock_t *lock = lock_addr(v);
long long val;
spin_lock_irqsave(lock, flags);
val = v->counter - 1;
if (val >= 0)
v->counter = val;
spin_unlock_irqrestore(lock, flags);
return val;
}
long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n)
{
unsigned long flags;
spinlock_t *lock = lock_addr(v);
long long val;
spin_lock_irqsave(lock, flags);
val = v->counter;
if (val == o)
v->counter = n;
spin_unlock_irqrestore(lock, flags);
return val;
}
long long atomic64_xchg(atomic64_t *v, long long new)
{
unsigned long flags;
spinlock_t *lock = lock_addr(v);
long long val;
spin_lock_irqsave(lock, flags);
val = v->counter;
v->counter = new;
spin_unlock_irqrestore(lock, flags);
return val;
}
int atomic64_add_unless(atomic64_t *v, long long a, long long u)
{
unsigned long flags;
spinlock_t *lock = lock_addr(v);
int ret = 1;
spin_lock_irqsave(lock, flags);
if (v->counter != u) {
v->counter += a;
ret = 0;
}
spin_unlock_irqrestore(lock, flags);
return ret;
}
static int init_atomic64_lock(void)
{
int i;
for (i = 0; i < NR_LOCKS; ++i)
spin_lock_init(&atomic64_lock[i].lock);
return 0;
}
pure_initcall(init_atomic64_lock);