diff options
Diffstat (limited to 'drivers/firewire')
-rw-r--r-- | drivers/firewire/ohci.c | 185 |
1 files changed, 183 insertions, 2 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index c026f46fc157..b983581cfe35 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c | |||
@@ -264,6 +264,8 @@ static char ohci_driver_name[] = KBUILD_MODNAME; | |||
264 | #define PCI_DEVICE_ID_AGERE_FW643 0x5901 | 264 | #define PCI_DEVICE_ID_AGERE_FW643 0x5901 |
265 | #define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380 | 265 | #define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380 |
266 | #define PCI_DEVICE_ID_TI_TSB12LV22 0x8009 | 266 | #define PCI_DEVICE_ID_TI_TSB12LV22 0x8009 |
267 | #define PCI_DEVICE_ID_TI_TSB12LV26 0x8020 | ||
268 | #define PCI_DEVICE_ID_TI_TSB82AA2 0x8025 | ||
267 | #define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd | 269 | #define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd |
268 | 270 | ||
269 | #define QUIRK_CYCLE_TIMER 1 | 271 | #define QUIRK_CYCLE_TIMER 1 |
@@ -271,6 +273,7 @@ static char ohci_driver_name[] = KBUILD_MODNAME; | |||
271 | #define QUIRK_BE_HEADERS 4 | 273 | #define QUIRK_BE_HEADERS 4 |
272 | #define QUIRK_NO_1394A 8 | 274 | #define QUIRK_NO_1394A 8 |
273 | #define QUIRK_NO_MSI 16 | 275 | #define QUIRK_NO_MSI 16 |
276 | #define QUIRK_TI_SLLZ059 32 | ||
274 | 277 | ||
275 | /* In case of multiple matches in ohci_quirks[], only the first one is used. */ | 278 | /* In case of multiple matches in ohci_quirks[], only the first one is used. */ |
276 | static const struct { | 279 | static const struct { |
@@ -300,6 +303,12 @@ static const struct { | |||
300 | {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID, | 303 | {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID, |
301 | QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A}, | 304 | QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A}, |
302 | 305 | ||
306 | {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV26, PCI_ANY_ID, | ||
307 | QUIRK_RESET_PACKET | QUIRK_TI_SLLZ059}, | ||
308 | |||
309 | {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB82AA2, PCI_ANY_ID, | ||
310 | QUIRK_RESET_PACKET | QUIRK_TI_SLLZ059}, | ||
311 | |||
303 | {PCI_VENDOR_ID_TI, PCI_ANY_ID, PCI_ANY_ID, | 312 | {PCI_VENDOR_ID_TI, PCI_ANY_ID, PCI_ANY_ID, |
304 | QUIRK_RESET_PACKET}, | 313 | QUIRK_RESET_PACKET}, |
305 | 314 | ||
@@ -316,6 +325,7 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0" | |||
316 | ", AR/selfID endianess = " __stringify(QUIRK_BE_HEADERS) | 325 | ", AR/selfID endianess = " __stringify(QUIRK_BE_HEADERS) |
317 | ", no 1394a enhancements = " __stringify(QUIRK_NO_1394A) | 326 | ", no 1394a enhancements = " __stringify(QUIRK_NO_1394A) |
318 | ", disable MSI = " __stringify(QUIRK_NO_MSI) | 327 | ", disable MSI = " __stringify(QUIRK_NO_MSI) |
328 | ", workaround for TI SLLZ059 errata = " __stringify(QUIRK_TI_SLLZ059) | ||
319 | ")"); | 329 | ")"); |
320 | 330 | ||
321 | #define OHCI_PARAM_DEBUG_AT_AR 1 | 331 | #define OHCI_PARAM_DEBUG_AT_AR 1 |
@@ -1714,6 +1724,114 @@ static u32 update_bus_time(struct fw_ohci *ohci) | |||
1714 | return ohci->bus_time | cycle_time_seconds; | 1724 | return ohci->bus_time | cycle_time_seconds; |
1715 | } | 1725 | } |
1716 | 1726 | ||
1727 | static int get_status_for_port(struct fw_ohci *ohci, int port_index) | ||
1728 | { | ||
1729 | int reg; | ||
1730 | |||
1731 | mutex_lock(&ohci->phy_reg_mutex); | ||
1732 | reg = write_phy_reg(ohci, 7, port_index); | ||
1733 | mutex_unlock(&ohci->phy_reg_mutex); | ||
1734 | if (reg < 0) | ||
1735 | return reg; | ||
1736 | |||
1737 | mutex_lock(&ohci->phy_reg_mutex); | ||
1738 | reg = read_phy_reg(ohci, 8); | ||
1739 | mutex_unlock(&ohci->phy_reg_mutex); | ||
1740 | if (reg < 0) | ||
1741 | return reg; | ||
1742 | |||
1743 | switch (reg & 0x0f) { | ||
1744 | case 0x06: | ||
1745 | return 2; /* is child node (connected to parent node) */ | ||
1746 | case 0x0e: | ||
1747 | return 3; /* is parent node (connected to child node) */ | ||
1748 | } | ||
1749 | return 1; /* not connected */ | ||
1750 | } | ||
1751 | |||
1752 | static int get_self_id_pos(struct fw_ohci *ohci, u32 self_id, | ||
1753 | int self_id_count) | ||
1754 | { | ||
1755 | int i; | ||
1756 | u32 entry; | ||
1757 | for (i = 0; i < self_id_count; i++) { | ||
1758 | entry = ohci->self_id_buffer[i]; | ||
1759 | if ((self_id & 0xff000000) == (entry & 0xff000000)) | ||
1760 | return -1; | ||
1761 | if ((self_id & 0xff000000) < (entry & 0xff000000)) | ||
1762 | return i; | ||
1763 | } | ||
1764 | return i; | ||
1765 | } | ||
1766 | |||
1767 | /* | ||
1768 | * This function implements a work around for the Texas Instruments PHY | ||
1769 | * TSB41BA3D. This phy has a bug at least in combination with the TI | ||
1770 | * LLCs TSB82AA2B and TSB12LV26. The selfid coming from the locally | ||
1771 | * connected phy is not propagated into the selfid buffer of the OHCI | ||
1772 | * (see http://www.ti.com/litv/pdf/sllz059 for details). | ||
1773 | * The main idea is to construct the selfid ourselves. | ||
1774 | */ | ||
1775 | |||
1776 | static int find_and_insert_self_id(struct fw_ohci *ohci, int self_id_count) | ||
1777 | { | ||
1778 | int reg; | ||
1779 | int i; | ||
1780 | int pos; | ||
1781 | int status; | ||
1782 | u32 self_id; | ||
1783 | |||
1784 | /* | ||
1785 | * preset bits in self_id | ||
1786 | * | ||
1787 | * link active: 0b1 | ||
1788 | * speed: 0b11 | ||
1789 | * bridge: 0b00 | ||
1790 | * contender: 0b1 | ||
1791 | * initiated reset: 0b0 | ||
1792 | * more packets: 0b0 | ||
1793 | */ | ||
1794 | self_id = 0x8040C800; | ||
1795 | |||
1796 | reg = reg_read(ohci, OHCI1394_NodeID); | ||
1797 | if (!(reg & OHCI1394_NodeID_idValid)) { | ||
1798 | fw_notify("node ID not valid, new bus reset in progress\n"); | ||
1799 | return -EBUSY; | ||
1800 | } | ||
1801 | self_id |= ((reg & 0x3f) << 24); /* phy ID */ | ||
1802 | |||
1803 | mutex_lock(&ohci->phy_reg_mutex); | ||
1804 | reg = read_phy_reg(ohci, 4); | ||
1805 | mutex_unlock(&ohci->phy_reg_mutex); | ||
1806 | if (reg < 0) | ||
1807 | return reg; | ||
1808 | self_id |= ((reg & 0x07) << 8); /* power class */ | ||
1809 | |||
1810 | mutex_lock(&ohci->phy_reg_mutex); | ||
1811 | reg = read_phy_reg(ohci, 1); | ||
1812 | mutex_unlock(&ohci->phy_reg_mutex); | ||
1813 | if (reg < 0) | ||
1814 | return reg; | ||
1815 | self_id |= ((reg & 0x3f) << 16); /* gap count */ | ||
1816 | |||
1817 | for (i = 0; i < 3; i++) { | ||
1818 | status = get_status_for_port(ohci, i); | ||
1819 | if (status < 0) | ||
1820 | return status; | ||
1821 | self_id |= ((status & 0x3) << (6 - (i * 2))); | ||
1822 | } | ||
1823 | |||
1824 | pos = get_self_id_pos(ohci, self_id, self_id_count); | ||
1825 | if (pos >= 0) { | ||
1826 | memmove(&(ohci->self_id_buffer[pos+1]), | ||
1827 | &(ohci->self_id_buffer[pos]), | ||
1828 | (self_id_count - pos) * sizeof(*ohci->self_id_buffer)); | ||
1829 | ohci->self_id_buffer[pos] = self_id; | ||
1830 | self_id_count++; | ||
1831 | } | ||
1832 | return self_id_count; | ||
1833 | } | ||
1834 | |||
1717 | static void bus_reset_work(struct work_struct *work) | 1835 | static void bus_reset_work(struct work_struct *work) |
1718 | { | 1836 | { |
1719 | struct fw_ohci *ohci = | 1837 | struct fw_ohci *ohci = |
@@ -1755,10 +1873,12 @@ static void bus_reset_work(struct work_struct *work) | |||
1755 | * bit extra to get the actual number of self IDs. | 1873 | * bit extra to get the actual number of self IDs. |
1756 | */ | 1874 | */ |
1757 | self_id_count = (reg >> 3) & 0xff; | 1875 | self_id_count = (reg >> 3) & 0xff; |
1758 | if (self_id_count == 0 || self_id_count > 252) { | 1876 | |
1877 | if (self_id_count > 252) { | ||
1759 | fw_notify("inconsistent self IDs\n"); | 1878 | fw_notify("inconsistent self IDs\n"); |
1760 | return; | 1879 | return; |
1761 | } | 1880 | } |
1881 | |||
1762 | generation = (cond_le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff; | 1882 | generation = (cond_le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff; |
1763 | rmb(); | 1883 | rmb(); |
1764 | 1884 | ||
@@ -1770,6 +1890,19 @@ static void bus_reset_work(struct work_struct *work) | |||
1770 | ohci->self_id_buffer[j] = | 1890 | ohci->self_id_buffer[j] = |
1771 | cond_le32_to_cpu(ohci->self_id_cpu[i]); | 1891 | cond_le32_to_cpu(ohci->self_id_cpu[i]); |
1772 | } | 1892 | } |
1893 | |||
1894 | if (ohci->quirks & QUIRK_TI_SLLZ059) { | ||
1895 | self_id_count = find_and_insert_self_id(ohci, self_id_count); | ||
1896 | if (self_id_count < 0) { | ||
1897 | fw_notify("could not construct local self IDs\n"); | ||
1898 | return; | ||
1899 | } | ||
1900 | } | ||
1901 | |||
1902 | if (self_id_count == 0) { | ||
1903 | fw_notify("inconsistent self IDs\n"); | ||
1904 | return; | ||
1905 | } | ||
1773 | rmb(); | 1906 | rmb(); |
1774 | 1907 | ||
1775 | /* | 1908 | /* |
@@ -2050,13 +2183,50 @@ static int configure_1394a_enhancements(struct fw_ohci *ohci) | |||
2050 | return 0; | 2183 | return 0; |
2051 | } | 2184 | } |
2052 | 2185 | ||
2186 | #define TSB41BA3D_VID 0x00080028 | ||
2187 | #define TSB41BA3D_PID 0x00833005 | ||
2188 | |||
2189 | static int probe_tsb41ba3d(struct fw_ohci *ohci) | ||
2190 | { | ||
2191 | int reg; | ||
2192 | int i; | ||
2193 | int vendor_id; | ||
2194 | int product_id; | ||
2195 | |||
2196 | reg = read_phy_reg(ohci, 2); | ||
2197 | if (reg < 0) | ||
2198 | return reg; | ||
2199 | |||
2200 | if ((reg & PHY_EXTENDED_REGISTERS) == PHY_EXTENDED_REGISTERS) { | ||
2201 | vendor_id = 0; | ||
2202 | for (i = 10; i < 13; i++) { | ||
2203 | reg = read_paged_phy_reg(ohci, 1, i); | ||
2204 | if (reg < 0) | ||
2205 | return reg; | ||
2206 | vendor_id = (vendor_id << 8) | reg; | ||
2207 | } | ||
2208 | product_id = 0; | ||
2209 | for (i = 13; i < 16; i++) { | ||
2210 | reg = read_paged_phy_reg(ohci, 1, i); | ||
2211 | if (reg < 0) | ||
2212 | return reg; | ||
2213 | product_id = (product_id << 8) | reg; | ||
2214 | } | ||
2215 | |||
2216 | if ((vendor_id == TSB41BA3D_VID) && | ||
2217 | (product_id == TSB41BA3D_PID)) | ||
2218 | return 1; | ||
2219 | } | ||
2220 | return 0; | ||
2221 | } | ||
2222 | |||
2053 | static int ohci_enable(struct fw_card *card, | 2223 | static int ohci_enable(struct fw_card *card, |
2054 | const __be32 *config_rom, size_t length) | 2224 | const __be32 *config_rom, size_t length) |
2055 | { | 2225 | { |
2056 | struct fw_ohci *ohci = fw_ohci(card); | 2226 | struct fw_ohci *ohci = fw_ohci(card); |
2057 | struct pci_dev *dev = to_pci_dev(card->device); | 2227 | struct pci_dev *dev = to_pci_dev(card->device); |
2058 | u32 lps, seconds, version, irqs; | 2228 | u32 lps, seconds, version, irqs; |
2059 | int i, ret; | 2229 | int i, ret, tsb41ba3d_found; |
2060 | 2230 | ||
2061 | if (software_reset(ohci)) { | 2231 | if (software_reset(ohci)) { |
2062 | fw_error("Failed to reset ohci card.\n"); | 2232 | fw_error("Failed to reset ohci card.\n"); |
@@ -2087,6 +2257,17 @@ static int ohci_enable(struct fw_card *card, | |||
2087 | return -EIO; | 2257 | return -EIO; |
2088 | } | 2258 | } |
2089 | 2259 | ||
2260 | if (ohci->quirks & QUIRK_TI_SLLZ059) { | ||
2261 | tsb41ba3d_found = probe_tsb41ba3d(ohci); | ||
2262 | if (tsb41ba3d_found < 0) | ||
2263 | return tsb41ba3d_found; | ||
2264 | if (!tsb41ba3d_found) { | ||
2265 | fw_notify("No TSB41BA3D found, " | ||
2266 | "resetting QUIRK_TI_SLLZ059\n"); | ||
2267 | ohci->quirks &= ~QUIRK_TI_SLLZ059; | ||
2268 | } | ||
2269 | } | ||
2270 | |||
2090 | reg_write(ohci, OHCI1394_HCControlClear, | 2271 | reg_write(ohci, OHCI1394_HCControlClear, |
2091 | OHCI1394_HCControl_noByteSwapData); | 2272 | OHCI1394_HCControl_noByteSwapData); |
2092 | 2273 | ||