firewire: add CSR PRIORITY_BUDGET support
authorClemens Ladisch <clemens@ladisch.de>
Thu, 10 Jun 2010 06:35:06 +0000 (08:35 +0200)
committerClemens Ladisch <clemens@ladisch.de>
Thu, 10 Jun 2010 06:35:06 +0000 (08:35 +0200)
If supported by the OHCI controller, implement the PRIORITY_BUDGET
register, which is required for nodes that can use asynchronous
priority arbitration.

To allow the core to determine what features the lowlevel device
supports, add a new card driver callback.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
drivers/firewire/core-transaction.c
drivers/firewire/core.h
drivers/firewire/ohci.c
include/linux/firewire.h

index 8146133818dc65d3392fb73a1c71056d11819eda..a61eb3fb957397aee8c3dd4868dcb7fbbad767bc 100644 (file)
@@ -1126,6 +1126,20 @@ static void handle_registers(struct fw_card *card, struct fw_request *request,
                        rcode = RCODE_TYPE_ERROR;
                break;
 
+       case CSR_PRIORITY_BUDGET:
+               if (!(card->driver->get_features(card) &
+                                               FEATURE_PRIORITY_BUDGET))
+                       rcode = RCODE_ADDRESS_ERROR;
+               else if (tcode == TCODE_READ_QUADLET_REQUEST)
+                       *data = cpu_to_be32(card->driver->
+                               read_csr_reg(card, CSR_PRIORITY_BUDGET));
+               else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
+                       card->driver->write_csr_reg(card, CSR_PRIORITY_BUDGET,
+                                                   be32_to_cpu(*data));
+               else
+                       rcode = RCODE_TYPE_ERROR;
+               break;
+
        case CSR_BROADCAST_CHANNEL:
                if (tcode == TCODE_READ_QUADLET_REQUEST)
                        *data = cpu_to_be32(card->broadcast_channel);
index efcdeb2e31e6a1dd1fd005a1a39793629b9fef29..3b8c0f042f49286341d8144d877d466581fc3039 100644 (file)
@@ -38,6 +38,8 @@ struct fw_packet;
 #define BROADCAST_CHANNEL_INITIAL      (1 << 31 | 31)
 #define BROADCAST_CHANNEL_VALID                (1 << 30)
 
+#define FEATURE_PRIORITY_BUDGET                0x01
+
 struct fw_card_driver {
        /*
         * Enable the given card with the given initial config rom.
@@ -78,6 +80,8 @@ struct fw_card_driver {
        u32 (*read_csr_reg)(struct fw_card *card, int csr_offset);
        void (*write_csr_reg)(struct fw_card *card, int csr_offset, u32 value);
 
+       unsigned int (*get_features)(struct fw_card *card);
+
        struct fw_iso_context *
        (*allocate_iso_context)(struct fw_card *card,
                                int type, int channel, size_t header_size);
index 9c588fd01250b1fee6fc40e0aaedb85fd07f16e3..0e5413531785f83d8562b49ffbbfc623bcdd2118 100644 (file)
@@ -170,6 +170,7 @@ struct fw_ohci {
        int generation;
        int request_generation; /* for timestamping incoming requests */
        unsigned quirks;
+       unsigned int pri_req_max;
        u32 bus_time;
 
        /*
@@ -1738,6 +1739,11 @@ static int ohci_enable(struct fw_card *card,
        reg_write(ohci, OHCI1394_IsochronousCycleTimer, seconds << 25);
        ohci->bus_time = seconds & ~0x3f;
 
+       /* Get implemented bits of the priority arbitration request counter. */
+       reg_write(ohci, OHCI1394_FairnessControl, 0x3f);
+       ohci->pri_req_max = reg_read(ohci, OHCI1394_FairnessControl) & 0x3f;
+       reg_write(ohci, OHCI1394_FairnessControl, 0);
+
        ar_context_run(&ohci->ar_request_ctx);
        ar_context_run(&ohci->ar_response_ctx);
 
@@ -2028,6 +2034,10 @@ static u32 ohci_read_csr_reg(struct fw_card *card, int csr_offset)
                value = reg_read(ohci, OHCI1394_ATRetries);
                return (value >> 4) & 0x0ffff00f;
 
+       case CSR_PRIORITY_BUDGET:
+               return (reg_read(ohci, OHCI1394_FairnessControl) & 0x3f) |
+                       (ohci->pri_req_max << 8);
+
        default:
                WARN_ON(1);
                return 0;
@@ -2065,12 +2075,28 @@ static void ohci_write_csr_reg(struct fw_card *card, int csr_offset, u32 value)
                flush_writes(ohci);
                break;
 
+       case CSR_PRIORITY_BUDGET:
+               reg_write(ohci, OHCI1394_FairnessControl, value & 0x3f);
+               flush_writes(ohci);
+               break;
+
        default:
                WARN_ON(1);
                break;
        }
 }
 
+static unsigned int ohci_get_features(struct fw_card *card)
+{
+       struct fw_ohci *ohci = fw_ohci(card);
+       unsigned int features = 0;
+
+       if (ohci->pri_req_max != 0)
+               features |= FEATURE_PRIORITY_BUDGET;
+
+       return features;
+}
+
 static void copy_iso_headers(struct iso_context *ctx, void *p)
 {
        int i = ctx->header_length;
@@ -2510,6 +2536,7 @@ static const struct fw_card_driver ohci_driver = {
        .enable_phys_dma        = ohci_enable_phys_dma,
        .read_csr_reg           = ohci_read_csr_reg,
        .write_csr_reg          = ohci_write_csr_reg,
+       .get_features           = ohci_get_features,
 
        .allocate_iso_context   = ohci_allocate_iso_context,
        .free_iso_context       = ohci_free_iso_context,
index cdf8213c68cad5be64a53f59eacbdaa6484ef703..a50377d9125492af64a03ee5136fdf08700322f5 100644 (file)
@@ -32,6 +32,7 @@
 #define CSR_CYCLE_TIME                 0x200
 #define CSR_BUS_TIME                   0x204
 #define CSR_BUSY_TIMEOUT               0x210
+#define CSR_PRIORITY_BUDGET            0x218
 #define CSR_BUS_MANAGER_ID             0x21c
 #define CSR_BANDWIDTH_AVAILABLE                0x220
 #define CSR_CHANNELS_AVAILABLE         0x224