Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 272389
b: refs/heads/master
c: 25935eb
h: refs/heads/master
i:
  272387: 3a8bd96
v: v3
  • Loading branch information
Stephan Gatzka authored and Stefan Richter committed Sep 16, 2011
1 parent c20e273 commit 2984f88
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 2d7a36e23300d268599f6eae4093643d22fbb356
refs/heads/master: 25935ebebd861182ac58ecea67718bb6a617c7cb
185 changes: 183 additions & 2 deletions trunk/drivers/firewire/ohci.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,13 +264,16 @@ static char ohci_driver_name[] = KBUILD_MODNAME;
#define PCI_DEVICE_ID_AGERE_FW643 0x5901
#define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380
#define PCI_DEVICE_ID_TI_TSB12LV22 0x8009
#define PCI_DEVICE_ID_TI_TSB12LV26 0x8020
#define PCI_DEVICE_ID_TI_TSB82AA2 0x8025
#define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd

#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
#define QUIRK_TI_SLLZ059 32

/* In case of multiple matches in ohci_quirks[], only the first one is used. */
static const struct {
Expand Down Expand Up @@ -300,6 +303,12 @@ static const struct {
{PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID,
QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A},

{PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV26, PCI_ANY_ID,
QUIRK_RESET_PACKET | QUIRK_TI_SLLZ059},

{PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB82AA2, PCI_ANY_ID,
QUIRK_RESET_PACKET | QUIRK_TI_SLLZ059},

{PCI_VENDOR_ID_TI, PCI_ANY_ID, PCI_ANY_ID,
QUIRK_RESET_PACKET},

Expand All @@ -316,6 +325,7 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
", AR/selfID endianess = " __stringify(QUIRK_BE_HEADERS)
", no 1394a enhancements = " __stringify(QUIRK_NO_1394A)
", disable MSI = " __stringify(QUIRK_NO_MSI)
", workaround for TI SLLZ059 errata = " __stringify(QUIRK_TI_SLLZ059)
")");

#define OHCI_PARAM_DEBUG_AT_AR 1
Expand Down Expand Up @@ -1714,6 +1724,114 @@ static u32 update_bus_time(struct fw_ohci *ohci)
return ohci->bus_time | cycle_time_seconds;
}

static int get_status_for_port(struct fw_ohci *ohci, int port_index)
{
int reg;

mutex_lock(&ohci->phy_reg_mutex);
reg = write_phy_reg(ohci, 7, port_index);
mutex_unlock(&ohci->phy_reg_mutex);
if (reg < 0)
return reg;

mutex_lock(&ohci->phy_reg_mutex);
reg = read_phy_reg(ohci, 8);
mutex_unlock(&ohci->phy_reg_mutex);
if (reg < 0)
return reg;

switch (reg & 0x0f) {
case 0x06:
return 2; /* is child node (connected to parent node) */
case 0x0e:
return 3; /* is parent node (connected to child node) */
}
return 1; /* not connected */
}

static int get_self_id_pos(struct fw_ohci *ohci, u32 self_id,
int self_id_count)
{
int i;
u32 entry;
for (i = 0; i < self_id_count; i++) {
entry = ohci->self_id_buffer[i];
if ((self_id & 0xff000000) == (entry & 0xff000000))
return -1;
if ((self_id & 0xff000000) < (entry & 0xff000000))
return i;
}
return i;
}

/*
* This function implements a work around for the Texas Instruments PHY
* TSB41BA3D. This phy has a bug at least in combination with the TI
* LLCs TSB82AA2B and TSB12LV26. The selfid coming from the locally
* connected phy is not propagated into the selfid buffer of the OHCI
* (see http://www.ti.com/litv/pdf/sllz059 for details).
* The main idea is to construct the selfid ourselves.
*/

