diff options
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/file.c | 178 |
1 files changed, 154 insertions, 24 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 78df905743b3..510adc57af90 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c | |||
@@ -40,6 +40,120 @@ | |||
40 | 40 | ||
41 | #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) | 41 | #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) |
42 | 42 | ||
43 | /* Simple attribute files */ | ||
44 | struct spufs_attr { | ||
45 | int (*get)(void *, u64 *); | ||
46 | int (*set)(void *, u64); | ||
47 | char get_buf[24]; /* enough to store a u64 and "\n\0" */ | ||
48 | char set_buf[24]; | ||
49 | void *data; | ||
50 | const char *fmt; /* format for read operation */ | ||
51 | struct mutex mutex; /* protects access to these buffers */ | ||
52 | }; | ||
53 | |||
54 | static int spufs_attr_open(struct inode *inode, struct file *file, | ||
55 | int (*get)(void *, u64 *), int (*set)(void *, u64), | ||
56 | const char *fmt) | ||
57 | { | ||
58 | struct spufs_attr *attr; | ||
59 | |||
60 | attr = kmalloc(sizeof(*attr), GFP_KERNEL); | ||
61 | if (!attr) | ||
62 | return -ENOMEM; | ||
63 | |||
64 | attr->get = get; | ||
65 | attr->set = set; | ||
66 | attr->data = inode->i_private; | ||
67 | attr->fmt = fmt; | ||
68 | mutex_init(&attr->mutex); | ||
69 | file->private_data = attr; | ||
70 | |||
71 | return nonseekable_open(inode, file); | ||
72 | } | ||
73 | |||
74 | static int spufs_attr_release(struct inode *inode, struct file *file) | ||
75 | { | ||
76 | kfree(file->private_data); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static ssize_t spufs_attr_read(struct file *file, char __user *buf, | ||
81 | size_t len, loff_t *ppos) | ||
82 | { | ||
83 | struct spufs_attr *attr; | ||
84 | size_t size; | ||
85 | ssize_t ret; | ||
86 | |||
87 | attr = file->private_data; | ||
88 | if (!attr->get) | ||
89 | return -EACCES; | ||
90 | |||
91 | ret = mutex_lock_interruptible(&attr->mutex); | ||
92 | if (ret) | ||
93 | return ret; | ||
94 | |||
95 | if (*ppos) { /* continued read */ | ||
96 | size = strlen(attr->get_buf); | ||
97 | } else { /* first read */ | ||
98 | u64 val; | ||
99 | ret = attr->get(attr->data, &val); | ||
100 | if (ret) | ||
101 | goto out; | ||
102 | |||
103 | size = scnprintf(attr->get_buf, sizeof(attr->get_buf), | ||
104 | attr->fmt, (unsigned long long)val); | ||
105 | } | ||
106 | |||
107 | ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size); | ||
108 | out: | ||
109 | mutex_unlock(&attr->mutex); | ||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | static ssize_t spufs_attr_write(struct file *file, const char __user *buf, | ||
114 | size_t len, loff_t *ppos) | ||
115 | { | ||
116 | struct spufs_attr *attr; | ||
117 | u64 val; | ||
118 | size_t size; | ||
119 | ssize_t ret; | ||
120 | |||
121 | attr = file->private_data; | ||
122 | if (!attr->set) | ||
123 | return -EACCES; | ||
124 | |||
125 | ret = mutex_lock_interruptible(&attr->mutex); | ||
126 | if (ret) | ||
127 | return ret; | ||
128 | |||
129 | ret = -EFAULT; | ||
130 | size = min(sizeof(attr->set_buf) - 1, len); | ||
131 | if (copy_from_user(attr->set_buf, buf, size)) | ||
132 | goto out; | ||
133 | |||
134 | ret = len; /* claim we got the whole input */ | ||
135 | attr->set_buf[size] = '\0'; | ||
136 | val = simple_strtol(attr->set_buf, NULL, 0); | ||
137 | attr->set(attr->data, val); | ||
138 | out: | ||
139 | mutex_unlock(&attr->mutex); | ||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | #define DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \ | ||
144 | static int __fops ## _open(struct inode *inode, struct file *file) \ | ||
145 | { \ | ||
146 | __simple_attr_check_format(__fmt, 0ull); \ | ||
147 | return spufs_attr_open(inode, file, __get, __set, __fmt); \ | ||
148 | } \ | ||
149 | static struct file_operations __fops = { \ | ||
150 | .owner = THIS_MODULE, \ | ||
151 | .open = __fops ## _open, \ | ||
152 | .release = spufs_attr_release, \ | ||
153 | .read = spufs_attr_read, \ | ||
154 | .write = spufs_attr_write, \ | ||
155 | }; | ||
156 | |||
43 | 157 | ||
44 | static int | 158 | static int |
45 | spufs_mem_open(struct inode *inode, struct file *file) | 159 | spufs_mem_open(struct inode *inode, struct file *file) |
@@ -296,25 +410,26 @@ static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) | |||
296 | #define spufs_cntl_mmap NULL | 410 | #define spufs_cntl_mmap NULL |
297 | #endif /* !SPUFS_MMAP_4K */ | 411 | #endif /* !SPUFS_MMAP_4K */ |
298 | 412 | ||
299 | static u64 spufs_cntl_get(void *data) | 413 | static int spufs_cntl_get(void *data, u64 *val) |
300 | { | 414 | { |
301 | struct spu_context *ctx = data; | 415 | struct spu_context *ctx = data; |
302 | u64 val; | ||
303 | 416 | ||
304 | spu_acquire(ctx); | 417 | spu_acquire(ctx); |
305 | val = ctx->ops->status_read(ctx); | 418 | *val = ctx->ops->status_read(ctx); |
306 | spu_release(ctx); | 419 | spu_release(ctx); |
307 | 420 | ||
308 | return val; | 421 | return 0; |
309 | } | 422 | } |
310 | 423 | ||
311 | static void spufs_cntl_set(void *data, u64 val) | 424 | static int spufs_cntl_set(void *data, u64 val) |
312 | { | 425 | { |
313 | struct spu_context *ctx = data; | 426 | struct spu_context *ctx = data; |
314 | 427 | ||
315 | spu_acquire(ctx); | 428 | spu_acquire(ctx); |
316 | ctx->ops->runcntl_write(ctx, val); | 429 | ctx->ops->runcntl_write(ctx, val); |
317 | spu_release(ctx); | 430 | spu_release(ctx); |
431 | |||
432 | return 0; | ||
318 | } | 433 | } |
319 | 434 | ||
320 | static int spufs_cntl_open(struct inode *inode, struct file *file) | 435 | static int spufs_cntl_open(struct inode *inode, struct file *file) |
@@ -327,7 +442,7 @@ static int spufs_cntl_open(struct inode *inode, struct file *file) | |||
327 | if (!i->i_openers++) | 442 | if (!i->i_openers++) |
328 | ctx->cntl = inode->i_mapping; | 443 | ctx->cntl = inode->i_mapping; |
329 | mutex_unlock(&ctx->mapping_lock); | 444 | mutex_unlock(&ctx->mapping_lock); |
330 | return simple_attr_open(inode, file, spufs_cntl_get, | 445 | return spufs_attr_open(inode, file, spufs_cntl_get, |
331 | spufs_cntl_set, "0x%08lx"); | 446 | spufs_cntl_set, "0x%08lx"); |
332 | } | 447 | } |
333 | 448 | ||
@@ -337,7 +452,7 @@ spufs_cntl_release(struct inode *inode, struct file *file) | |||
337 | struct spufs_inode_info *i = SPUFS_I(inode); | 452 | struct spufs_inode_info *i = SPUFS_I(inode); |
338 | struct spu_context *ctx = i->i_ctx; | 453 | struct spu_context *ctx = i->i_ctx; |
339 | 454 | ||
340 | simple_attr_close(inode, file); | 455 | spufs_attr_release(inode, file); |
341 | 456 | ||
342 | mutex_lock(&ctx->mapping_lock); | 457 | mutex_lock(&ctx->mapping_lock); |
343 | if (!--i->i_openers) | 458 | if (!--i->i_openers) |
@@ -349,8 +464,8 @@ spufs_cntl_release(struct inode *inode, struct file *file) | |||
349 | static const struct file_operations spufs_cntl_fops = { | 464 | static const struct file_operations spufs_cntl_fops = { |
350 | .open = spufs_cntl_open, | 465 | .open = spufs_cntl_open, |
351 | .release = spufs_cntl_release, | 466 | .release = spufs_cntl_release, |
352 | .read = simple_attr_read, | 467 | .read = spufs_attr_read, |
353 | .write = simple_attr_write, | 468 | .write = spufs_attr_write, |
354 | .mmap = spufs_cntl_mmap, | 469 | .mmap = spufs_cntl_mmap, |
355 | }; | 470 | }; |
356 | 471 | ||
@@ -1102,33 +1217,34 @@ static const struct file_operations spufs_signal2_nosched_fops = { | |||
1102 | #define SPU_ATTR_ACQUIRE_SAVED 2 | 1217 | #define SPU_ATTR_ACQUIRE_SAVED 2 |
1103 | 1218 | ||
1104 | #define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire) \ | 1219 | #define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire) \ |
1105 | static u64 __##__get(void *data) \ | 1220 | static int __##__get(void *data, u64 *val) \ |
1106 | { \ | 1221 | { \ |
1107 | struct spu_context *ctx = data; \ | 1222 | struct spu_context *ctx = data; \ |
1108 | u64 ret; \ | ||
1109 | \ | 1223 | \ |
1110 | if (__acquire == SPU_ATTR_ACQUIRE) { \ | 1224 | if (__acquire == SPU_ATTR_ACQUIRE) { \ |
1111 | spu_acquire(ctx); \ | 1225 | spu_acquire(ctx); \ |
1112 | ret = __get(ctx); \ | 1226 | *val = __get(ctx); \ |
1113 | spu_release(ctx); \ | 1227 | spu_release(ctx); \ |
1114 | } else if (__acquire == SPU_ATTR_ACQUIRE_SAVED) { \ | 1228 | } else if (__acquire == SPU_ATTR_ACQUIRE_SAVED) { \ |
1115 | spu_acquire_saved(ctx); \ | 1229 | spu_acquire_saved(ctx); \ |
1116 | ret = __get(ctx); \ | 1230 | *val = __get(ctx); \ |
1117 | spu_release_saved(ctx); \ | 1231 | spu_release_saved(ctx); \ |
1118 | } else \ | 1232 | } else \ |
1119 | ret = __get(ctx); \ | 1233 | *val = __get(ctx); \ |
1120 | \ | 1234 | \ |
1121 | return ret; \ | 1235 | return 0; \ |
1122 | } \ | 1236 | } \ |
1123 | DEFINE_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt); | 1237 | DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt); |
1124 | 1238 | ||
1125 | static void spufs_signal1_type_set(void *data, u64 val) | 1239 | static int spufs_signal1_type_set(void *data, u64 val) |
1126 | { | 1240 | { |
1127 | struct spu_context *ctx = data; | 1241 | struct spu_context *ctx = data; |
1128 | 1242 | ||
1129 | spu_acquire(ctx); | 1243 | spu_acquire(ctx); |
1130 | ctx->ops->signal1_type_set(ctx, val); | 1244 | ctx->ops->signal1_type_set(ctx, val); |
1131 | spu_release(ctx); | 1245 | spu_release(ctx); |
1246 | |||
1247 | return 0; | ||
1132 | } | 1248 | } |
1133 | 1249 | ||
1134 | static u64 spufs_signal1_type_get(struct spu_context *ctx) | 1250 | static u64 spufs_signal1_type_get(struct spu_context *ctx) |
@@ -1139,13 +1255,15 @@ DEFINE_SPUFS_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, | |||
1139 | spufs_signal1_type_set, "%llu", SPU_ATTR_ACQUIRE); | 1255 | spufs_signal1_type_set, "%llu", SPU_ATTR_ACQUIRE); |
1140 | 1256 | ||
1141 | 1257 | ||
1142 | static void spufs_signal2_type_set(void *data, u64 val) | 1258 | static int spufs_signal2_type_set(void *data, u64 val) |
1143 | { | 1259 | { |
1144 | struct spu_context *ctx = data; | 1260 | struct spu_context *ctx = data; |
1145 | 1261 | ||
1146 | spu_acquire(ctx); | 1262 | spu_acquire(ctx); |
1147 | ctx->ops->signal2_type_set(ctx, val); | 1263 | ctx->ops->signal2_type_set(ctx, val); |
1148 | spu_release(ctx); | 1264 | spu_release(ctx); |
1265 | |||
1266 | return 0; | ||
1149 | } | 1267 | } |
1150 | 1268 | ||
1151 | static u64 spufs_signal2_type_get(struct spu_context *ctx) | 1269 | static u64 spufs_signal2_type_get(struct spu_context *ctx) |
@@ -1625,12 +1743,14 @@ static const struct file_operations spufs_mfc_fops = { | |||
1625 | .mmap = spufs_mfc_mmap, | 1743 | .mmap = spufs_mfc_mmap, |
1626 | }; | 1744 | }; |
1627 | 1745 | ||
1628 | static void spufs_npc_set(void *data, u64 val) | 1746 | static int spufs_npc_set(void *data, u64 val) |
1629 | { | 1747 | { |
1630 | struct spu_context *ctx = data; | 1748 | struct spu_context *ctx = data; |
1631 | spu_acquire(ctx); | 1749 | spu_acquire(ctx); |
1632 | ctx->ops->npc_write(ctx, val); | 1750 | ctx->ops->npc_write(ctx, val); |
1633 | spu_release(ctx); | 1751 | spu_release(ctx); |
1752 | |||
1753 | return 0; | ||
1634 | } | 1754 | } |
1635 | 1755 | ||
1636 | static u64 spufs_npc_get(struct spu_context *ctx) | 1756 | static u64 spufs_npc_get(struct spu_context *ctx) |
@@ -1640,13 +1760,15 @@ static u64 spufs_npc_get(struct spu_context *ctx) | |||
1640 | DEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, | 1760 | DEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, |
1641 | "0x%llx\n", SPU_ATTR_ACQUIRE); | 1761 | "0x%llx\n", SPU_ATTR_ACQUIRE); |
1642 | 1762 | ||
1643 | static void spufs_decr_set(void *data, u64 val) | 1763 | static int spufs_decr_set(void *data, u64 val) |
1644 | { | 1764 | { |
1645 | struct spu_context *ctx = data; | 1765 | struct spu_context *ctx = data; |
1646 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | 1766 | struct spu_lscsa *lscsa = ctx->csa.lscsa; |
1647 | spu_acquire_saved(ctx); | 1767 | spu_acquire_saved(ctx); |
1648 | lscsa->decr.slot[0] = (u32) val; | 1768 | lscsa->decr.slot[0] = (u32) val; |
1649 | spu_release_saved(ctx); | 1769 | spu_release_saved(ctx); |
1770 | |||
1771 | return 0; | ||
1650 | } | 1772 | } |
1651 | 1773 | ||
1652 | static u64 spufs_decr_get(struct spu_context *ctx) | 1774 | static u64 spufs_decr_get(struct spu_context *ctx) |
@@ -1657,7 +1779,7 @@ static u64 spufs_decr_get(struct spu_context *ctx) | |||
1657 | DEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, | 1779 | DEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, |
1658 | "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED); | 1780 | "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED); |
1659 | 1781 | ||
1660 | static void spufs_decr_status_set(void *data, u64 val) | 1782 | static int spufs_decr_status_set(void *data, u64 val) |
1661 | { | 1783 | { |
1662 | struct spu_context *ctx = data; | 1784 | struct spu_context *ctx = data; |
1663 | spu_acquire_saved(ctx); | 1785 | spu_acquire_saved(ctx); |
@@ -1666,6 +1788,8 @@ static void spufs_decr_status_set(void *data, u64 val) | |||
1666 | else | 1788 | else |
1667 | ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING; | 1789 | ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING; |
1668 | spu_release_saved(ctx); | 1790 | spu_release_saved(ctx); |
1791 | |||
1792 | return 0; | ||
1669 | } | 1793 | } |
1670 | 1794 | ||
1671 | static u64 spufs_decr_status_get(struct spu_context *ctx) | 1795 | static u64 spufs_decr_status_get(struct spu_context *ctx) |
@@ -1679,13 +1803,15 @@ DEFINE_SPUFS_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, | |||
1679 | spufs_decr_status_set, "0x%llx\n", | 1803 | spufs_decr_status_set, "0x%llx\n", |
1680 | SPU_ATTR_ACQUIRE_SAVED); | 1804 | SPU_ATTR_ACQUIRE_SAVED); |
1681 | 1805 | ||
1682 | static void spufs_event_mask_set(void *data, u64 val) | 1806 | static int spufs_event_mask_set(void *data, u64 val) |
1683 | { | 1807 | { |
1684 | struct spu_context *ctx = data; | 1808 | struct spu_context *ctx = data; |
1685 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | 1809 | struct spu_lscsa *lscsa = ctx->csa.lscsa; |
1686 | spu_acquire_saved(ctx); | 1810 | spu_acquire_saved(ctx); |
1687 | lscsa->event_mask.slot[0] = (u32) val; | 1811 | lscsa->event_mask.slot[0] = (u32) val; |
1688 | spu_release_saved(ctx); | 1812 | spu_release_saved(ctx); |
1813 | |||
1814 | return 0; | ||
1689 | } | 1815 | } |
1690 | 1816 | ||
1691 | static u64 spufs_event_mask_get(struct spu_context *ctx) | 1817 | static u64 spufs_event_mask_get(struct spu_context *ctx) |
@@ -1710,13 +1836,15 @@ static u64 spufs_event_status_get(struct spu_context *ctx) | |||
1710 | DEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, | 1836 | DEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, |
1711 | NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) | 1837 | NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) |
1712 | 1838 | ||
1713 | static void spufs_srr0_set(void *data, u64 val) | 1839 | static int spufs_srr0_set(void *data, u64 val) |
1714 | { | 1840 | { |
1715 | struct spu_context *ctx = data; | 1841 | struct spu_context *ctx = data; |
1716 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | 1842 | struct spu_lscsa *lscsa = ctx->csa.lscsa; |
1717 | spu_acquire_saved(ctx); | 1843 | spu_acquire_saved(ctx); |
1718 | lscsa->srr0.slot[0] = (u32) val; | 1844 | lscsa->srr0.slot[0] = (u32) val; |
1719 | spu_release_saved(ctx); | 1845 | spu_release_saved(ctx); |
1846 | |||
1847 | return 0; | ||
1720 | } | 1848 | } |
1721 | 1849 | ||
1722 | static u64 spufs_srr0_get(struct spu_context *ctx) | 1850 | static u64 spufs_srr0_get(struct spu_context *ctx) |
@@ -1747,10 +1875,12 @@ static u64 spufs_object_id_get(struct spu_context *ctx) | |||
1747 | return ctx->object_id; | 1875 | return ctx->object_id; |
1748 | } | 1876 | } |
1749 | 1877 | ||
1750 | static void spufs_object_id_set(void *data, u64 id) | 1878 | static int spufs_object_id_set(void *data, u64 id) |
1751 | { | 1879 | { |
1752 | struct spu_context *ctx = data; | 1880 | struct spu_context *ctx = data; |
1753 | ctx->object_id = id; | 1881 | ctx->object_id = id; |
1882 | |||
1883 | return 0; | ||
1754 | } | 1884 | } |
1755 | 1885 | ||
1756 | DEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, | 1886 | DEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, |