diff options
author | Geoff Levand <geoffrey.levand@am.sony.com> | 2007-06-15 18:01:06 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-06-28 05:16:40 -0400 |
commit | 7626e78d29651d3075e88f233c0632867ea6a35c (patch) | |
tree | 0f1d4b26d6597b9a81af2e2009ce2dae6aaabbc7 | |
parent | a3323d1a52ec5b70821590e4beaaf13c466fd396 (diff) |
[POWERPC] PS3: Vuart rework
PS3 vuart updates to reflect the new PS3 unified device support.
- Move vuart devices to the PS3 system bus.
- Replace use of ps3_vuart_port_device with ps3_system_bus_device.
- Make the PS3 vuart bus driver a loadable module.
- Add remove() and shutdown() routines.
- Move ps3_vuart_work into ps3_vuart_port_priv.tx_list.
- Remove redundant spinlock ps3_vuart_work.lock.
- No longer free ps3_vuart_port_device.priv on shutdown.
- Cleanup Kconfig defs.
- Export symbols needed for modular port drivers.
- Arrange to use port numbers found in repository.
- Fix bugs in ps3_vuart_read_async() and polled reading
- Cleanup handling of shared interrupt with ps3_vuart_bus_interrupt_get()
and ps3_vuart_bus_interrupt_put()
- Add more comments to vuart.c.
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/platforms/ps3/Kconfig | 21 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/interrupt.c | 2 | ||||
-rw-r--r-- | drivers/ps3/vuart.c | 813 | ||||
-rw-r--r-- | drivers/ps3/vuart.h | 71 | ||||
-rw-r--r-- | include/asm-powerpc/ps3.h | 17 |
5 files changed, 520 insertions, 404 deletions
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index 40f0008af4d1..b5122a764813 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig | |||
@@ -73,18 +73,12 @@ config PS3_USE_LPAR_ADDR | |||
73 | 73 | ||
74 | config PS3_VUART | 74 | config PS3_VUART |
75 | depends on PPC_PS3 | 75 | depends on PPC_PS3 |
76 | bool "PS3 Virtual UART support" if PS3_ADVANCED | 76 | tristate |
77 | default y | ||
78 | help | ||
79 | Include support for the PS3 Virtual UART. | ||
80 | |||
81 | This support is required for several system services | ||
82 | including the System Manager and AV Settings. In | ||
83 | general, all users will say Y. | ||
84 | 77 | ||
85 | config PS3_PS3AV | 78 | config PS3_PS3AV |
79 | depends on PPC_PS3 | ||
86 | tristate "PS3 AV settings driver" if PS3_ADVANCED | 80 | tristate "PS3 AV settings driver" if PS3_ADVANCED |
87 | depends on PS3_VUART | 81 | select PS3_VUART |
88 | default y | 82 | default y |
89 | help | 83 | help |
90 | Include support for the PS3 AV Settings driver. | 84 | Include support for the PS3 AV Settings driver. |
@@ -93,13 +87,14 @@ config PS3_PS3AV | |||
93 | general, all users will say Y or M. | 87 | general, all users will say Y or M. |
94 | 88 | ||
95 | config PS3_SYS_MANAGER | 89 | config PS3_SYS_MANAGER |
96 | bool "PS3 System Manager driver" if PS3_ADVANCED | 90 | depends on PPC_PS3 |
97 | depends on PS3_VUART | 91 | tristate "PS3 System Manager driver" if PS3_ADVANCED |
98 | default y | 92 | select PS3_VUART |
93 | default m | ||
99 | help | 94 | help |
100 | Include support for the PS3 System Manager. | 95 | Include support for the PS3 System Manager. |
101 | 96 | ||
102 | This support is required for system control. In | 97 | This support is required for system control. In |
103 | general, all users will say Y. | 98 | general, all users will say Y or M. |
104 | 99 | ||
105 | endmenu | 100 | endmenu |
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 51141dc06f91..99a0826c8d90 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c | |||
@@ -564,6 +564,7 @@ int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp, | |||
564 | 564 | ||
565 | return result; | 565 | return result; |
566 | } | 566 | } |
567 | EXPORT_SYMBOL_GPL(ps3_vuart_irq_setup); | ||
567 | 568 | ||
568 | int ps3_vuart_irq_destroy(unsigned int virq) | 569 | int ps3_vuart_irq_destroy(unsigned int virq) |
569 | { | 570 | { |
@@ -583,6 +584,7 @@ int ps3_vuart_irq_destroy(unsigned int virq) | |||
583 | 584 | ||
584 | return result; | 585 | return result; |
585 | } | 586 | } |
587 | EXPORT_SYMBOL_GPL(ps3_vuart_irq_destroy); | ||
586 | 588 | ||
587 | /** | 589 | /** |
588 | * ps3_spe_irq_setup - Setup an spe virq. | 590 | * ps3_spe_irq_setup - Setup an spe virq. |
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c index 5333fb2f0d86..bea25a1391ee 100644 --- a/drivers/ps3/vuart.c +++ b/drivers/ps3/vuart.c | |||
@@ -71,6 +71,34 @@ enum vuart_interrupt_mask { | |||
71 | }; | 71 | }; |
72 | 72 | ||
73 | /** | 73 | /** |
74 | * struct ps3_vuart_port_priv - private vuart device data. | ||
75 | */ | ||
76 | |||
77 | struct ps3_vuart_port_priv { | ||
78 | u64 interrupt_mask; | ||
79 | |||
80 | struct { | ||
81 | spinlock_t lock; | ||
82 | struct list_head head; | ||
83 | } tx_list; | ||
84 | struct { | ||
85 | struct ps3_vuart_work work; | ||
86 | unsigned long bytes_held; | ||
87 | spinlock_t lock; | ||
88 | struct list_head head; | ||
89 | } rx_list; | ||
90 | struct ps3_vuart_stats stats; | ||
91 | }; | ||
92 | |||
93 | static struct ps3_vuart_port_priv *to_port_priv( | ||
94 | struct ps3_system_bus_device *dev) | ||
95 | { | ||
96 | BUG_ON(!dev); | ||
97 | BUG_ON(!dev->driver_priv); | ||
98 | return (struct ps3_vuart_port_priv *)dev->driver_priv; | ||
99 | } | ||
100 | |||
101 | /** | ||
74 | * struct ports_bmp - bitmap indicating ports needing service. | 102 | * struct ports_bmp - bitmap indicating ports needing service. |
75 | * | 103 | * |
76 | * A 256 bit read only bitmap indicating ports needing service. Do not write | 104 | * A 256 bit read only bitmap indicating ports needing service. Do not write |
@@ -89,23 +117,6 @@ static void __maybe_unused _dump_ports_bmp( | |||
89 | pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status); | 117 | pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status); |
90 | } | 118 | } |
91 | 119 | ||
92 | static int ps3_vuart_match_id_to_port(enum ps3_match_id match_id, | ||
93 | unsigned int *port_number) | ||
94 | { | ||
95 | switch(match_id) { | ||
96 | case PS3_MATCH_ID_AV_SETTINGS: | ||
97 | *port_number = 0; | ||
98 | return 0; | ||
99 | case PS3_MATCH_ID_SYSTEM_MANAGER: | ||
100 | *port_number = 2; | ||
101 | return 0; | ||
102 | default: | ||
103 | WARN_ON(1); | ||
104 | *port_number = UINT_MAX; | ||
105 | return -EINVAL; | ||
106 | }; | ||
107 | } | ||
108 | |||
109 | #define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__) | 120 | #define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__) |
110 | static void __maybe_unused _dump_port_params(unsigned int port_number, | 121 | static void __maybe_unused _dump_port_params(unsigned int port_number, |
111 | const char* func, int line) | 122 | const char* func, int line) |
@@ -144,14 +155,14 @@ struct vuart_triggers { | |||
144 | unsigned long tx; | 155 | unsigned long tx; |
145 | }; | 156 | }; |
146 | 157 | ||
147 | int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, | 158 | int ps3_vuart_get_triggers(struct ps3_system_bus_device *dev, |
148 | struct vuart_triggers *trig) | 159 | struct vuart_triggers *trig) |
149 | { | 160 | { |
150 | int result; | 161 | int result; |
151 | unsigned long size; | 162 | unsigned long size; |
152 | unsigned long val; | 163 | unsigned long val; |
153 | 164 | ||
154 | result = lv1_get_virtual_uart_param(dev->priv->port_number, | 165 | result = lv1_get_virtual_uart_param(dev->port_number, |
155 | PARAM_TX_TRIGGER, &trig->tx); | 166 | PARAM_TX_TRIGGER, &trig->tx); |
156 | 167 | ||
157 | if (result) { | 168 | if (result) { |
@@ -160,7 +171,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, | |||
160 | return result; | 171 | return result; |
161 | } | 172 | } |
162 | 173 | ||
163 | result = lv1_get_virtual_uart_param(dev->priv->port_number, | 174 | result = lv1_get_virtual_uart_param(dev->port_number, |
164 | PARAM_RX_BUF_SIZE, &size); | 175 | PARAM_RX_BUF_SIZE, &size); |
165 | 176 | ||
166 | if (result) { | 177 | if (result) { |
@@ -169,7 +180,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, | |||
169 | return result; | 180 | return result; |
170 | } | 181 | } |
171 | 182 | ||
172 | result = lv1_get_virtual_uart_param(dev->priv->port_number, | 183 | result = lv1_get_virtual_uart_param(dev->port_number, |
173 | PARAM_RX_TRIGGER, &val); | 184 | PARAM_RX_TRIGGER, &val); |
174 | 185 | ||
175 | if (result) { | 186 | if (result) { |
@@ -186,13 +197,13 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, | |||
186 | return result; | 197 | return result; |
187 | } | 198 | } |
188 | 199 | ||
189 | int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, | 200 | int ps3_vuart_set_triggers(struct ps3_system_bus_device *dev, unsigned int tx, |
190 | unsigned int rx) | 201 | unsigned int rx) |
191 | { | 202 | { |
192 | int result; | 203 | int result; |
193 | unsigned long size; | 204 | unsigned long size; |
194 | 205 | ||
195 | result = lv1_set_virtual_uart_param(dev->priv->port_number, | 206 | result = lv1_set_virtual_uart_param(dev->port_number, |
196 | PARAM_TX_TRIGGER, tx); | 207 | PARAM_TX_TRIGGER, tx); |
197 | 208 | ||
198 | if (result) { | 209 | if (result) { |
@@ -201,7 +212,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, | |||
201 | return result; | 212 | return result; |
202 | } | 213 | } |
203 | 214 | ||
204 | result = lv1_get_virtual_uart_param(dev->priv->port_number, | 215 | result = lv1_get_virtual_uart_param(dev->port_number, |
205 | PARAM_RX_BUF_SIZE, &size); | 216 | PARAM_RX_BUF_SIZE, &size); |
206 | 217 | ||
207 | if (result) { | 218 | if (result) { |
@@ -210,7 +221,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, | |||
210 | return result; | 221 | return result; |
211 | } | 222 | } |
212 | 223 | ||
213 | result = lv1_set_virtual_uart_param(dev->priv->port_number, | 224 | result = lv1_set_virtual_uart_param(dev->port_number, |
214 | PARAM_RX_TRIGGER, size - rx); | 225 | PARAM_RX_TRIGGER, size - rx); |
215 | 226 | ||
216 | if (result) { | 227 | if (result) { |
@@ -225,10 +236,12 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, | |||
225 | return result; | 236 | return result; |
226 | } | 237 | } |
227 | 238 | ||
228 | static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev, | 239 | static int ps3_vuart_get_rx_bytes_waiting(struct ps3_system_bus_device *dev, |
229 | u64 *bytes_waiting) | 240 | u64 *bytes_waiting) |
230 | { | 241 | { |
231 | int result = lv1_get_virtual_uart_param(dev->priv->port_number, | 242 | int result; |
243 | |||
244 | result = lv1_get_virtual_uart_param(dev->port_number, | ||
232 | PARAM_RX_BYTES, bytes_waiting); | 245 | PARAM_RX_BYTES, bytes_waiting); |
233 | 246 | ||
234 | if (result) | 247 | if (result) |
@@ -240,17 +253,24 @@ static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev, | |||
240 | return result; | 253 | return result; |
241 | } | 254 | } |
242 | 255 | ||
243 | static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev, | 256 | /** |
257 | * ps3_vuart_set_interrupt_mask - Enable/disable the port interrupt sources. | ||
258 | * @dev: The struct ps3_system_bus_device instance. | ||
259 | * @bmp: Logical OR of enum vuart_interrupt_mask values. A zero bit disables. | ||
260 | */ | ||
261 | |||
262 | static int ps3_vuart_set_interrupt_mask(struct ps3_system_bus_device *dev, | ||
244 | unsigned long mask) | 263 | unsigned long mask) |
245 | { | 264 | { |
246 | int result; | 265 | int result; |
266 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
247 | 267 | ||
248 | dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask); | 268 | dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask); |
249 | 269 | ||
250 | dev->priv->interrupt_mask = mask; | 270 | priv->interrupt_mask = mask; |
251 | 271 | ||
252 | result = lv1_set_virtual_uart_param(dev->priv->port_number, | 272 | result = lv1_set_virtual_uart_param(dev->port_number, |
253 | PARAM_INTERRUPT_MASK, dev->priv->interrupt_mask); | 273 | PARAM_INTERRUPT_MASK, priv->interrupt_mask); |
254 | 274 | ||
255 | if (result) | 275 | if (result) |
256 | dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n", | 276 | dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n", |
@@ -259,79 +279,96 @@ static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev, | |||
259 | return result; | 279 | return result; |
260 | } | 280 | } |
261 | 281 | ||
262 | static int ps3_vuart_get_interrupt_status(struct ps3_vuart_port_device *dev, | 282 | static int ps3_vuart_get_interrupt_status(struct ps3_system_bus_device *dev, |
263 | unsigned long *status) | 283 | unsigned long *status) |
264 | { | 284 | { |
285 | int result; | ||
286 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
265 | u64 tmp; | 287 | u64 tmp; |
266 | int result = lv1_get_virtual_uart_param(dev->priv->port_number, | 288 | |
289 | result = lv1_get_virtual_uart_param(dev->port_number, | ||
267 | PARAM_INTERRUPT_STATUS, &tmp); | 290 | PARAM_INTERRUPT_STATUS, &tmp); |
268 | 291 | ||
269 | if (result) | 292 | if (result) |
270 | dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n", | 293 | dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n", |
271 | __func__, __LINE__, ps3_result(result)); | 294 | __func__, __LINE__, ps3_result(result)); |
272 | 295 | ||
273 | *status = tmp & dev->priv->interrupt_mask; | 296 | *status = tmp & priv->interrupt_mask; |
274 | 297 | ||
275 | dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n", | 298 | dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n", |
276 | __func__, __LINE__, dev->priv->interrupt_mask, tmp, *status); | 299 | __func__, __LINE__, priv->interrupt_mask, tmp, *status); |
277 | 300 | ||
278 | return result; | 301 | return result; |
279 | } | 302 | } |
280 | 303 | ||
281 | int ps3_vuart_enable_interrupt_tx(struct ps3_vuart_port_device *dev) | 304 | int ps3_vuart_enable_interrupt_tx(struct ps3_system_bus_device *dev) |
282 | { | 305 | { |
283 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_TX) ? 0 | 306 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
284 | : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | 307 | |
308 | return (priv->interrupt_mask & INTERRUPT_MASK_TX) ? 0 | ||
309 | : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask | ||
285 | | INTERRUPT_MASK_TX); | 310 | | INTERRUPT_MASK_TX); |
286 | } | 311 | } |
287 | 312 | ||
288 | int ps3_vuart_enable_interrupt_rx(struct ps3_vuart_port_device *dev) | 313 | int ps3_vuart_enable_interrupt_rx(struct ps3_system_bus_device *dev) |
289 | { | 314 | { |
290 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_RX) ? 0 | 315 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
291 | : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | 316 | |
317 | return (priv->interrupt_mask & INTERRUPT_MASK_RX) ? 0 | ||
318 | : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask | ||
292 | | INTERRUPT_MASK_RX); | 319 | | INTERRUPT_MASK_RX); |
293 | } | 320 | } |
294 | 321 | ||
295 | int ps3_vuart_enable_interrupt_disconnect(struct ps3_vuart_port_device *dev) | 322 | int ps3_vuart_enable_interrupt_disconnect(struct ps3_system_bus_device *dev) |
296 | { | 323 | { |
297 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0 | 324 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
298 | : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | 325 | |
326 | return (priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0 | ||
327 | : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask | ||
299 | | INTERRUPT_MASK_DISCONNECT); | 328 | | INTERRUPT_MASK_DISCONNECT); |
300 | } | 329 | } |
301 | 330 | ||
302 | int ps3_vuart_disable_interrupt_tx(struct ps3_vuart_port_device *dev) | 331 | int ps3_vuart_disable_interrupt_tx(struct ps3_system_bus_device *dev) |
303 | { | 332 | { |
304 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_TX) | 333 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
305 | ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | 334 | |
335 | return (priv->interrupt_mask & INTERRUPT_MASK_TX) | ||
336 | ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask | ||
306 | & ~INTERRUPT_MASK_TX) : 0; | 337 | & ~INTERRUPT_MASK_TX) : 0; |
307 | } | 338 | } |
308 | 339 | ||
309 | int ps3_vuart_disable_interrupt_rx(struct ps3_vuart_port_device *dev) | 340 | int ps3_vuart_disable_interrupt_rx(struct ps3_system_bus_device *dev) |
310 | { | 341 | { |
311 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_RX) | 342 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
312 | ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | 343 | |
344 | return (priv->interrupt_mask & INTERRUPT_MASK_RX) | ||
345 | ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask | ||
313 | & ~INTERRUPT_MASK_RX) : 0; | 346 | & ~INTERRUPT_MASK_RX) : 0; |
314 | } | 347 | } |
315 | 348 | ||
316 | int ps3_vuart_disable_interrupt_disconnect(struct ps3_vuart_port_device *dev) | 349 | int ps3_vuart_disable_interrupt_disconnect(struct ps3_system_bus_device *dev) |
317 | { | 350 | { |
318 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) | 351 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
319 | ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | 352 | |
353 | return (priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) | ||
354 | ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask | ||
320 | & ~INTERRUPT_MASK_DISCONNECT) : 0; | 355 | & ~INTERRUPT_MASK_DISCONNECT) : 0; |
321 | } | 356 | } |
322 | 357 | ||
323 | /** | 358 | /** |
324 | * ps3_vuart_raw_write - Low level write helper. | 359 | * ps3_vuart_raw_write - Low level write helper. |
360 | * @dev: The struct ps3_system_bus_device instance. | ||
325 | * | 361 | * |
326 | * Do not call ps3_vuart_raw_write directly, use ps3_vuart_write. | 362 | * Do not call ps3_vuart_raw_write directly, use ps3_vuart_write. |
327 | */ | 363 | */ |
328 | 364 | ||
329 | static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev, | 365 | static int ps3_vuart_raw_write(struct ps3_system_bus_device *dev, |
330 | const void* buf, unsigned int bytes, unsigned long *bytes_written) | 366 | const void* buf, unsigned int bytes, unsigned long *bytes_written) |
331 | { | 367 | { |
332 | int result; | 368 | int result; |
369 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
333 | 370 | ||
334 | result = lv1_write_virtual_uart(dev->priv->port_number, | 371 | result = lv1_write_virtual_uart(dev->port_number, |
335 | ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written); | 372 | ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written); |
336 | 373 | ||
337 | if (result) { | 374 | if (result) { |
@@ -340,28 +377,30 @@ static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev, | |||
340 | return result; | 377 | return result; |
341 | } | 378 | } |
342 | 379 | ||
343 | dev->priv->stats.bytes_written += *bytes_written; | 380 | priv->stats.bytes_written += *bytes_written; |
344 | 381 | ||
345 | dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__, __LINE__, | 382 | dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__, __LINE__, |
346 | *bytes_written, bytes, dev->priv->stats.bytes_written); | 383 | *bytes_written, bytes, priv->stats.bytes_written); |
347 | 384 | ||
348 | return result; | 385 | return result; |
349 | } | 386 | } |
350 | 387 | ||
351 | /** | 388 | /** |
352 | * ps3_vuart_raw_read - Low level read helper. | 389 | * ps3_vuart_raw_read - Low level read helper. |
390 | * @dev: The struct ps3_system_bus_device instance. | ||
353 | * | 391 | * |
354 | * Do not call ps3_vuart_raw_read directly, use ps3_vuart_read. | 392 | * Do not call ps3_vuart_raw_read directly, use ps3_vuart_read. |
355 | */ | 393 | */ |
356 | 394 | ||
357 | static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf, | 395 | static int ps3_vuart_raw_read(struct ps3_system_bus_device *dev, void *buf, |
358 | unsigned int bytes, unsigned long *bytes_read) | 396 | unsigned int bytes, unsigned long *bytes_read) |
359 | { | 397 | { |
360 | int result; | 398 | int result; |
399 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
361 | 400 | ||
362 | dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes); | 401 | dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes); |
363 | 402 | ||
364 | result = lv1_read_virtual_uart(dev->priv->port_number, | 403 | result = lv1_read_virtual_uart(dev->port_number, |
365 | ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read); | 404 | ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read); |
366 | 405 | ||
367 | if (result) { | 406 | if (result) { |
@@ -370,25 +409,27 @@ static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf, | |||
370 | return result; | 409 | return result; |
371 | } | 410 | } |
372 | 411 | ||
373 | dev->priv->stats.bytes_read += *bytes_read; | 412 | priv->stats.bytes_read += *bytes_read; |
374 | 413 | ||
375 | dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__, | 414 | dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__, |
376 | *bytes_read, bytes, dev->priv->stats.bytes_read); | 415 | *bytes_read, bytes, priv->stats.bytes_read); |
377 | 416 | ||
378 | return result; | 417 | return result; |
379 | } | 418 | } |
380 | 419 | ||
381 | /** | 420 | /** |
382 | * ps3_vuart_clear_rx_bytes - Discard bytes received. | 421 | * ps3_vuart_clear_rx_bytes - Discard bytes received. |
422 | * @dev: The struct ps3_system_bus_device instance. | ||
383 | * @bytes: Max byte count to discard, zero = all pending. | 423 | * @bytes: Max byte count to discard, zero = all pending. |
384 | * | 424 | * |
385 | * Used to clear pending rx interrupt source. Will not block. | 425 | * Used to clear pending rx interrupt source. Will not block. |
386 | */ | 426 | */ |
387 | 427 | ||
388 | void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev, | 428 | void ps3_vuart_clear_rx_bytes(struct ps3_system_bus_device *dev, |
389 | unsigned int bytes) | 429 | unsigned int bytes) |
390 | { | 430 | { |
391 | int result; | 431 | int result; |
432 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
392 | u64 bytes_waiting; | 433 | u64 bytes_waiting; |
393 | void* tmp; | 434 | void* tmp; |
394 | 435 | ||
@@ -418,8 +459,9 @@ void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev, | |||
418 | 459 | ||
419 | /* Don't include these bytes in the stats. */ | 460 | /* Don't include these bytes in the stats. */ |
420 | 461 | ||
421 | dev->priv->stats.bytes_read -= bytes_waiting; | 462 | priv->stats.bytes_read -= bytes_waiting; |
422 | } | 463 | } |
464 | EXPORT_SYMBOL_GPL(ps3_vuart_clear_rx_bytes); | ||
423 | 465 | ||
424 | /** | 466 | /** |
425 | * struct list_buffer - An element for a port device fifo buffer list. | 467 | * struct list_buffer - An element for a port device fifo buffer list. |
@@ -435,6 +477,7 @@ struct list_buffer { | |||
435 | 477 | ||
436 | /** | 478 | /** |
437 | * ps3_vuart_write - the entry point for writing data to a port | 479 | * ps3_vuart_write - the entry point for writing data to a port |
480 | * @dev: The struct ps3_system_bus_device instance. | ||
438 | * | 481 | * |
439 | * If the port is idle on entry as much of the incoming data is written to | 482 | * If the port is idle on entry as much of the incoming data is written to |
440 | * the port as the port will accept. Otherwise a list buffer is created | 483 | * the port as the port will accept. Otherwise a list buffer is created |
@@ -442,25 +485,26 @@ struct list_buffer { | |||
442 | * then enqueued for transmision via the transmit interrupt. | 485 | * then enqueued for transmision via the transmit interrupt. |
443 | */ | 486 | */ |
444 | 487 | ||
445 | int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, | 488 | int ps3_vuart_write(struct ps3_system_bus_device *dev, const void *buf, |
446 | unsigned int bytes) | 489 | unsigned int bytes) |
447 | { | 490 | { |
448 | static unsigned long dbg_number; | 491 | static unsigned long dbg_number; |
449 | int result; | 492 | int result; |
493 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
450 | unsigned long flags; | 494 | unsigned long flags; |
451 | struct list_buffer *lb; | 495 | struct list_buffer *lb; |
452 | 496 | ||
453 | dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, | 497 | dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, |
454 | bytes, bytes); | 498 | bytes, bytes); |
455 | 499 | ||
456 | spin_lock_irqsave(&dev->priv->tx_list.lock, flags); | 500 | spin_lock_irqsave(&priv->tx_list.lock, flags); |
457 | 501 | ||
458 | if (list_empty(&dev->priv->tx_list.head)) { | 502 | if (list_empty(&priv->tx_list.head)) { |
459 | unsigned long bytes_written; | 503 | unsigned long bytes_written; |
460 | 504 | ||
461 | result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written); | 505 | result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written); |
462 | 506 | ||
463 | spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); | 507 | spin_unlock_irqrestore(&priv->tx_list.lock, flags); |
464 | 508 | ||
465 | if (result) { | 509 | if (result) { |
466 | dev_dbg(&dev->core, | 510 | dev_dbg(&dev->core, |
@@ -478,7 +522,7 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, | |||
478 | bytes -= bytes_written; | 522 | bytes -= bytes_written; |
479 | buf += bytes_written; | 523 | buf += bytes_written; |
480 | } else | 524 | } else |
481 | spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); | 525 | spin_unlock_irqrestore(&priv->tx_list.lock, flags); |
482 | 526 | ||
483 | lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL); | 527 | lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL); |
484 | 528 | ||
@@ -491,29 +535,86 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, | |||
491 | lb->tail = lb->data + bytes; | 535 | lb->tail = lb->data + bytes; |
492 | lb->dbg_number = ++dbg_number; | 536 | lb->dbg_number = ++dbg_number; |
493 | 537 | ||
494 | spin_lock_irqsave(&dev->priv->tx_list.lock, flags); | 538 | spin_lock_irqsave(&priv->tx_list.lock, flags); |
495 | list_add_tail(&lb->link, &dev->priv->tx_list.head); | 539 | list_add_tail(&lb->link, &priv->tx_list.head); |
496 | ps3_vuart_enable_interrupt_tx(dev); | 540 | ps3_vuart_enable_interrupt_tx(dev); |
497 | spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); | 541 | spin_unlock_irqrestore(&priv->tx_list.lock, flags); |
498 | 542 | ||
499 | dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n", | 543 | dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n", |
500 | __func__, __LINE__, lb->dbg_number, bytes); | 544 | __func__, __LINE__, lb->dbg_number, bytes); |
501 | 545 | ||
502 | return 0; | 546 | return 0; |
503 | } | 547 | } |
548 | EXPORT_SYMBOL_GPL(ps3_vuart_write); | ||
549 | |||
550 | /** | ||
551 | * ps3_vuart_queue_rx_bytes - Queue waiting bytes into the buffer list. | ||
552 | * @dev: The struct ps3_system_bus_device instance. | ||
553 | * @bytes_queued: Number of bytes queued to the buffer list. | ||
554 | * | ||
555 | * Must be called with priv->rx_list.lock held. | ||
556 | */ | ||
557 | |||
558 | static int ps3_vuart_queue_rx_bytes(struct ps3_system_bus_device *dev, | ||
559 | u64 *bytes_queued) | ||
560 | { | ||
561 | static unsigned long dbg_number; | ||
562 | int result; | ||
563 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
564 | struct list_buffer *lb; | ||
565 | u64 bytes; | ||
566 | |||
567 | *bytes_queued = 0; | ||
568 | |||
569 | result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes); | ||
570 | BUG_ON(result); | ||
571 | |||
572 | if (result) | ||
573 | return -EIO; | ||
574 | |||
575 | if (!bytes) | ||
576 | return 0; | ||
577 | |||
578 | /* Add some extra space for recently arrived data. */ | ||
579 | |||
580 | bytes += 128; | ||
581 | |||
582 | lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_ATOMIC); | ||
583 | |||
584 | if (!lb) | ||
585 | return -ENOMEM; | ||
586 | |||
587 | ps3_vuart_raw_read(dev, lb->data, bytes, &bytes); | ||
588 | |||
589 | lb->head = lb->data; | ||
590 | lb->tail = lb->data + bytes; | ||
591 | lb->dbg_number = ++dbg_number; | ||
592 | |||
593 | list_add_tail(&lb->link, &priv->rx_list.head); | ||
594 | priv->rx_list.bytes_held += bytes; | ||
595 | |||
596 | dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n", | ||
597 | __func__, __LINE__, lb->dbg_number, bytes); | ||
598 | |||
599 | *bytes_queued = bytes; | ||
600 | |||
601 | return 0; | ||
602 | } | ||
504 | 603 | ||
505 | /** | 604 | /** |
506 | * ps3_vuart_read - the entry point for reading data from a port | 605 | * ps3_vuart_read - The entry point for reading data from a port. |
507 | * | 606 | * |
508 | * If enough bytes to satisfy the request are held in the buffer list those | 607 | * Queue data waiting at the port, and if enough bytes to satisfy the request |
509 | * bytes are dequeued and copied to the caller's buffer. Emptied list buffers | 608 | * are held in the buffer list those bytes are dequeued and copied to the |
510 | * are retiered. If the request cannot be statified by bytes held in the list | 609 | * caller's buffer. Emptied list buffers are retiered. If the request cannot |
511 | * buffers -EAGAIN is returned. | 610 | * be statified by bytes held in the list buffers -EAGAIN is returned. |
512 | */ | 611 | */ |
513 | 612 | ||
514 | int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, | 613 | int ps3_vuart_read(struct ps3_system_bus_device *dev, void *buf, |
515 | unsigned int bytes) | 614 | unsigned int bytes) |
516 | { | 615 | { |
616 | int result; | ||
617 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
517 | unsigned long flags; | 618 | unsigned long flags; |
518 | struct list_buffer *lb, *n; | 619 | struct list_buffer *lb, *n; |
519 | unsigned long bytes_read; | 620 | unsigned long bytes_read; |
@@ -521,30 +622,37 @@ int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, | |||
521 | dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, | 622 | dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, |
522 | bytes, bytes); | 623 | bytes, bytes); |
523 | 624 | ||
524 | spin_lock_irqsave(&dev->priv->rx_list.lock, flags); | 625 | spin_lock_irqsave(&priv->rx_list.lock, flags); |
525 | 626 | ||
526 | if (dev->priv->rx_list.bytes_held < bytes) { | 627 | /* Queue rx bytes here for polled reads. */ |
527 | spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); | 628 | |
528 | dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n", | 629 | while (priv->rx_list.bytes_held < bytes) { |
529 | __func__, __LINE__, | 630 | u64 tmp; |
530 | bytes - dev->priv->rx_list.bytes_held); | 631 | |
531 | return -EAGAIN; | 632 | result = ps3_vuart_queue_rx_bytes(dev, &tmp); |
633 | if (result || !tmp) { | ||
634 | dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n", | ||
635 | __func__, __LINE__, | ||
636 | bytes - priv->rx_list.bytes_held); | ||
637 | spin_unlock_irqrestore(&priv->rx_list.lock, flags); | ||
638 | return -EAGAIN; | ||
639 | } | ||
532 | } | 640 | } |
533 | 641 | ||
534 | list_for_each_entry_safe(lb, n, &dev->priv->rx_list.head, link) { | 642 | list_for_each_entry_safe(lb, n, &priv->rx_list.head, link) { |
535 | bytes_read = min((unsigned int)(lb->tail - lb->head), bytes); | 643 | bytes_read = min((unsigned int)(lb->tail - lb->head), bytes); |
536 | 644 | ||
537 | memcpy(buf, lb->head, bytes_read); | 645 | memcpy(buf, lb->head, bytes_read); |
538 | buf += bytes_read; | 646 | buf += bytes_read; |
539 | bytes -= bytes_read; | 647 | bytes -= bytes_read; |
540 | dev->priv->rx_list.bytes_held -= bytes_read; | 648 | priv->rx_list.bytes_held -= bytes_read; |
541 | 649 | ||
542 | if (bytes_read < lb->tail - lb->head) { | 650 | if (bytes_read < lb->tail - lb->head) { |
543 | lb->head += bytes_read; | 651 | lb->head += bytes_read; |
544 | dev_dbg(&dev->core, "%s:%d: buf_%lu: dequeued %lxh " | 652 | dev_dbg(&dev->core, "%s:%d: buf_%lu: dequeued %lxh " |
545 | "bytes\n", __func__, __LINE__, lb->dbg_number, | 653 | "bytes\n", __func__, __LINE__, lb->dbg_number, |
546 | bytes_read); | 654 | bytes_read); |
547 | spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); | 655 | spin_unlock_irqrestore(&priv->rx_list.lock, flags); |
548 | return 0; | 656 | return 0; |
549 | } | 657 | } |
550 | 658 | ||
@@ -556,16 +664,32 @@ int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, | |||
556 | kfree(lb); | 664 | kfree(lb); |
557 | } | 665 | } |
558 | 666 | ||
559 | spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); | 667 | spin_unlock_irqrestore(&priv->rx_list.lock, flags); |
560 | return 0; | 668 | return 0; |
561 | } | 669 | } |
670 | EXPORT_SYMBOL_GPL(ps3_vuart_read); | ||
562 | 671 | ||
563 | int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func, | 672 | /** |
564 | unsigned int bytes) | 673 | * ps3_vuart_work - Asynchronous read handler. |
674 | */ | ||
675 | |||
676 | static void ps3_vuart_work(struct work_struct *work) | ||
677 | { | ||
678 | struct ps3_system_bus_device *dev = | ||
679 | ps3_vuart_work_to_system_bus_dev(work); | ||
680 | struct ps3_vuart_port_driver *drv = | ||
681 | ps3_system_bus_dev_to_vuart_drv(dev); | ||
682 | |||
683 | BUG_ON(!drv); | ||
684 | drv->work(dev); | ||
685 | } | ||
686 | |||
687 | int ps3_vuart_read_async(struct ps3_system_bus_device *dev, unsigned int bytes) | ||
565 | { | 688 | { |
689 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
566 | unsigned long flags; | 690 | unsigned long flags; |
567 | 691 | ||
568 | if(dev->priv->work.trigger) { | 692 | if (priv->rx_list.work.trigger) { |
569 | dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n", | 693 | dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n", |
570 | __func__, __LINE__); | 694 | __func__, __LINE__); |
571 | return -EAGAIN; | 695 | return -EAGAIN; |
@@ -573,30 +697,32 @@ int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func, | |||
573 | 697 | ||
574 | BUG_ON(!bytes); | 698 | BUG_ON(!bytes); |
575 | 699 | ||
576 | PREPARE_WORK(&dev->priv->work.work, func); | 700 | PREPARE_WORK(&priv->rx_list.work.work, ps3_vuart_work); |
577 | 701 | ||
578 | spin_lock_irqsave(&dev->priv->work.lock, flags); | 702 | spin_lock_irqsave(&priv->rx_list.lock, flags); |
579 | if(dev->priv->rx_list.bytes_held >= bytes) { | 703 | if (priv->rx_list.bytes_held >= bytes) { |
580 | dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n", | 704 | dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n", |
581 | __func__, __LINE__, bytes); | 705 | __func__, __LINE__, bytes); |
582 | schedule_work(&dev->priv->work.work); | 706 | schedule_work(&priv->rx_list.work.work); |
583 | spin_unlock_irqrestore(&dev->priv->work.lock, flags); | 707 | spin_unlock_irqrestore(&priv->rx_list.lock, flags); |
584 | return 0; | 708 | return 0; |
585 | } | 709 | } |
586 | 710 | ||
587 | dev->priv->work.trigger = bytes; | 711 | priv->rx_list.work.trigger = bytes; |
588 | spin_unlock_irqrestore(&dev->priv->work.lock, flags); | 712 | spin_unlock_irqrestore(&priv->rx_list.lock, flags); |
589 | 713 | ||
590 | dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__, | 714 | dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__, |
591 | __LINE__, bytes, bytes); | 715 | __LINE__, bytes, bytes); |
592 | 716 | ||
593 | return 0; | 717 | return 0; |
594 | } | 718 | } |
719 | EXPORT_SYMBOL_GPL(ps3_vuart_read_async); | ||
595 | 720 | ||
596 | void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev) | 721 | void ps3_vuart_cancel_async(struct ps3_system_bus_device *dev) |
597 | { | 722 | { |
598 | dev->priv->work.trigger = 0; | 723 | to_port_priv(dev)->rx_list.work.trigger = 0; |
599 | } | 724 | } |
725 | EXPORT_SYMBOL_GPL(ps3_vuart_cancel_async); | ||
600 | 726 | ||
601 | /** | 727 | /** |
602 | * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler | 728 | * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler |
@@ -606,18 +732,19 @@ void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev) | |||
606 | * adjusts the final list buffer state for a partial write. | 732 | * adjusts the final list buffer state for a partial write. |
607 | */ | 733 | */ |
608 | 734 | ||
609 | static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev) | 735 | static int ps3_vuart_handle_interrupt_tx(struct ps3_system_bus_device *dev) |
610 | { | 736 | { |
611 | int result = 0; | 737 | int result = 0; |
738 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
612 | unsigned long flags; | 739 | unsigned long flags; |
613 | struct list_buffer *lb, *n; | 740 | struct list_buffer *lb, *n; |
614 | unsigned long bytes_total = 0; | 741 | unsigned long bytes_total = 0; |
615 | 742 | ||
616 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 743 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
617 | 744 | ||
618 | spin_lock_irqsave(&dev->priv->tx_list.lock, flags); | 745 | spin_lock_irqsave(&priv->tx_list.lock, flags); |
619 | 746 | ||
620 | list_for_each_entry_safe(lb, n, &dev->priv->tx_list.head, link) { | 747 | list_for_each_entry_safe(lb, n, &priv->tx_list.head, link) { |
621 | 748 | ||
622 | unsigned long bytes_written; | 749 | unsigned long bytes_written; |
623 | 750 | ||
@@ -651,7 +778,7 @@ static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev) | |||
651 | 778 | ||
652 | ps3_vuart_disable_interrupt_tx(dev); | 779 | ps3_vuart_disable_interrupt_tx(dev); |
653 | port_full: | 780 | port_full: |
654 | spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); | 781 | spin_unlock_irqrestore(&priv->tx_list.lock, flags); |
655 | dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n", | 782 | dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n", |
656 | __func__, __LINE__, bytes_total); | 783 | __func__, __LINE__, bytes_total); |
657 | return result; | 784 | return result; |
@@ -665,60 +792,37 @@ port_full: | |||
665 | * buffer list. Buffer list data is dequeued via ps3_vuart_read. | 792 | * buffer list. Buffer list data is dequeued via ps3_vuart_read. |
666 | */ | 793 | */ |
667 | 794 | ||
668 | static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev) | 795 | static int ps3_vuart_handle_interrupt_rx(struct ps3_system_bus_device *dev) |
669 | { | 796 | { |
670 | static unsigned long dbg_number; | 797 | int result; |
671 | int result = 0; | 798 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
672 | unsigned long flags; | 799 | unsigned long flags; |
673 | struct list_buffer *lb; | 800 | u64 bytes; |
674 | unsigned long bytes; | ||
675 | 801 | ||
676 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 802 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
677 | 803 | ||
678 | result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes); | 804 | spin_lock_irqsave(&priv->rx_list.lock, flags); |
679 | 805 | result = ps3_vuart_queue_rx_bytes(dev, &bytes); | |
680 | if (result) | ||
681 | return -EIO; | ||
682 | |||
683 | BUG_ON(!bytes); | ||
684 | |||
685 | /* Add some extra space for recently arrived data. */ | ||
686 | |||
687 | bytes += 128; | ||
688 | |||
689 | lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_ATOMIC); | ||
690 | 806 | ||
691 | if (!lb) | 807 | if (result) { |
692 | return -ENOMEM; | 808 | spin_unlock_irqrestore(&priv->rx_list.lock, flags); |
693 | 809 | return result; | |
694 | ps3_vuart_raw_read(dev, lb->data, bytes, &bytes); | 810 | } |
695 | |||
696 | lb->head = lb->data; | ||
697 | lb->tail = lb->data + bytes; | ||
698 | lb->dbg_number = ++dbg_number; | ||
699 | |||
700 | spin_lock_irqsave(&dev->priv->rx_list.lock, flags); | ||
701 | list_add_tail(&lb->link, &dev->priv->rx_list.head); | ||
702 | dev->priv->rx_list.bytes_held += bytes; | ||
703 | spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); | ||
704 | |||
705 | dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n", | ||
706 | __func__, __LINE__, lb->dbg_number, bytes); | ||
707 | 811 | ||
708 | spin_lock_irqsave(&dev->priv->work.lock, flags); | 812 | if (priv->rx_list.work.trigger && priv->rx_list.bytes_held |
709 | if(dev->priv->work.trigger | 813 | >= priv->rx_list.work.trigger) { |
710 | && dev->priv->rx_list.bytes_held >= dev->priv->work.trigger) { | ||
711 | dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n", | 814 | dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n", |
712 | __func__, __LINE__, dev->priv->work.trigger); | 815 | __func__, __LINE__, priv->rx_list.work.trigger); |
713 | dev->priv->work.trigger = 0; | 816 | priv->rx_list.work.trigger = 0; |
714 | schedule_work(&dev->priv->work.work); | 817 | schedule_work(&priv->rx_list.work.work); |
715 | } | 818 | } |
716 | spin_unlock_irqrestore(&dev->priv->work.lock, flags); | 819 | |
717 | return 0; | 820 | spin_unlock_irqrestore(&priv->rx_list.lock, flags); |
821 | return result; | ||
718 | } | 822 | } |
719 | 823 | ||
720 | static int ps3_vuart_handle_interrupt_disconnect( | 824 | static int ps3_vuart_handle_interrupt_disconnect( |
721 | struct ps3_vuart_port_device *dev) | 825 | struct ps3_system_bus_device *dev) |
722 | { | 826 | { |
723 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 827 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
724 | BUG_ON("no support"); | 828 | BUG_ON("no support"); |
@@ -733,9 +837,10 @@ static int ps3_vuart_handle_interrupt_disconnect( | |||
733 | * stage handler after one iteration. | 837 | * stage handler after one iteration. |
734 | */ | 838 | */ |
735 | 839 | ||
736 | static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) | 840 | static int ps3_vuart_handle_port_interrupt(struct ps3_system_bus_device *dev) |
737 | { | 841 | { |
738 | int result; | 842 | int result; |
843 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
739 | unsigned long status; | 844 | unsigned long status; |
740 | 845 | ||
741 | result = ps3_vuart_get_interrupt_status(dev, &status); | 846 | result = ps3_vuart_get_interrupt_status(dev, &status); |
@@ -747,21 +852,21 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) | |||
747 | status); | 852 | status); |
748 | 853 | ||
749 | if (status & INTERRUPT_MASK_DISCONNECT) { | 854 | if (status & INTERRUPT_MASK_DISCONNECT) { |
750 | dev->priv->stats.disconnect_interrupts++; | 855 | priv->stats.disconnect_interrupts++; |
751 | result = ps3_vuart_handle_interrupt_disconnect(dev); | 856 | result = ps3_vuart_handle_interrupt_disconnect(dev); |
752 | if (result) | 857 | if (result) |
753 | ps3_vuart_disable_interrupt_disconnect(dev); | 858 | ps3_vuart_disable_interrupt_disconnect(dev); |
754 | } | 859 | } |
755 | 860 | ||
756 | if (status & INTERRUPT_MASK_TX) { | 861 | if (status & INTERRUPT_MASK_TX) { |
757 | dev->priv->stats.tx_interrupts++; | 862 | priv->stats.tx_interrupts++; |
758 | result = ps3_vuart_handle_interrupt_tx(dev); | 863 | result = ps3_vuart_handle_interrupt_tx(dev); |
759 | if (result) | 864 | if (result) |
760 | ps3_vuart_disable_interrupt_tx(dev); | 865 | ps3_vuart_disable_interrupt_tx(dev); |
761 | } | 866 | } |
762 | 867 | ||
763 | if (status & INTERRUPT_MASK_RX) { | 868 | if (status & INTERRUPT_MASK_RX) { |
764 | dev->priv->stats.rx_interrupts++; | 869 | priv->stats.rx_interrupts++; |
765 | result = ps3_vuart_handle_interrupt_rx(dev); | 870 | result = ps3_vuart_handle_interrupt_rx(dev); |
766 | if (result) | 871 | if (result) |
767 | ps3_vuart_disable_interrupt_rx(dev); | 872 | ps3_vuart_disable_interrupt_rx(dev); |
@@ -771,11 +876,11 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) | |||
771 | } | 876 | } |
772 | 877 | ||
773 | struct vuart_bus_priv { | 878 | struct vuart_bus_priv { |
774 | const struct ports_bmp bmp; | 879 | struct ports_bmp *bmp; |
775 | unsigned int virq; | 880 | unsigned int virq; |
776 | struct semaphore probe_mutex; | 881 | struct semaphore probe_mutex; |
777 | int use_count; | 882 | int use_count; |
778 | struct ps3_vuart_port_device *devices[PORT_COUNT]; | 883 | struct ps3_system_bus_device *devices[PORT_COUNT]; |
779 | } static vuart_bus_priv; | 884 | } static vuart_bus_priv; |
780 | 885 | ||
781 | /** | 886 | /** |
@@ -788,17 +893,16 @@ struct vuart_bus_priv { | |||
788 | 893 | ||
789 | static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private) | 894 | static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private) |
790 | { | 895 | { |
791 | struct vuart_bus_priv *bus_priv; | 896 | struct vuart_bus_priv *bus_priv = _private; |
792 | 897 | ||
793 | BUG_ON(!_private); | 898 | BUG_ON(!bus_priv); |
794 | bus_priv = (struct vuart_bus_priv *)_private; | ||
795 | 899 | ||
796 | while (1) { | 900 | while (1) { |
797 | unsigned int port; | 901 | unsigned int port; |
798 | 902 | ||
799 | dump_ports_bmp(&bus_priv->bmp); | 903 | dump_ports_bmp(bus_priv->bmp); |
800 | 904 | ||
801 | port = (BITS_PER_LONG - 1) - __ilog2(bus_priv->bmp.status); | 905 | port = (BITS_PER_LONG - 1) - __ilog2(bus_priv->bmp->status); |
802 | 906 | ||
803 | if (port == BITS_PER_LONG) | 907 | if (port == BITS_PER_LONG) |
804 | break; | 908 | break; |
@@ -812,100 +916,144 @@ static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private) | |||
812 | return IRQ_HANDLED; | 916 | return IRQ_HANDLED; |
813 | } | 917 | } |
814 | 918 | ||
815 | static int ps3_vuart_match(struct device *_dev, struct device_driver *_drv) | 919 | static int ps3_vuart_bus_interrupt_get(void) |
816 | { | 920 | { |
817 | int result; | 921 | int result; |
818 | struct ps3_vuart_port_driver *drv = to_ps3_vuart_port_driver(_drv); | ||
819 | struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); | ||
820 | 922 | ||
821 | result = dev->match_id == drv->match_id; | 923 | pr_debug(" -> %s:%d\n", __func__, __LINE__); |
924 | |||
925 | vuart_bus_priv.use_count++; | ||
926 | |||
927 | BUG_ON(vuart_bus_priv.use_count > 2); | ||
928 | |||
929 | if (vuart_bus_priv.use_count != 1) { | ||
930 | return 0; | ||
931 | } | ||
932 | |||
933 | BUG_ON(vuart_bus_priv.bmp); | ||
934 | |||
935 | vuart_bus_priv.bmp = kzalloc(sizeof(struct ports_bmp), GFP_KERNEL); | ||
936 | |||
937 | if (!vuart_bus_priv.bmp) { | ||
938 | pr_debug("%s:%d: kzalloc failed.\n", __func__, __LINE__); | ||
939 | result = -ENOMEM; | ||
940 | goto fail_bmp_malloc; | ||
941 | } | ||
942 | |||
943 | result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY, vuart_bus_priv.bmp, | ||
944 | &vuart_bus_priv.virq); | ||
945 | |||
946 | if (result) { | ||
947 | pr_debug("%s:%d: ps3_vuart_irq_setup failed (%d)\n", | ||
948 | __func__, __LINE__, result); | ||
949 | result = -EPERM; | ||
950 | goto fail_alloc_irq; | ||
951 | } | ||
952 | |||
953 | result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler, | ||
954 | IRQF_DISABLED, "vuart", &vuart_bus_priv); | ||
822 | 955 | ||
823 | dev_info(&dev->core, "%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__, | 956 | if (result) { |
824 | __LINE__, dev->match_id, dev->core.bus_id, drv->match_id, | 957 | pr_debug("%s:%d: request_irq failed (%d)\n", |
825 | drv->core.name, (result ? "match" : "miss")); | 958 | __func__, __LINE__, result); |
959 | goto fail_request_irq; | ||
960 | } | ||
826 | 961 | ||
962 | pr_debug(" <- %s:%d: ok\n", __func__, __LINE__); | ||
827 | return result; | 963 | return result; |
964 | |||
965 | fail_request_irq: | ||
966 | ps3_vuart_irq_destroy(vuart_bus_priv.virq); | ||
967 | vuart_bus_priv.virq = NO_IRQ; | ||
968 | fail_alloc_irq: | ||
969 | kfree(vuart_bus_priv.bmp); | ||
970 | vuart_bus_priv.bmp = NULL; | ||
971 | fail_bmp_malloc: | ||
972 | vuart_bus_priv.use_count--; | ||
973 | pr_debug(" <- %s:%d: failed\n", __func__, __LINE__); | ||
974 | return result; | ||
975 | } | ||
976 | |||
977 | static int ps3_vuart_bus_interrupt_put(void) | ||
978 | { | ||
979 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
980 | |||
981 | vuart_bus_priv.use_count--; | ||
982 | |||
983 | BUG_ON(vuart_bus_priv.use_count < 0); | ||
984 | |||
985 | if (vuart_bus_priv.use_count != 0) | ||
986 | return 0; | ||
987 | |||
988 | free_irq(vuart_bus_priv.virq, &vuart_bus_priv); | ||
989 | |||
990 | ps3_vuart_irq_destroy(vuart_bus_priv.virq); | ||
991 | vuart_bus_priv.virq = NO_IRQ; | ||
992 | |||
993 | kfree(vuart_bus_priv.bmp); | ||
994 | vuart_bus_priv.bmp = NULL; | ||
995 | |||
996 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
997 | return 0; | ||
828 | } | 998 | } |
829 | 999 | ||
830 | static int ps3_vuart_probe(struct device *_dev) | 1000 | static int ps3_vuart_probe(struct ps3_system_bus_device *dev) |
831 | { | 1001 | { |
832 | int result; | 1002 | int result; |
833 | unsigned int port_number; | 1003 | struct ps3_vuart_port_driver *drv; |
834 | struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); | 1004 | struct ps3_vuart_port_priv *priv = NULL; |
835 | struct ps3_vuart_port_driver *drv = | ||
836 | to_ps3_vuart_port_driver(_dev->driver); | ||
837 | 1005 | ||
838 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 1006 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
839 | 1007 | ||
1008 | drv = ps3_system_bus_dev_to_vuart_drv(dev); | ||
1009 | |||
1010 | dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__, | ||
1011 | drv->core.core.name); | ||
1012 | |||
840 | BUG_ON(!drv); | 1013 | BUG_ON(!drv); |
841 | 1014 | ||
842 | down(&vuart_bus_priv.probe_mutex); | 1015 | if (dev->port_number >= PORT_COUNT) { |
1016 | BUG(); | ||
1017 | return -EINVAL; | ||
1018 | } | ||
843 | 1019 | ||
844 | /* Setup vuart_bus_priv.devices[]. */ | 1020 | down(&vuart_bus_priv.probe_mutex); |
845 | 1021 | ||
846 | result = ps3_vuart_match_id_to_port(dev->match_id, | 1022 | result = ps3_vuart_bus_interrupt_get(); |
847 | &port_number); | ||
848 | 1023 | ||
849 | if (result) { | 1024 | if (result) |
850 | dev_dbg(&dev->core, "%s:%d: unknown match_id (%d)\n", | 1025 | goto fail_setup_interrupt; |
851 | __func__, __LINE__, dev->match_id); | ||
852 | result = -EINVAL; | ||
853 | goto fail_match; | ||
854 | } | ||
855 | 1026 | ||
856 | if (vuart_bus_priv.devices[port_number]) { | 1027 | if (vuart_bus_priv.devices[dev->port_number]) { |
857 | dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__, | 1028 | dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__, |
858 | __LINE__, port_number); | 1029 | __LINE__, dev->port_number); |
859 | result = -EBUSY; | 1030 | result = -EBUSY; |
860 | goto fail_match; | 1031 | goto fail_busy; |
861 | } | 1032 | } |
862 | 1033 | ||
863 | vuart_bus_priv.devices[port_number] = dev; | 1034 | vuart_bus_priv.devices[dev->port_number] = dev; |
864 | 1035 | ||
865 | /* Setup dev->priv. */ | 1036 | /* Setup dev->driver_priv. */ |
866 | 1037 | ||
867 | dev->priv = kzalloc(sizeof(struct ps3_vuart_port_priv), GFP_KERNEL); | 1038 | dev->driver_priv = kzalloc(sizeof(struct ps3_vuart_port_priv), |
1039 | GFP_KERNEL); | ||
868 | 1040 | ||
869 | if (!dev->priv) { | 1041 | if (!dev->driver_priv) { |
870 | result = -ENOMEM; | 1042 | result = -ENOMEM; |
871 | goto fail_alloc; | 1043 | goto fail_dev_malloc; |
872 | } | 1044 | } |
873 | 1045 | ||
874 | dev->priv->port_number = port_number; | 1046 | priv = to_port_priv(dev); |
875 | |||
876 | INIT_LIST_HEAD(&dev->priv->tx_list.head); | ||
877 | spin_lock_init(&dev->priv->tx_list.lock); | ||
878 | 1047 | ||
879 | INIT_LIST_HEAD(&dev->priv->rx_list.head); | 1048 | INIT_LIST_HEAD(&priv->tx_list.head); |
880 | spin_lock_init(&dev->priv->rx_list.lock); | 1049 | spin_lock_init(&priv->tx_list.lock); |
881 | 1050 | ||
882 | INIT_WORK(&dev->priv->work.work, NULL); | 1051 | INIT_LIST_HEAD(&priv->rx_list.head); |
883 | spin_lock_init(&dev->priv->work.lock); | 1052 | spin_lock_init(&priv->rx_list.lock); |
884 | dev->priv->work.trigger = 0; | ||
885 | dev->priv->work.dev = dev; | ||
886 | 1053 | ||
887 | if (++vuart_bus_priv.use_count == 1) { | 1054 | INIT_WORK(&priv->rx_list.work.work, NULL); |
888 | 1055 | priv->rx_list.work.trigger = 0; | |
889 | result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY, | 1056 | priv->rx_list.work.dev = dev; |
890 | (void*)&vuart_bus_priv.bmp.status, &vuart_bus_priv.virq); | ||
891 | |||
892 | if (result) { | ||
893 | dev_dbg(&dev->core, | ||
894 | "%s:%d: ps3_vuart_irq_setup failed (%d)\n", | ||
895 | __func__, __LINE__, result); | ||
896 | result = -EPERM; | ||
897 | goto fail_alloc_irq; | ||
898 | } | ||
899 | |||
900 | result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler, | ||
901 | IRQF_DISABLED, "vuart", &vuart_bus_priv); | ||
902 | |||
903 | if (result) { | ||
904 | dev_info(&dev->core, "%s:%d: request_irq failed (%d)\n", | ||
905 | __func__, __LINE__, result); | ||
906 | goto fail_request_irq; | ||
907 | } | ||
908 | } | ||
909 | 1057 | ||
910 | /* clear stale pending interrupts */ | 1058 | /* clear stale pending interrupts */ |
911 | 1059 | ||
@@ -936,150 +1084,158 @@ static int ps3_vuart_probe(struct device *_dev) | |||
936 | 1084 | ||
937 | fail_probe: | 1085 | fail_probe: |
938 | ps3_vuart_set_interrupt_mask(dev, 0); | 1086 | ps3_vuart_set_interrupt_mask(dev, 0); |
939 | fail_request_irq: | 1087 | kfree(dev->driver_priv); |
940 | ps3_vuart_irq_destroy(vuart_bus_priv.virq); | 1088 | dev->driver_priv = NULL; |
941 | vuart_bus_priv.virq = NO_IRQ; | 1089 | fail_dev_malloc: |
942 | fail_alloc_irq: | 1090 | vuart_bus_priv.devices[dev->port_number] = NULL; |
943 | --vuart_bus_priv.use_count; | 1091 | fail_busy: |
944 | kfree(dev->priv); | 1092 | ps3_vuart_bus_interrupt_put(); |
945 | dev->priv = NULL; | 1093 | fail_setup_interrupt: |
946 | fail_alloc: | ||
947 | vuart_bus_priv.devices[port_number] = NULL; | ||
948 | fail_match: | ||
949 | up(&vuart_bus_priv.probe_mutex); | 1094 | up(&vuart_bus_priv.probe_mutex); |
950 | dev_dbg(&dev->core, "%s:%d failed\n", __func__, __LINE__); | 1095 | dev_dbg(&dev->core, "%s:%d: failed\n", __func__, __LINE__); |
951 | return result; | 1096 | return result; |
952 | } | 1097 | } |
953 | 1098 | ||
954 | static int ps3_vuart_remove(struct device *_dev) | 1099 | /** |
1100 | * ps3_vuart_cleanup - common cleanup helper. | ||
1101 | * @dev: The struct ps3_system_bus_device instance. | ||
1102 | * | ||
1103 | * Cleans interrupts and HV resources. Must be called with | ||
1104 | * vuart_bus_priv.probe_mutex held. Used by ps3_vuart_remove and | ||
1105 | * ps3_vuart_shutdown. After this call, polled reading will still work. | ||
1106 | */ | ||
1107 | |||
1108 | static int ps3_vuart_cleanup(struct ps3_system_bus_device *dev) | ||
955 | { | 1109 | { |
956 | struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); | 1110 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
957 | struct ps3_vuart_port_driver *drv = | 1111 | |
958 | to_ps3_vuart_port_driver(_dev->driver); | 1112 | ps3_vuart_cancel_async(dev); |
1113 | ps3_vuart_set_interrupt_mask(dev, 0); | ||
1114 | ps3_vuart_bus_interrupt_put(); | ||
1115 | return 0; | ||
1116 | } | ||
1117 | |||
1118 | /** | ||
1119 | * ps3_vuart_remove - Completely clean the device instance. | ||
1120 | * @dev: The struct ps3_system_bus_device instance. | ||
1121 | * | ||
1122 | * Cleans all memory, interrupts and HV resources. After this call the | ||
1123 | * device can no longer be used. | ||
1124 | */ | ||
1125 | |||
1126 | static int ps3_vuart_remove(struct ps3_system_bus_device *dev) | ||
1127 | { | ||
1128 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
1129 | struct ps3_vuart_port_driver *drv; | ||
1130 | |||
1131 | BUG_ON(!dev); | ||
959 | 1132 | ||
960 | down(&vuart_bus_priv.probe_mutex); | 1133 | down(&vuart_bus_priv.probe_mutex); |
961 | 1134 | ||
962 | dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__, | 1135 | dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__, |
963 | dev->core.bus_id); | 1136 | dev->match_id); |
964 | 1137 | ||
965 | BUG_ON(vuart_bus_priv.use_count < 1); | 1138 | if (!dev->core.driver) { |
1139 | dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__, | ||
1140 | __LINE__); | ||
1141 | up(&vuart_bus_priv.probe_mutex); | ||
1142 | return 0; | ||
1143 | } | ||
966 | 1144 | ||
967 | if (drv->remove) | 1145 | drv = ps3_system_bus_dev_to_vuart_drv(dev); |
968 | drv->remove(dev); | ||
969 | else | ||
970 | dev_dbg(&dev->core, "%s:%d: %s no remove method\n", __func__, | ||
971 | __LINE__, dev->core.bus_id); | ||
972 | 1146 | ||
973 | vuart_bus_priv.devices[dev->priv->port_number] = NULL; | 1147 | BUG_ON(!drv); |
974 | 1148 | ||
975 | if (--vuart_bus_priv.use_count == 0) { | 1149 | if (drv->remove) { |
1150 | drv->remove(dev); | ||
1151 | } else { | ||
1152 | dev_dbg(&dev->core, "%s:%d: no remove method\n", __func__, | ||
1153 | __LINE__); | ||
976 | BUG(); | 1154 | BUG(); |
977 | free_irq(vuart_bus_priv.virq, &vuart_bus_priv); | ||
978 | ps3_vuart_irq_destroy(vuart_bus_priv.virq); | ||
979 | vuart_bus_priv.virq = NO_IRQ; | ||
980 | } | 1155 | } |
981 | 1156 | ||
982 | kfree(dev->priv); | 1157 | ps3_vuart_cleanup(dev); |
983 | dev->priv = NULL; | 1158 | |
1159 | vuart_bus_priv.devices[dev->port_number] = NULL; | ||
1160 | kfree(priv); | ||
1161 | priv = NULL; | ||
984 | 1162 | ||
1163 | dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); | ||
985 | up(&vuart_bus_priv.probe_mutex); | 1164 | up(&vuart_bus_priv.probe_mutex); |
986 | return 0; | 1165 | return 0; |
987 | } | 1166 | } |
988 | 1167 | ||
989 | static void ps3_vuart_shutdown(struct device *_dev) | ||
990 | { | ||
991 | struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); | ||
992 | struct ps3_vuart_port_driver *drv = | ||
993 | to_ps3_vuart_port_driver(_dev->driver); | ||
994 | |||
995 | dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__, | ||
996 | dev->core.bus_id); | ||
997 | |||
998 | if (drv->shutdown) | ||
999 | drv->shutdown(dev); | ||
1000 | else | ||
1001 | dev_dbg(&dev->core, "%s:%d: %s no shutdown method\n", __func__, | ||
1002 | __LINE__, dev->core.bus_id); | ||
1003 | } | ||
1004 | |||
1005 | /** | 1168 | /** |
1006 | * ps3_vuart_bus - The vuart bus instance. | 1169 | * ps3_vuart_shutdown - Cleans interrupts and HV resources. |
1170 | * @dev: The struct ps3_system_bus_device instance. | ||
1007 | * | 1171 | * |
1008 | * The vuart is managed as a bus that port devices connect to. | 1172 | * Cleans interrupts and HV resources. After this call the |
1173 | * device can still be used in polling mode. This behavior required | ||
1174 | * by sys-manager to be able to complete the device power operation | ||
1175 | * sequence. | ||
1009 | */ | 1176 | */ |
1010 | 1177 | ||
1011 | struct bus_type ps3_vuart_bus = { | 1178 | static int ps3_vuart_shutdown(struct ps3_system_bus_device *dev) |
1012 | .name = "ps3_vuart", | ||
1013 | .match = ps3_vuart_match, | ||
1014 | .probe = ps3_vuart_probe, | ||
1015 | .remove = ps3_vuart_remove, | ||
1016 | .shutdown = ps3_vuart_shutdown, | ||
1017 | }; | ||
1018 | |||
1019 | int __init ps3_vuart_bus_init(void) | ||
1020 | { | 1179 | { |
1021 | int result; | 1180 | struct ps3_vuart_port_driver *drv; |
1022 | 1181 | ||
1023 | pr_debug("%s:%d:\n", __func__, __LINE__); | 1182 | BUG_ON(!dev); |
1024 | 1183 | ||
1025 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | 1184 | down(&vuart_bus_priv.probe_mutex); |
1026 | return -ENODEV; | ||
1027 | 1185 | ||
1028 | init_MUTEX(&vuart_bus_priv.probe_mutex); | 1186 | dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__, |
1029 | result = bus_register(&ps3_vuart_bus); | 1187 | dev->match_id); |
1030 | BUG_ON(result); | ||
1031 | 1188 | ||
1032 | return result; | 1189 | if (!dev->core.driver) { |
1033 | } | 1190 | dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__, |
1191 | __LINE__); | ||
1192 | up(&vuart_bus_priv.probe_mutex); | ||
1193 | return 0; | ||
1194 | } | ||
1034 | 1195 | ||
1035 | void __exit ps3_vuart_bus_exit(void) | 1196 | drv = ps3_system_bus_dev_to_vuart_drv(dev); |
1036 | { | ||
1037 | pr_debug("%s:%d:\n", __func__, __LINE__); | ||
1038 | bus_unregister(&ps3_vuart_bus); | ||
1039 | } | ||
1040 | 1197 | ||
1041 | core_initcall(ps3_vuart_bus_init); | 1198 | BUG_ON(!drv); |
1042 | module_exit(ps3_vuart_bus_exit); | ||
1043 | 1199 | ||
1044 | /** | 1200 | if (drv->shutdown) |
1045 | * ps3_vuart_port_release_device - Remove a vuart port device. | 1201 | drv->shutdown(dev); |
1046 | */ | 1202 | else if (drv->remove) { |
1203 | dev_dbg(&dev->core, "%s:%d: no shutdown, calling remove\n", | ||
1204 | __func__, __LINE__); | ||
1205 | drv->remove(dev); | ||
1206 | } else { | ||
1207 | dev_dbg(&dev->core, "%s:%d: no shutdown method\n", __func__, | ||
1208 | __LINE__); | ||
1209 | BUG(); | ||
1210 | } | ||
1047 | 1211 | ||
1048 | static void ps3_vuart_port_release_device(struct device *_dev) | 1212 | ps3_vuart_cleanup(dev); |
1049 | { | ||
1050 | #if defined(DEBUG) | ||
1051 | struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); | ||
1052 | 1213 | ||
1053 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 1214 | dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); |
1054 | 1215 | ||
1055 | BUG_ON(dev->priv && "forgot to free"); | 1216 | up(&vuart_bus_priv.probe_mutex); |
1056 | memset(&dev->core, 0, sizeof(dev->core)); | 1217 | return 0; |
1057 | #endif | ||
1058 | } | 1218 | } |
1059 | 1219 | ||
1060 | /** | 1220 | static int __init ps3_vuart_bus_init(void) |
1061 | * ps3_vuart_port_device_register - Add a vuart port device. | ||
1062 | */ | ||
1063 | |||
1064 | int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev) | ||
1065 | { | 1221 | { |
1066 | static unsigned int dev_count = 1; | 1222 | pr_debug("%s:%d:\n", __func__, __LINE__); |
1067 | |||
1068 | BUG_ON(dev->priv && "forgot to free"); | ||
1069 | 1223 | ||
1070 | dev->core.parent = NULL; | 1224 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) |
1071 | dev->core.bus = &ps3_vuart_bus; | 1225 | return -ENODEV; |
1072 | dev->core.release = ps3_vuart_port_release_device; | ||
1073 | 1226 | ||
1074 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x", | 1227 | init_MUTEX(&vuart_bus_priv.probe_mutex); |
1075 | dev_count++); | ||
1076 | 1228 | ||
1077 | dev_dbg(&dev->core, "%s:%d register\n", __func__, __LINE__); | 1229 | return 0; |
1230 | } | ||
1078 | 1231 | ||
1079 | return device_register(&dev->core); | 1232 | static void __exit ps3_vuart_bus_exit(void) |
1233 | { | ||
1234 | pr_debug("%s:%d:\n", __func__, __LINE__); | ||
1080 | } | 1235 | } |
1081 | 1236 | ||
1082 | EXPORT_SYMBOL_GPL(ps3_vuart_port_device_register); | 1237 | core_initcall(ps3_vuart_bus_init); |
1238 | module_exit(ps3_vuart_bus_exit); | ||
1083 | 1239 | ||
1084 | /** | 1240 | /** |
1085 | * ps3_vuart_port_driver_register - Add a vuart port device driver. | 1241 | * ps3_vuart_port_driver_register - Add a vuart port device driver. |
@@ -1089,12 +1245,18 @@ int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv) | |||
1089 | { | 1245 | { |
1090 | int result; | 1246 | int result; |
1091 | 1247 | ||
1092 | pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name); | 1248 | pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.core.name); |
1093 | drv->core.bus = &ps3_vuart_bus; | 1249 | |
1094 | result = driver_register(&drv->core); | 1250 | BUG_ON(!drv->core.match_id); |
1251 | BUG_ON(!drv->core.core.name); | ||
1252 | |||
1253 | drv->core.probe = ps3_vuart_probe; | ||
1254 | drv->core.remove = ps3_vuart_remove; | ||
1255 | drv->core.shutdown = ps3_vuart_shutdown; | ||
1256 | |||
1257 | result = ps3_system_bus_driver_register(&drv->core); | ||
1095 | return result; | 1258 | return result; |
1096 | } | 1259 | } |
1097 | |||
1098 | EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register); | 1260 | EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register); |
1099 | 1261 | ||
1100 | /** | 1262 | /** |
@@ -1103,8 +1265,7 @@ EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register); | |||
1103 | 1265 | ||
1104 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv) | 1266 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv) |
1105 | { | 1267 | { |
1106 | pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name); | 1268 | pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.core.name); |
1107 | driver_unregister(&drv->core); | 1269 | ps3_system_bus_driver_unregister(&drv->core); |
1108 | } | 1270 | } |
1109 | |||
1110 | EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_unregister); | 1271 | EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_unregister); |
diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h index 1be992d568c8..eb7f6d94a890 100644 --- a/drivers/ps3/vuart.h +++ b/drivers/ps3/vuart.h | |||
@@ -34,29 +34,7 @@ struct ps3_vuart_stats { | |||
34 | struct ps3_vuart_work { | 34 | struct ps3_vuart_work { |
35 | struct work_struct work; | 35 | struct work_struct work; |
36 | unsigned long trigger; | 36 | unsigned long trigger; |
37 | spinlock_t lock; | 37 | struct ps3_system_bus_device *dev; /* to convert work to device */ |
38 | struct ps3_vuart_port_device* dev; /* to convert work to device */ | ||
39 | }; | ||
40 | |||
41 | /** | ||
42 | * struct ps3_vuart_port_priv - private vuart device data. | ||
43 | */ | ||
44 | |||
45 | struct ps3_vuart_port_priv { | ||
46 | unsigned int port_number; | ||
47 | u64 interrupt_mask; | ||
48 | |||
49 | struct { | ||
50 | spinlock_t lock; | ||
51 | struct list_head head; | ||
52 | } tx_list; | ||
53 | struct { | ||
54 | unsigned long bytes_held; | ||
55 | spinlock_t lock; | ||
56 | struct list_head head; | ||
57 | } rx_list; | ||
58 | struct ps3_vuart_stats stats; | ||
59 | struct ps3_vuart_work work; | ||
60 | }; | 38 | }; |
61 | 39 | ||
62 | /** | 40 | /** |
@@ -64,32 +42,30 @@ struct ps3_vuart_port_priv { | |||
64 | */ | 42 | */ |
65 | 43 | ||
66 | struct ps3_vuart_port_driver { | 44 | struct ps3_vuart_port_driver { |
67 | enum ps3_match_id match_id; | 45 | struct ps3_system_bus_driver core; |
68 | struct device_driver core; | 46 | int (*probe)(struct ps3_system_bus_device *); |
69 | int (*probe)(struct ps3_vuart_port_device *); | 47 | int (*remove)(struct ps3_system_bus_device *); |
70 | int (*remove)(struct ps3_vuart_port_device *); | 48 | void (*shutdown)(struct ps3_system_bus_device *); |
71 | void (*shutdown)(struct ps3_vuart_port_device *); | 49 | void (*work)(struct ps3_system_bus_device *); |
72 | int (*tx_event)(struct ps3_vuart_port_device *dev); | 50 | /* int (*tx_event)(struct ps3_system_bus_device *dev); */ |
73 | int (*rx_event)(struct ps3_vuart_port_device *dev); | 51 | /* int (*rx_event)(struct ps3_system_bus_device *dev); */ |
74 | int (*disconnect_event)(struct ps3_vuart_port_device *dev); | 52 | /* int (*disconnect_event)(struct ps3_system_bus_device *dev); */ |
75 | /* int (*suspend)(struct ps3_vuart_port_device *, pm_message_t); */ | 53 | /* int (*suspend)(struct ps3_system_bus_device *, pm_message_t); */ |
76 | /* int (*resume)(struct ps3_vuart_port_device *); */ | 54 | /* int (*resume)(struct ps3_system_bus_device *); */ |
77 | }; | 55 | }; |
78 | 56 | ||
79 | int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv); | 57 | int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv); |
80 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv); | 58 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv); |
81 | 59 | ||
82 | static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver( | 60 | static inline struct ps3_vuart_port_driver * |
83 | struct device_driver *_drv) | 61 | ps3_system_bus_dev_to_vuart_drv(struct ps3_system_bus_device *_dev) |
84 | { | ||
85 | return container_of(_drv, struct ps3_vuart_port_driver, core); | ||
86 | } | ||
87 | static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device( | ||
88 | struct device *_dev) | ||
89 | { | 62 | { |
90 | return container_of(_dev, struct ps3_vuart_port_device, core); | 63 | struct ps3_system_bus_driver *sbd = |
64 | ps3_system_bus_dev_to_system_bus_drv(_dev); | ||
65 | BUG_ON(!sbd); | ||
66 | return container_of(sbd, struct ps3_vuart_port_driver, core); | ||
91 | } | 67 | } |
92 | static inline struct ps3_vuart_port_device *ps3_vuart_work_to_port_device( | 68 | static inline struct ps3_system_bus_device *ps3_vuart_work_to_system_bus_dev( |
93 | struct work_struct *_work) | 69 | struct work_struct *_work) |
94 | { | 70 | { |
95 | struct ps3_vuart_work *vw = container_of(_work, struct ps3_vuart_work, | 71 | struct ps3_vuart_work *vw = container_of(_work, struct ps3_vuart_work, |
@@ -97,14 +73,13 @@ static inline struct ps3_vuart_port_device *ps3_vuart_work_to_port_device( | |||
97 | return vw->dev; | 73 | return vw->dev; |
98 | } | 74 | } |
99 | 75 | ||
100 | int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, | 76 | int ps3_vuart_write(struct ps3_system_bus_device *dev, const void *buf, |
101 | unsigned int bytes); | ||
102 | int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, | ||
103 | unsigned int bytes); | 77 | unsigned int bytes); |
104 | int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func, | 78 | int ps3_vuart_read(struct ps3_system_bus_device *dev, void *buf, |
105 | unsigned int bytes); | 79 | unsigned int bytes); |
106 | void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev); | 80 | int ps3_vuart_read_async(struct ps3_system_bus_device *dev, unsigned int bytes); |
107 | void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev, | 81 | void ps3_vuart_cancel_async(struct ps3_system_bus_device *dev); |
82 | void ps3_vuart_clear_rx_bytes(struct ps3_system_bus_device *dev, | ||
108 | unsigned int bytes); | 83 | unsigned int bytes); |
109 | 84 | ||
110 | #endif | 85 | #endif |
diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h index 4f753907bbf9..433c38eb61ae 100644 --- a/include/asm-powerpc/ps3.h +++ b/include/asm-powerpc/ps3.h | |||
@@ -407,23 +407,6 @@ static inline void *ps3_system_bus_get_driver_data( | |||
407 | 407 | ||
408 | extern struct bus_type ps3_system_bus_type; | 408 | extern struct bus_type ps3_system_bus_type; |
409 | 409 | ||
410 | /* vuart routines */ | ||
411 | |||
412 | struct ps3_vuart_port_priv; | ||
413 | |||
414 | /** | ||
415 | * struct ps3_vuart_port_device - a device on a vuart port | ||
416 | */ | ||
417 | |||
418 | struct ps3_vuart_port_device { | ||
419 | enum ps3_match_id match_id; | ||
420 | struct device core; | ||
421 | struct ps3_vuart_port_priv* priv; /* private driver variables */ | ||
422 | |||
423 | }; | ||
424 | |||
425 | int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev); | ||
426 | |||
427 | /* system manager */ | 410 | /* system manager */ |
428 | 411 | ||
429 | #ifdef CONFIG_PS3_SYS_MANAGER | 412 | #ifdef CONFIG_PS3_SYS_MANAGER |