static int find_and_insert_self_id(struct fw_ohci *ohci, int self_id_count)
{
int reg;
int i;
int pos;
int status;
u32 self_id;

/*
* preset bits in self_id
*
* link active: 0b1
* speed: 0b11
* bridge: 0b00
* contender: 0b1
* initiated reset: 0b0
* more packets: 0b0
*/
self_id = 0x8040C800;

reg = reg_read(ohci, OHCI1394_NodeID);
if (!(reg & OHCI1394_NodeID_idValid)) {
fw_notify("node ID not valid, new bus reset in progress\n");
return -EBUSY;
}
self_id |= ((reg & 0x3f) << 24); /* phy ID */

mutex_lock(&ohci->phy_reg_mutex);
reg = read_phy_reg(ohci, 4);
mutex_unlock(&ohci->phy_reg_mutex);
if (reg < 0)
return reg;
self_id |= ((reg & 0x07) << 8); /* power class */

mutex_lock(&ohci->phy_reg_mutex);
reg = read_phy_reg(ohci, 1);
mutex_unlock(&ohci->phy_reg_mutex);
if (reg < 0)
return reg;
self_id |= ((reg & 0x3f) << 16); /* gap count */

for (i = 0; i < 3; i++) {
status = get_status_for_port(ohci, i);
if (status < 0)
return status;
self_id |= ((status & 0x3) << (6 - (i * 2)));
}

pos = get_self_id_pos(ohci, self_id, self_id_count);
if (pos >= 0) {
memmove(&(ohci->self_id_buffer[pos+1]),
&(ohci->self_id_buffer[pos]),
(self_id_count - pos) * sizeof(*ohci->self_id_buffer));
ohci->self_id_buffer[pos] = self_id;
self_id_count++;
}
return self_id_count;
}

static void bus_reset_work(struct work_struct *work)
{
struct fw_ohci *ohci =
Expand Down Expand Up @@ -1755,10 +1873,12 @@ static void bus_reset_work(struct work_struct *work)
* bit extra to get the actual number of self IDs.
*/
self_id_count = (reg >> 3) & 0xff;
if (self_id_count == 0 || self_id_count > 252) {

if (self_id_count > 252) {
fw_notify("inconsistent self IDs\n");
return;
}

generation = (cond_le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff;
rmb();

Expand All @@ -1770,6 +1890,19 @@ static void bus_reset_work(struct work_struct *work)
ohci->self_id_buffer[j] =
cond_le32_to_cpu(ohci->self_id_cpu[i]);
}

if (ohci->quirks & QUIRK_TI_SLLZ059) {
self_id_count = find_and_insert_self_id(ohci, self_id_count);
if (self_id_count < 0) {
fw_notify("could not construct local self IDs\n");
return;
}
}

if (self_id_count == 0) {
fw_notify("inconsistent self IDs\n");
return;
}
rmb();

/*
Expand Down Expand Up @@ -2050,13 +2183,50 @@ static int configure_1394a_enhancements(struct fw_ohci *ohci)
return 0;
}

#define TSB41BA3D_VID 0x00080028
#define TSB41BA3D_PID 0x00833005

static int probe_tsb41ba3d(struct fw_ohci *ohci)
{
int reg;
int i;
int vendor_id;
int product_id;

reg = read_phy_reg(ohci, 2);
if (reg < 0)
return reg;

if ((reg & PHY_EXTENDED_REGISTERS) == PHY_EXTENDED_REGISTERS) {
vendor_id = 0;
for (i = 10; i < 13; i++) {
reg = read_paged_phy_reg(ohci, 1, i);
if (reg < 0)
return reg;
vendor_id = (vendor_id << 8) | reg;
}
product_id = 0;
for (i = 13; i < 16; i++) {
reg = read_paged_phy_reg(ohci, 1, i);
if (reg < 0)
return reg;
product_id = (product_id << 8) | reg;
}

if ((vendor_id == TSB41BA3D_VID) &&
(product_id == TSB41BA3D_PID))
return 1;
}
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, seconds, version, irqs;
int i, ret;
int i, ret, tsb41ba3d_found;

if (software_reset(ohci)) {
fw_error("Failed to reset ohci card.\n");
Expand Down Expand Up @@ -2087,6 +2257,17 @@ static int ohci_enable(struct fw_card *card,
return -EIO;
}

if (ohci->quirks & QUIRK_TI_SLLZ059) {
tsb41ba3d_found = probe_tsb41ba3d(ohci);
if (tsb41ba3d_found < 0)
return tsb41ba3d_found;
if (!tsb41ba3d_found) {
fw_notify("No TSB41BA3D found, "
"resetting QUIRK_TI_SLLZ059\n");
ohci->quirks &= ~QUIRK_TI_SLLZ059;
}
}

reg_write(ohci, OHCI1394_HCControlClear,
OHCI1394_HCControl_noByteSwapData);

Expand Down

0 comments on commit 2984f88

Please sign in to comment.