* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/bug.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/spinlock.h>
int generation;
int request_generation; /* for timestamping incoming requests */
unsigned quirks;
+ unsigned int pri_req_max;
+ u32 bus_time;
+ bool is_root;
+ bool csr_state_setclear_abdicate;
/*
* Spinlock for accessing fw_ohci data. Never call out of
*/
spinlock_t lock;
+ struct mutex phy_reg_mutex;
+
struct ar_context ar_request_ctx;
struct ar_context ar_response_ctx;
struct context at_request_ctx;
static char ohci_driver_name[] = KBUILD_MODNAME;
+#define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380
+#define PCI_DEVICE_ID_TI_TSB12LV22 0x8009
+
#define QUIRK_CYCLE_TIMER 1
#define QUIRK_RESET_PACKET 2
#define QUIRK_BE_HEADERS 4
+#define QUIRK_NO_1394A 8
+#define QUIRK_NO_MSI 16
/* In case of multiple matches in ohci_quirks[], only the first one is used. */
static const struct {
unsigned short vendor, device, flags;
} ohci_quirks[] = {
+ {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, QUIRK_CYCLE_TIMER |
+ QUIRK_RESET_PACKET |
+ QUIRK_NO_1394A},
{PCI_VENDOR_ID_TI, PCI_ANY_ID, QUIRK_RESET_PACKET},
{PCI_VENDOR_ID_AL, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
+ {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, QUIRK_NO_MSI},
{PCI_VENDOR_ID_NEC, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
{PCI_VENDOR_ID_VIA, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
{PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, QUIRK_BE_HEADERS},
", nonatomic cycle timer = " __stringify(QUIRK_CYCLE_TIMER)
", reset packet generation = " __stringify(QUIRK_RESET_PACKET)
", AR/selfID endianess = " __stringify(QUIRK_BE_HEADERS)
+ ", no 1394a enhancements = " __stringify(QUIRK_NO_1394A)
+ ", disable MSI = " __stringify(QUIRK_NO_MSI)
")");
-#ifdef CONFIG_FIREWIRE_OHCI_DEBUG
-
#define OHCI_PARAM_DEBUG_AT_AR 1
#define OHCI_PARAM_DEBUG_SELFIDS 2
#define OHCI_PARAM_DEBUG_IRQS 4
#define OHCI_PARAM_DEBUG_BUSRESETS 8 /* only effective before chip init */
+#ifdef CONFIG_FIREWIRE_OHCI_DEBUG
+
static int param_debug;
module_param_named(debug, param_debug, int, 0644);
MODULE_PARM_DESC(debug, "Verbose logging (default = 0"
!(evt & OHCI1394_busReset))
return;
- fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
+ fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
evt & OHCI1394_selfIDComplete ? " selfID" : "",
evt & OHCI1394_RQPkt ? " AR_req" : "",
evt & OHCI1394_RSPkt ? " AR_resp" : "",
evt & OHCI1394_isochTx ? " IT" : "",
evt & OHCI1394_postedWriteErr ? " postedWriteErr" : "",
evt & OHCI1394_cycleTooLong ? " cycleTooLong" : "",
+ evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "",
evt & OHCI1394_cycleInconsistent ? " cycleInconsistent" : "",
evt & OHCI1394_regAccessFail ? " regAccessFail" : "",
evt & OHCI1394_busReset ? " busReset" : "",
OHCI1394_RSPkt | OHCI1394_reqTxComplete |
OHCI1394_respTxComplete | OHCI1394_isochRx |
OHCI1394_isochTx | OHCI1394_postedWriteErr |
- OHCI1394_cycleTooLong | OHCI1394_cycleInconsistent |
+ OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds |
+ OHCI1394_cycleInconsistent |
OHCI1394_regAccessFail | OHCI1394_busReset)
? " ?" : "");
}
#else
-#define log_irqs(evt)
-#define log_selfids(node_id, generation, self_id_count, sid)
-#define log_ar_at_event(dir, speed, header, evt)
+#define param_debug 0
+static inline void log_irqs(u32 evt) {}
+static inline void log_selfids(int node_id, int generation, int self_id_count, u32 *s) {}
+static inline void log_ar_at_event(char dir, int speed, u32 *header, int evt) {}
#endif /* CONFIG_FIREWIRE_OHCI_DEBUG */
reg_read(ohci, OHCI1394_Version);
}
-static int ohci_update_phy_reg(struct fw_card *card, int addr,
- int clear_bits, int set_bits)
+static int read_phy_reg(struct fw_ohci *ohci, int addr)
{
- struct fw_ohci *ohci = fw_ohci(card);
- u32 val, old;
+ u32 val;
+ int i;
reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr));
- flush_writes(ohci);
- msleep(2);
- val = reg_read(ohci, OHCI1394_PhyControl);
- if ((val & OHCI1394_PhyControl_ReadDone) == 0) {
- fw_error("failed to set phy reg bits.\n");
- return -EBUSY;
+ for (i = 0; i < 3 + 100; i++) {
+ val = reg_read(ohci, OHCI1394_PhyControl);
+ if (val & OHCI1394_PhyControl_ReadDone)
+ return OHCI1394_PhyControl_ReadData(val);
+
+ /*
+ * Try a few times without waiting. Sleeping is necessary
+ * only when the link/PHY interface is busy.
+ */
+ if (i >= 3)
+ msleep(1);
}
+ fw_error("failed to read phy reg\n");
+
+ return -EBUSY;
+}
+
+static int write_phy_reg(const struct fw_ohci *ohci, int addr, u32 val)
+{
+ int i;
- old = OHCI1394_PhyControl_ReadData(val);
- old = (old & ~clear_bits) | set_bits;
reg_write(ohci, OHCI1394_PhyControl,
- OHCI1394_PhyControl_Write(addr, old));
+ OHCI1394_PhyControl_Write(addr, val));
+ for (i = 0; i < 3 + 100; i++) {
+ val = reg_read(ohci, OHCI1394_PhyControl);
+ if (!(val & OHCI1394_PhyControl_WritePending))
+ return 0;
- return 0;
+ if (i >= 3)
+ msleep(1);
+ }
+ fw_error("failed to write phy reg\n");
+
+ return -EBUSY;
+}
+
+static int update_phy_reg(struct fw_ohci *ohci, int addr,
+ int clear_bits, int set_bits)
+{
+ int ret = read_phy_reg(ohci, addr);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * The interrupt status bits are cleared by writing a one bit.
+ * Avoid clearing them unless explicitly requested in set_bits.
+ */
+ if (addr == 5)
+ clear_bits |= PHY_INT_STATUS_BITS;
+
+ return write_phy_reg(ohci, addr, (ret & ~clear_bits) | set_bits);
+}
+
+static int read_paged_phy_reg(struct fw_ohci *ohci, int page, int addr)
+{
+ int ret;
+
+ ret = update_phy_reg(ohci, 7, PHY_PAGE_SELECT, page << 5);
+ if (ret < 0)
+ return ret;
+
+ return read_phy_reg(ohci, addr);
+}
+
+static int ohci_read_phy_reg(struct fw_card *card, int addr)
+{
+ struct fw_ohci *ohci = fw_ohci(card);
+ int ret;
+
+ mutex_lock(&ohci->phy_reg_mutex);
+ ret = read_phy_reg(ohci, addr);
+ mutex_unlock(&ohci->phy_reg_mutex);
+
+ return ret;
+}
+
+static int ohci_update_phy_reg(struct fw_card *card, int addr,
+ int clear_bits, int set_bits)
+{
+ struct fw_ohci *ohci = fw_ohci(card);
+ int ret;
+
+ mutex_lock(&ohci->phy_reg_mutex);
+ ret = update_phy_reg(ohci, addr, clear_bits, set_bits);
+ mutex_unlock(&ohci->phy_reg_mutex);
+
+ return ret;
}
static int ar_context_add_page(struct ar_context *ctx)
}
+static u32 cycle_timer_ticks(u32 cycle_timer)
+{
+ u32 ticks;
+
+ ticks = cycle_timer & 0xfff;
+ ticks += 3072 * ((cycle_timer >> 12) & 0x1fff);
+ ticks += (3072 * 8000) * (cycle_timer >> 25);
+
+ return ticks;
+}
+
+/*
+ * Some controllers exhibit one or more of the following bugs when updating the
+ * iso cycle timer register:
+ * - When the lowest six bits are wrapping around to zero, a read that happens
+ * at the same time will return garbage in the lowest ten bits.
+ * - When the cycleOffset field wraps around to zero, the cycleCount field is
+ * not incremented for about 60 ns.
+ * - Occasionally, the entire register reads zero.
+ *
+ * To catch these, we read the register three times and ensure that the
+ * difference between each two consecutive reads is approximately the same, i.e.
+ * less than twice the other. Furthermore, any negative difference indicates an
+ * error. (A PCI read should take at least 20 ticks of the 24.576 MHz timer to
+ * execute, so we have enough precision to compute the ratio of the differences.)
+ */
+static u32 get_cycle_time(struct fw_ohci *ohci)
+{
+ u32 c0, c1, c2;
+ u32 t0, t1, t2;
+ s32 diff01, diff12;
+ int i;
+
+ c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+
+ if (ohci->quirks & QUIRK_CYCLE_TIMER) {
+ i = 0;
+ c1 = c2;
+ c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+ do {
+ c0 = c1;
+ c1 = c2;
+ c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+ t0 = cycle_timer_ticks(c0);
+ t1 = cycle_timer_ticks(c1);
+ t2 = cycle_timer_ticks(c2);
+ diff01 = t1 - t0;
+ diff12 = t2 - t1;
+ } while ((diff01 <= 0 || diff12 <= 0 ||
+ diff01 / diff12 >= 2 || diff12 / diff01 >= 2)
+ && i++ < 20);
+ }
+
+ return c2;
+}
+
+/*
+ * This function has to be called at least every 64 seconds. The bus_time
+ * field stores not only the upper 25 bits of the BUS_TIME register but also
+ * the most significant bit of the cycle timer in bit 6 so that we can detect
+ * changes in this bit.
+ */
+static u32 update_bus_time(struct fw_ohci *ohci)
+{
+ u32 cycle_time_seconds = get_cycle_time(ohci) >> 25;
+
+ if ((ohci->bus_time & 0x40) != (cycle_time_seconds & 0x40))
+ ohci->bus_time += 0x40;
+
+ return ohci->bus_time | cycle_time_seconds;
+}
+
static void bus_reset_tasklet(unsigned long data)
{
struct fw_ohci *ohci = (struct fw_ohci *)data;
unsigned long flags;
void *free_rom = NULL;
dma_addr_t free_rom_bus = 0;
+ bool is_new_root;
reg = reg_read(ohci, OHCI1394_NodeID);
if (!(reg & OHCI1394_NodeID_idValid)) {
ohci->node_id = reg & (OHCI1394_NodeID_busNumber |
OHCI1394_NodeID_nodeNumber);
+ is_new_root = (reg & OHCI1394_NodeID_root) != 0;
+ if (!(ohci->is_root && is_new_root))
+ reg_write(ohci, OHCI1394_LinkControlSet,
+ OHCI1394_LinkControl_cycleMaster);
+ ohci->is_root = is_new_root;
+
reg = reg_read(ohci, OHCI1394_SelfIDCount);
if (reg & OHCI1394_SelfIDCount_selfIDError) {
fw_notify("inconsistent self IDs\n");
self_id_count, ohci->self_id_buffer);
fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation,
- self_id_count, ohci->self_id_buffer);
+ self_id_count, ohci->self_id_buffer,
+ ohci->csr_state_setclear_abdicate);
+ ohci->csr_state_setclear_abdicate = false;
}
static irqreturn_t irq_handler(int irq, void *data)
fw_notify("isochronous cycle inconsistent\n");
}
+ if (event & OHCI1394_cycle64Seconds) {
+ spin_lock(&ohci->lock);
+ update_bus_time(ohci);
+ spin_unlock(&ohci->lock);
+ }
+
return IRQ_HANDLED;
}
memset(&dest[length], 0, CONFIG_ROM_SIZE - size);
}
+static int configure_1394a_enhancements(struct fw_ohci *ohci)
+{
+ bool enable_1394a;
+ int ret, clear, set, offset;
+
+ /* Check if the driver should configure link and PHY. */
+ if (!(reg_read(ohci, OHCI1394_HCControlSet) &
+ OHCI1394_HCControl_programPhyEnable))
+ return 0;
+
+ /* Paranoia: check whether the PHY supports 1394a, too. */
+ enable_1394a = false;
+ ret = read_phy_reg(ohci, 2);
+ if (ret < 0)
+ return ret;
+ if ((ret & PHY_EXTENDED_REGISTERS) == PHY_EXTENDED_REGISTERS) {
+ ret = read_paged_phy_reg(ohci, 1, 8);
+ if (ret < 0)
+ return ret;
+ if (ret >= 1)
+ enable_1394a = true;
+ }
+
+ if (ohci->quirks & QUIRK_NO_1394A)
+ enable_1394a = false;
+
+ /* Configure PHY and link consistently. */
+ if (enable_1394a) {
+ clear = 0;
+ set = PHY_ENABLE_ACCEL | PHY_ENABLE_MULTI;
+ } else {
+ clear = PHY_ENABLE_ACCEL | PHY_ENABLE_MULTI;
+ set = 0;
+ }
+ ret = update_phy_reg(ohci, 5, clear, set);
+ if (ret < 0)
+ return ret;
+
+ if (enable_1394a)
+ offset = OHCI1394_HCControlSet;
+ else
+ offset = OHCI1394_HCControlClear;
+ reg_write(ohci, offset, OHCI1394_HCControl_aPhyEnhanceEnable);
+
+ /* Clean up: configuration has been taken care of. */
+ reg_write(ohci, OHCI1394_HCControlClear,
+ OHCI1394_HCControl_programPhyEnable);
+
+ return 0;
+}
+
static int ohci_enable(struct fw_card *card,
const __be32 *config_rom, size_t length)
{
struct fw_ohci *ohci = fw_ohci(card);
struct pci_dev *dev = to_pci_dev(card->device);
- u32 lps;
- int i;
+ u32 lps, seconds, version, irqs;
+ int i, ret;
if (software_reset(ohci)) {
fw_error("Failed to reset ohci card.\n");
OHCI1394_HCControl_noByteSwapData);
reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
- reg_write(ohci, OHCI1394_LinkControlClear,
- OHCI1394_LinkControl_rcvPhyPkt);
reg_write(ohci, OHCI1394_LinkControlSet,
OHCI1394_LinkControl_rcvSelfID |
+ OHCI1394_LinkControl_rcvPhyPkt |
OHCI1394_LinkControl_cycleTimerEnable |
OHCI1394_LinkControl_cycleMaster);
reg_write(ohci, OHCI1394_ATRetries,
OHCI1394_MAX_AT_REQ_RETRIES |
(OHCI1394_MAX_AT_RESP_RETRIES << 4) |
- (OHCI1394_MAX_PHYS_RESP_RETRIES << 8));
+ (OHCI1394_MAX_PHYS_RESP_RETRIES << 8) |
+ (200 << 16));
+
+ seconds = lower_32_bits(get_seconds());
+ reg_write(ohci, OHCI1394_IsochronousCycleTimer, seconds << 25);
+ ohci->bus_time = seconds & ~0x3f;
+
+ version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
+ if (version >= OHCI_VERSION_1_1) {
+ reg_write(ohci, OHCI1394_InitialChannelsAvailableHi,
+ 0xfffffffe);
+ card->broadcast_channel_auto_allocated = true;
+ }
+
+ /* 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);
+ card->priority_budget_implemented = ohci->pri_req_max != 0;
ar_context_run(&ohci->ar_request_ctx);
ar_context_run(&ohci->ar_response_ctx);
reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000);
reg_write(ohci, OHCI1394_IntEventClear, ~0);
reg_write(ohci, OHCI1394_IntMaskClear, ~0);
- reg_write(ohci, OHCI1394_IntMaskSet,
- OHCI1394_selfIDComplete |
- OHCI1394_RQPkt | OHCI1394_RSPkt |
- OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
- OHCI1394_isochRx | OHCI1394_isochTx |
- OHCI1394_postedWriteErr | OHCI1394_cycleTooLong |
- OHCI1394_cycleInconsistent | OHCI1394_regAccessFail |
- OHCI1394_masterIntEnable);
- if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
- reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
+
+ ret = configure_1394a_enhancements(ohci);
+ if (ret < 0)
+ return ret;
/* Activate link_on bit and contender bit in our self ID packets.*/
- if (ohci_update_phy_reg(card, 4, 0,
- PHY_LINK_ACTIVE | PHY_CONTENDER) < 0)
- return -EIO;
+ ret = ohci_update_phy_reg(card, 4, 0, PHY_LINK_ACTIVE | PHY_CONTENDER);
+ if (ret < 0)
+ return ret;
/*
* When the link is not yet enabled, the atomic config rom
reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
+ if (!(ohci->quirks & QUIRK_NO_MSI))
+ pci_enable_msi(dev);
if (request_irq(dev->irq, irq_handler,
- IRQF_SHARED, ohci_driver_name, ohci)) {
- fw_error("Failed to allocate shared interrupt %d.\n",
- dev->irq);
+ pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED,
+ ohci_driver_name, ohci)) {
+ fw_error("Failed to allocate interrupt %d.\n", dev->irq);
+ pci_disable_msi(dev);
dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
ohci->config_rom, ohci->config_rom_bus);
return -EIO;
}
+ irqs = OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
+ OHCI1394_RQPkt | OHCI1394_RSPkt |
+ OHCI1394_isochTx | OHCI1394_isochRx |
+ OHCI1394_postedWriteErr |
+ OHCI1394_selfIDComplete |
+ OHCI1394_regAccessFail |
+ OHCI1394_cycle64Seconds |
+ OHCI1394_cycleInconsistent | OHCI1394_cycleTooLong |
+ OHCI1394_masterIntEnable;
+ if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
+ irqs |= OHCI1394_busReset;
+ reg_write(ohci, OHCI1394_IntMaskSet, irqs);
+
reg_write(ohci, OHCI1394_HCControlSet,
OHCI1394_HCControl_linkEnable |
OHCI1394_HCControl_BIBimageValid);
flush_writes(ohci);
- /*
- * We are ready to go, initiate bus reset to finish the
- * initialization.
- */
-
- fw_core_initiate_bus_reset(&ohci->card, 1);
+ /* We are ready to go, reset bus to finish initialization. */
+ fw_schedule_bus_reset(&ohci->card, false, true);
return 0;
}
* takes effect.
*/
if (ret == 0)
- fw_core_initiate_bus_reset(&ohci->card, 1);
+ fw_schedule_bus_reset(&ohci->card, true, true);
else
dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
next_config_rom, next_config_rom_bus);
#endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */
}
-static u32 cycle_timer_ticks(u32 cycle_timer)
+static u32 ohci_read_csr(struct fw_card *card, int csr_offset)
{
- u32 ticks;
+ struct fw_ohci *ohci = fw_ohci(card);
+ unsigned long flags;
+ u32 value;
+
+ switch (csr_offset) {
+ case CSR_STATE_CLEAR:
+ case CSR_STATE_SET:
+ if (ohci->is_root &&
+ (reg_read(ohci, OHCI1394_LinkControlSet) &
+ OHCI1394_LinkControl_cycleMaster))
+ value = CSR_STATE_BIT_CMSTR;
+ else
+ value = 0;
+ if (ohci->csr_state_setclear_abdicate)
+ value |= CSR_STATE_BIT_ABDICATE;
- ticks = cycle_timer & 0xfff;
- ticks += 3072 * ((cycle_timer >> 12) & 0x1fff);
- ticks += (3072 * 8000) * (cycle_timer >> 25);
+ return value;
- return ticks;
+ case CSR_NODE_IDS:
+ return reg_read(ohci, OHCI1394_NodeID) << 16;
+
+ case CSR_CYCLE_TIME:
+ return get_cycle_time(ohci);
+
+ case CSR_BUS_TIME:
+ /*
+ * We might be called just after the cycle timer has wrapped
+ * around but just before the cycle64Seconds handler, so we
+ * better check here, too, if the bus time needs to be updated.
+ */
+ spin_lock_irqsave(&ohci->lock, flags);
+ value = update_bus_time(ohci);
+ spin_unlock_irqrestore(&ohci->lock, flags);
+ return value;
+
+ case CSR_BUSY_TIMEOUT:
+ 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;
+ }
}
-/*
- * Some controllers exhibit one or more of the following bugs when updating the
- * iso cycle timer register:
- * - When the lowest six bits are wrapping around to zero, a read that happens
- * at the same time will return garbage in the lowest ten bits.
- * - When the cycleOffset field wraps around to zero, the cycleCount field is
- * not incremented for about 60 ns.
- * - Occasionally, the entire register reads zero.
- *
- * To catch these, we read the register three times and ensure that the
- * difference between each two consecutive reads is approximately the same, i.e.
- * less than twice the other. Furthermore, any negative difference indicates an
- * error. (A PCI read should take at least 20 ticks of the 24.576 MHz timer to
- * execute, so we have enough precision to compute the ratio of the differences.)
- */
-static u32 ohci_get_cycle_time(struct fw_card *card)
+static void ohci_write_csr(struct fw_card *card, int csr_offset, u32 value)
{
struct fw_ohci *ohci = fw_ohci(card);
- u32 c0, c1, c2;
- u32 t0, t1, t2;
- s32 diff01, diff12;
- int i;
+ unsigned long flags;
- c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+ switch (csr_offset) {
+ case CSR_STATE_CLEAR:
+ if ((value & CSR_STATE_BIT_CMSTR) && ohci->is_root) {
+ reg_write(ohci, OHCI1394_LinkControlClear,
+ OHCI1394_LinkControl_cycleMaster);
+ flush_writes(ohci);
+ }
+ if (value & CSR_STATE_BIT_ABDICATE)
+ ohci->csr_state_setclear_abdicate = false;
+ break;
- if (ohci->quirks & QUIRK_CYCLE_TIMER) {
- i = 0;
- c1 = c2;
- c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
- do {
- c0 = c1;
- c1 = c2;
- c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
- t0 = cycle_timer_ticks(c0);
- t1 = cycle_timer_ticks(c1);
- t2 = cycle_timer_ticks(c2);
- diff01 = t1 - t0;
- diff12 = t2 - t1;
- } while ((diff01 <= 0 || diff12 <= 0 ||
- diff01 / diff12 >= 2 || diff12 / diff01 >= 2)
- && i++ < 20);
- }
+ case CSR_STATE_SET:
+ if ((value & CSR_STATE_BIT_CMSTR) && ohci->is_root) {
+ reg_write(ohci, OHCI1394_LinkControlSet,
+ OHCI1394_LinkControl_cycleMaster);
+ flush_writes(ohci);
+ }
+ if (value & CSR_STATE_BIT_ABDICATE)
+ ohci->csr_state_setclear_abdicate = true;
+ break;
- return c2;
+ case CSR_NODE_IDS:
+ reg_write(ohci, OHCI1394_NodeID, value >> 16);
+ flush_writes(ohci);
+ break;
+
+ case CSR_CYCLE_TIME:
+ reg_write(ohci, OHCI1394_IsochronousCycleTimer, value);
+ reg_write(ohci, OHCI1394_IntEventSet,
+ OHCI1394_cycleInconsistent);
+ flush_writes(ohci);
+ break;
+
+ case CSR_BUS_TIME:
+ spin_lock_irqsave(&ohci->lock, flags);
+ ohci->bus_time = (ohci->bus_time & 0x7f) | (value & ~0x7f);
+ spin_unlock_irqrestore(&ohci->lock, flags);
+ break;
+
+ case CSR_BUSY_TIMEOUT:
+ value = (value & 0xf) | ((value & 0xf) << 4) |
+ ((value & 0xf) << 8) | ((value & 0x0ffff000) << 4);
+ reg_write(ohci, OHCI1394_ATRetries, 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 void copy_iso_headers(struct iso_context *ctx, void *p)
static const struct fw_card_driver ohci_driver = {
.enable = ohci_enable,
+ .read_phy_reg = ohci_read_phy_reg,
.update_phy_reg = ohci_update_phy_reg,
.set_config_rom = ohci_set_config_rom,
.send_request = ohci_send_request,
.send_response = ohci_send_response,
.cancel_packet = ohci_cancel_packet,
.enable_phys_dma = ohci_enable_phys_dma,
- .get_cycle_time = ohci_get_cycle_time,
+ .read_csr = ohci_read_csr,
+ .write_csr = ohci_write_csr,
.allocate_iso_context = ohci_allocate_iso_context,
.free_iso_context = ohci_free_iso_context,
};
#ifdef CONFIG_PPC_PMAC
-static void ohci_pmac_on(struct pci_dev *dev)
+static void pmac_ohci_on(struct pci_dev *dev)
{
if (machine_is(powermac)) {
struct device_node *ofn = pci_device_to_OF_node(dev);
}
}
-static void ohci_pmac_off(struct pci_dev *dev)
+static void pmac_ohci_off(struct pci_dev *dev)
{
if (machine_is(powermac)) {
struct device_node *ofn = pci_device_to_OF_node(dev);
}
}
#else
-#define ohci_pmac_on(dev)
-#define ohci_pmac_off(dev)
+static inline void pmac_ohci_on(struct pci_dev *dev) {}
+static inline void pmac_ohci_off(struct pci_dev *dev) {}
#endif /* CONFIG_PPC_PMAC */
static int __devinit pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
struct fw_ohci *ohci;
- u32 bus_options, max_receive, link_speed, version;
+ u32 bus_options, max_receive, link_speed, version, link_enh;
u64 guid;
int i, err, n_ir, n_it;
size_t size;
fw_card_initialize(&ohci->card, &ohci_driver, &dev->dev);
- ohci_pmac_on(dev);
+ pmac_ohci_on(dev);
err = pci_enable_device(dev);
if (err) {
pci_set_drvdata(dev, ohci);
spin_lock_init(&ohci->lock);
+ mutex_init(&ohci->phy_reg_mutex);
tasklet_init(&ohci->bus_reset_tasklet,
bus_reset_tasklet, (unsigned long)ohci);
if (param_quirks)
ohci->quirks = param_quirks;
+ /* TI OHCI-Lynx and compatible: set recommended configuration bits. */
+ if (dev->vendor == PCI_VENDOR_ID_TI) {
+ pci_read_config_dword(dev, PCI_CFG_TI_LinkEnh, &link_enh);
+
+ /* adjust latency of ATx FIFO: use 1.7 KB threshold */
+ link_enh &= ~TI_LinkEnh_atx_thresh_mask;
+ link_enh |= TI_LinkEnh_atx_thresh_1_7K;
+
+ /* use priority arbitration for asynchronous responses */
+ link_enh |= TI_LinkEnh_enab_unfair;
+
+ /* required for aPhyEnhanceEnable to work */
+ link_enh |= TI_LinkEnh_enab_accel;
+
+ pci_write_config_dword(dev, PCI_CFG_TI_LinkEnh, link_enh);
+ }
+
ar_context_init(&ohci->ar_request_ctx, ohci,
OHCI1394_AsReqRcvContextControlSet);
pci_disable_device(dev);
fail_free:
kfree(&ohci->card);
- ohci_pmac_off(dev);
+ pmac_ohci_off(dev);
fail:
if (err == -ENOMEM)
fw_error("Out of memory\n");
context_release(&ohci->at_response_ctx);
kfree(ohci->it_context_list);
kfree(ohci->ir_context_list);
+ pci_disable_msi(dev);
pci_iounmap(dev, ohci->registers);
pci_release_region(dev, 0);
pci_disable_device(dev);
kfree(&ohci->card);
- ohci_pmac_off(dev);
+ pmac_ohci_off(dev);
fw_notify("Removed fw-ohci device.\n");
}
software_reset(ohci);
free_irq(dev->irq, ohci);
+ pci_disable_msi(dev);
err = pci_save_state(dev);
if (err) {
fw_error("pci_save_state failed\n");
err = pci_set_power_state(dev, pci_choose_state(dev, state));
if (err)
fw_error("pci_set_power_state failed with %d\n", err);
- ohci_pmac_off(dev);
+ pmac_ohci_off(dev);
return 0;
}
struct fw_ohci *ohci = pci_get_drvdata(dev);
int err;
- ohci_pmac_on(dev);
+ pmac_ohci_on(dev);
pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
err = pci_enable_device(dev);