diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-04-02 13:46:56 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-04-08 16:44:40 -0400 |
commit | d625a29ba649a4df6027520ffc378f23c0e6883e (patch) | |
tree | 07b895d38717e24e655948c963f4287f551df42f /drivers/ssb/pcmcia.c | |
parent | 93af2614513103216038afa708718295e7016dbb (diff) |
ssb: Add support for block-I/O
This adds support for block based I/O to SSB.
This is needed in order to efficiently support PIO data
transfers to the card.
The block-I/O support is only compiled, if it's selected by the
weird driver that needs it. So there's no overhead for sane devices.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/ssb/pcmcia.c')
-rw-r--r-- | drivers/ssb/pcmcia.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c index dcaf2412bea7..24c2a46c1476 100644 --- a/drivers/ssb/pcmcia.c +++ b/drivers/ssb/pcmcia.c | |||
@@ -285,6 +285,64 @@ static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset) | |||
285 | return (lo | (hi << 16)); | 285 | return (lo | (hi << 16)); |
286 | } | 286 | } |
287 | 287 | ||
288 | #ifdef CONFIG_SSB_BLOCKIO | ||
289 | static void ssb_pcmcia_block_read(struct ssb_device *dev, void *buffer, | ||
290 | size_t count, u16 offset, u8 reg_width) | ||
291 | { | ||
292 | struct ssb_bus *bus = dev->bus; | ||
293 | unsigned long flags; | ||
294 | void __iomem *addr = bus->mmio + offset; | ||
295 | int err; | ||
296 | |||
297 | spin_lock_irqsave(&bus->bar_lock, flags); | ||
298 | err = select_core_and_segment(dev, &offset); | ||
299 | if (unlikely(err)) { | ||
300 | memset(buffer, 0xFF, count); | ||
301 | goto unlock; | ||
302 | } | ||
303 | switch (reg_width) { | ||
304 | case sizeof(u8): { | ||
305 | u8 *buf = buffer; | ||
306 | |||
307 | while (count) { | ||
308 | *buf = __raw_readb(addr); | ||
309 | buf++; | ||
310 | count--; | ||
311 | } | ||
312 | break; | ||
313 | } | ||
314 | case sizeof(u16): { | ||
315 | __le16 *buf = buffer; | ||
316 | |||
317 | SSB_WARN_ON(count & 1); | ||
318 | while (count) { | ||
319 | *buf = (__force __le16)__raw_readw(addr); | ||
320 | buf++; | ||
321 | count -= 2; | ||
322 | } | ||
323 | break; | ||
324 | } | ||
325 | case sizeof(u32): { | ||
326 | __le16 *buf = buffer; | ||
327 | |||
328 | SSB_WARN_ON(count & 3); | ||
329 | while (count) { | ||
330 | *buf = (__force __le16)__raw_readw(addr); | ||
331 | buf++; | ||
332 | *buf = (__force __le16)__raw_readw(addr + 2); | ||
333 | buf++; | ||
334 | count -= 4; | ||
335 | } | ||
336 | break; | ||
337 | } | ||
338 | default: | ||
339 | SSB_WARN_ON(1); | ||
340 | } | ||
341 | unlock: | ||
342 | spin_unlock_irqrestore(&bus->bar_lock, flags); | ||
343 | } | ||
344 | #endif /* CONFIG_SSB_BLOCKIO */ | ||
345 | |||
288 | static void ssb_pcmcia_write8(struct ssb_device *dev, u16 offset, u8 value) | 346 | static void ssb_pcmcia_write8(struct ssb_device *dev, u16 offset, u8 value) |
289 | { | 347 | { |
290 | struct ssb_bus *bus = dev->bus; | 348 | struct ssb_bus *bus = dev->bus; |
@@ -329,6 +387,63 @@ static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value) | |||
329 | spin_unlock_irqrestore(&bus->bar_lock, flags); | 387 | spin_unlock_irqrestore(&bus->bar_lock, flags); |
330 | } | 388 | } |
331 | 389 | ||
390 | #ifdef CONFIG_SSB_BLOCKIO | ||
391 | static void ssb_pcmcia_block_write(struct ssb_device *dev, const void *buffer, | ||
392 | size_t count, u16 offset, u8 reg_width) | ||
393 | { | ||
394 | struct ssb_bus *bus = dev->bus; | ||
395 | unsigned long flags; | ||
396 | void __iomem *addr = bus->mmio + offset; | ||
397 | int err; | ||
398 | |||
399 | spin_lock_irqsave(&bus->bar_lock, flags); | ||
400 | err = select_core_and_segment(dev, &offset); | ||
401 | if (unlikely(err)) | ||
402 | goto unlock; | ||
403 | switch (reg_width) { | ||
404 | case sizeof(u8): { | ||
405 | const u8 *buf = buffer; | ||
406 | |||
407 | while (count) { | ||
408 | __raw_writeb(*buf, addr); | ||
409 | buf++; | ||
410 | count--; | ||
411 | } | ||
412 | break; | ||
413 | } | ||
414 | case sizeof(u16): { | ||
415 | const __le16 *buf = buffer; | ||
416 | |||
417 | SSB_WARN_ON(count & 1); | ||
418 | while (count) { | ||
419 | __raw_writew((__force u16)(*buf), addr); | ||
420 | buf++; | ||
421 | count -= 2; | ||
422 | } | ||
423 | break; | ||
424 | } | ||
425 | case sizeof(u32): { | ||
426 | const __le16 *buf = buffer; | ||
427 | |||
428 | SSB_WARN_ON(count & 3); | ||
429 | while (count) { | ||
430 | __raw_writew((__force u16)(*buf), addr); | ||
431 | buf++; | ||
432 | __raw_writew((__force u16)(*buf), addr + 2); | ||
433 | buf++; | ||
434 | count -= 4; | ||
435 | } | ||
436 | break; | ||
437 | } | ||
438 | default: | ||
439 | SSB_WARN_ON(1); | ||
440 | } | ||
441 | unlock: | ||
442 | mmiowb(); | ||
443 | spin_unlock_irqrestore(&bus->bar_lock, flags); | ||
444 | } | ||
445 | #endif /* CONFIG_SSB_BLOCKIO */ | ||
446 | |||
332 | /* Not "static", as it's used in main.c */ | 447 | /* Not "static", as it's used in main.c */ |
333 | const struct ssb_bus_ops ssb_pcmcia_ops = { | 448 | const struct ssb_bus_ops ssb_pcmcia_ops = { |
334 | .read8 = ssb_pcmcia_read8, | 449 | .read8 = ssb_pcmcia_read8, |
@@ -337,6 +452,10 @@ const struct ssb_bus_ops ssb_pcmcia_ops = { | |||
337 | .write8 = ssb_pcmcia_write8, | 452 | .write8 = ssb_pcmcia_write8, |
338 | .write16 = ssb_pcmcia_write16, | 453 | .write16 = ssb_pcmcia_write16, |
339 | .write32 = ssb_pcmcia_write32, | 454 | .write32 = ssb_pcmcia_write32, |
455 | #ifdef CONFIG_SSB_BLOCKIO | ||
456 | .block_read = ssb_pcmcia_block_read, | ||
457 | .block_write = ssb_pcmcia_block_write, | ||
458 | #endif | ||
340 | }; | 459 | }; |
341 | 460 | ||
342 | static int ssb_pcmcia_sprom_command(struct ssb_bus *bus, u8 command) | 461 | static int ssb_pcmcia_sprom_command(struct ssb_bus *bus, u8 command) |