diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-22 17:49:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-22 17:49:48 -0400 |
commit | 441c196e84b11aad3123baa9320eee7abc6b5c98 (patch) | |
tree | ea51d689c9ac09cce10a5758f19d6adbd8a7a9d7 /drivers/firewire/ohci.c | |
parent | 951cc93a7493a81a47e20231441bc6cf17c98a37 (diff) | |
parent | 9a00c24ae7cb08dcd46edf1327a47871e8466444 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6:
firewire: document the sysfs ABIs
firewire: cdev: ABI documentation enhancements
firewire: cdev: prevent race between first get_info ioctl and bus reset event queuing
firewire: cdev: return -ENOTTY for unimplemented ioctls, not -EINVAL
firewire: ohci: skip soft reset retries after card ejection
firewire: ohci: fix PHY reg access after card ejection
firewire: ohci: add a comment on PHY reg access serialization
firewire: ohci: reduce potential context_stop latency
firewire: ohci: remove superfluous posted write flushes
firewire: net: replacing deprecated __attribute__((packed)) with __packed
Diffstat (limited to 'drivers/firewire/ohci.c')
-rw-r--r-- | drivers/firewire/ohci.c | 42 |
1 files changed, 27 insertions, 15 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index ebb897329c1e..bcf792fac442 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c | |||
@@ -253,7 +253,6 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) | |||
253 | #define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 | 253 | #define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 |
254 | 254 | ||
255 | #define OHCI1394_REGISTER_SIZE 0x800 | 255 | #define OHCI1394_REGISTER_SIZE 0x800 |
256 | #define OHCI_LOOP_COUNT 500 | ||
257 | #define OHCI1394_PCI_HCI_Control 0x40 | 256 | #define OHCI1394_PCI_HCI_Control 0x40 |
258 | #define SELF_ID_BUF_SIZE 0x800 | 257 | #define SELF_ID_BUF_SIZE 0x800 |
259 | #define OHCI_TCODE_PHY_PACKET 0x0e | 258 | #define OHCI_TCODE_PHY_PACKET 0x0e |
@@ -514,6 +513,12 @@ static inline void flush_writes(const struct fw_ohci *ohci) | |||
514 | reg_read(ohci, OHCI1394_Version); | 513 | reg_read(ohci, OHCI1394_Version); |
515 | } | 514 | } |
516 | 515 | ||
516 | /* | ||
517 | * Beware! read_phy_reg(), write_phy_reg(), update_phy_reg(), and | ||
518 | * read_paged_phy_reg() require the caller to hold ohci->phy_reg_mutex. | ||
519 | * In other words, only use ohci_read_phy_reg() and ohci_update_phy_reg() | ||
520 | * directly. Exceptions are intrinsically serialized contexts like pci_probe. | ||
521 | */ | ||
517 | static int read_phy_reg(struct fw_ohci *ohci, int addr) | 522 | static int read_phy_reg(struct fw_ohci *ohci, int addr) |
518 | { | 523 | { |
519 | u32 val; | 524 | u32 val; |
@@ -522,6 +527,9 @@ static int read_phy_reg(struct fw_ohci *ohci, int addr) | |||
522 | reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr)); | 527 | reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr)); |
523 | for (i = 0; i < 3 + 100; i++) { | 528 | for (i = 0; i < 3 + 100; i++) { |
524 | val = reg_read(ohci, OHCI1394_PhyControl); | 529 | val = reg_read(ohci, OHCI1394_PhyControl); |
530 | if (!~val) | ||
531 | return -ENODEV; /* Card was ejected. */ | ||
532 | |||
525 | if (val & OHCI1394_PhyControl_ReadDone) | 533 | if (val & OHCI1394_PhyControl_ReadDone) |
526 | return OHCI1394_PhyControl_ReadData(val); | 534 | return OHCI1394_PhyControl_ReadData(val); |
527 | 535 | ||
@@ -545,6 +553,9 @@ static int write_phy_reg(const struct fw_ohci *ohci, int addr, u32 val) | |||
545 | OHCI1394_PhyControl_Write(addr, val)); | 553 | OHCI1394_PhyControl_Write(addr, val)); |
546 | for (i = 0; i < 3 + 100; i++) { | 554 | for (i = 0; i < 3 + 100; i++) { |
547 | val = reg_read(ohci, OHCI1394_PhyControl); | 555 | val = reg_read(ohci, OHCI1394_PhyControl); |
556 | if (!~val) | ||
557 | return -ENODEV; /* Card was ejected. */ | ||
558 | |||
548 | if (!(val & OHCI1394_PhyControl_WritePending)) | 559 | if (!(val & OHCI1394_PhyControl_WritePending)) |
549 | return 0; | 560 | return 0; |
550 | 561 | ||
@@ -630,7 +641,6 @@ static void ar_context_link_page(struct ar_context *ctx, unsigned int index) | |||
630 | ctx->last_buffer_index = index; | 641 | ctx->last_buffer_index = index; |
631 | 642 | ||
632 | reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); | 643 | reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); |
633 | flush_writes(ctx->ohci); | ||
634 | } | 644 | } |
635 | 645 | ||
636 | static void ar_context_release(struct ar_context *ctx) | 646 | static void ar_context_release(struct ar_context *ctx) |
@@ -1002,7 +1012,6 @@ static void ar_context_run(struct ar_context *ctx) | |||
1002 | 1012 | ||
1003 | reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ctx->descriptors_bus | 1); | 1013 | reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ctx->descriptors_bus | 1); |
1004 | reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN); | 1014 | reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN); |
1005 | flush_writes(ctx->ohci); | ||
1006 | } | 1015 | } |
1007 | 1016 | ||
1008 | static struct descriptor *find_branch_descriptor(struct descriptor *d, int z) | 1017 | static struct descriptor *find_branch_descriptor(struct descriptor *d, int z) |
@@ -1202,14 +1211,14 @@ static void context_stop(struct context *ctx) | |||
1202 | 1211 | ||
1203 | reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); | 1212 | reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); |
1204 | ctx->running = false; | 1213 | ctx->running = false; |
1205 | flush_writes(ctx->ohci); | ||
1206 | 1214 | ||
1207 | for (i = 0; i < 10; i++) { | 1215 | for (i = 0; i < 1000; i++) { |
1208 | reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs)); | 1216 | reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs)); |
1209 | if ((reg & CONTEXT_ACTIVE) == 0) | 1217 | if ((reg & CONTEXT_ACTIVE) == 0) |
1210 | return; | 1218 | return; |
1211 | 1219 | ||
1212 | mdelay(1); | 1220 | if (i) |
1221 | udelay(10); | ||
1213 | } | 1222 | } |
1214 | fw_error("Error: DMA context still active (0x%08x)\n", reg); | 1223 | fw_error("Error: DMA context still active (0x%08x)\n", reg); |
1215 | } | 1224 | } |
@@ -1346,12 +1355,10 @@ static int at_context_queue_packet(struct context *ctx, | |||
1346 | 1355 | ||
1347 | context_append(ctx, d, z, 4 - z); | 1356 | context_append(ctx, d, z, 4 - z); |
1348 | 1357 | ||
1349 | if (ctx->running) { | 1358 | if (ctx->running) |
1350 | reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); | 1359 | reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); |
1351 | flush_writes(ohci); | 1360 | else |
1352 | } else { | ||
1353 | context_run(ctx, 0); | 1361 | context_run(ctx, 0); |
1354 | } | ||
1355 | 1362 | ||
1356 | return 0; | 1363 | return 0; |
1357 | } | 1364 | } |
@@ -1960,14 +1967,18 @@ static irqreturn_t irq_handler(int irq, void *data) | |||
1960 | 1967 | ||
1961 | static int software_reset(struct fw_ohci *ohci) | 1968 | static int software_reset(struct fw_ohci *ohci) |
1962 | { | 1969 | { |
1970 | u32 val; | ||
1963 | int i; | 1971 | int i; |
1964 | 1972 | ||
1965 | reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset); | 1973 | reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset); |
1974 | for (i = 0; i < 500; i++) { | ||
1975 | val = reg_read(ohci, OHCI1394_HCControlSet); | ||
1976 | if (!~val) | ||
1977 | return -ENODEV; /* Card was ejected. */ | ||
1966 | 1978 | ||
1967 | for (i = 0; i < OHCI_LOOP_COUNT; i++) { | 1979 | if (!(val & OHCI1394_HCControl_softReset)) |
1968 | if ((reg_read(ohci, OHCI1394_HCControlSet) & | ||
1969 | OHCI1394_HCControl_softReset) == 0) | ||
1970 | return 0; | 1980 | return 0; |
1981 | |||
1971 | msleep(1); | 1982 | msleep(1); |
1972 | } | 1983 | } |
1973 | 1984 | ||
@@ -2197,7 +2208,9 @@ static int ohci_enable(struct fw_card *card, | |||
2197 | OHCI1394_LinkControl_rcvPhyPkt); | 2208 | OHCI1394_LinkControl_rcvPhyPkt); |
2198 | 2209 | ||
2199 | ar_context_run(&ohci->ar_request_ctx); | 2210 | ar_context_run(&ohci->ar_request_ctx); |
2200 | ar_context_run(&ohci->ar_response_ctx); /* also flushes writes */ | 2211 | ar_context_run(&ohci->ar_response_ctx); |
2212 | |||
2213 | flush_writes(ohci); | ||
2201 | 2214 | ||
2202 | /* We are ready to go, reset bus to finish initialization. */ | 2215 | /* We are ready to go, reset bus to finish initialization. */ |
2203 | fw_schedule_bus_reset(&ohci->card, false, true); | 2216 | fw_schedule_bus_reset(&ohci->card, false, true); |
@@ -3129,7 +3142,6 @@ static void ohci_flush_queue_iso(struct fw_iso_context *base) | |||
3129 | &container_of(base, struct iso_context, base)->context; | 3142 | &container_of(base, struct iso_context, base)->context; |
3130 | 3143 | ||
3131 | reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); | 3144 | reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); |
3132 | flush_writes(ctx->ohci); | ||
3133 | } | 3145 | } |
3134 | 3146 | ||
3135 | static const struct fw_card_driver ohci_driver = { | 3147 | static const struct fw_card_driver ohci_driver = { |