summaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2010-06-10 08:35:06 +0200
committerClemens Ladisch <clemens@ladisch.de>2010-06-10 08:35:06 +0200
commita1a1132bd83d0aea51d4f19be4b4a58a064a0131 (patch)
tree93352d6aa9fd8eaa0521fbeb65853cd9f485666e /drivers/firewire
parentfirewire: add CSR BUSY_TIMEOUT support (diff)
downloadlinux-a1a1132bd83d0aea51d4f19be4b4a58a064a0131.tar.xz
linux-a1a1132bd83d0aea51d4f19be4b4a58a064a0131.zip
firewire: add CSR PRIORITY_BUDGET support
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>
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/core-transaction.c14
-rw-r--r--drivers/firewire/core.h4
-rw-r--r--drivers/firewire/ohci.c27
3 files changed, 45 insertions, 0 deletions
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 8146133818dc..a61eb3fb9573 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -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);
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index efcdeb2e31e6..3b8c0f042f49 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -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);
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 9c588fd01250..0e5413531785 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -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,