summaryrefslogtreecommitdiff
path: root/drivers/net/tg3.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2005-05-18 22:50:10 -0700
committerDavid S. Miller <davem@davemloft.net>2005-05-18 22:50:10 -0700
commit59e6b4343299373bc10dd131ab5142f53ddd838a (patch)
tree1381e9d661f4ff83e89cb17678ce4813a90c4afb /drivers/net/tg3.c
parent15f9850d3c2d46f5851a424d2990a18b5bb5ebfd (diff)
downloadlinux-3.10-59e6b4343299373bc10dd131ab5142f53ddd838a.tar.gz
linux-3.10-59e6b4343299373bc10dd131ab5142f53ddd838a.tar.bz2
linux-3.10-59e6b4343299373bc10dd131ab5142f53ddd838a.zip
[TG3]: Refine DMA boundary setting.
Extract DMA boundary bit selection into a seperate function, tg3_calc_dma_bndry(). Call this from tg3_test_dma(). Make DMA test more reliable by using no DMA boundry setting during the test. If the test passes, then use the setting we selected before the test. Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Michael Chan <mchan@broadcom.com>
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r--drivers/net/tg3.c207
1 files changed, 163 insertions, 44 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 3df5b78d269..4ab9680ffbd 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -8775,6 +8775,146 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
return 0;
}
+#define BOUNDARY_SINGLE_CACHELINE 1
+#define BOUNDARY_MULTI_CACHELINE 2
+
+static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
+{
+ int cacheline_size;
+ u8 byte;
+ int goal;
+
+ pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, &byte);
+ if (byte == 0)
+ cacheline_size = 1024;
+ else
+ cacheline_size = (int) byte * 4;
+
+ /* On 5703 and later chips, the boundary bits have no
+ * effect.
+ */
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 &&
+ !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
+ goto out;
+
+#if defined(CONFIG_PPC64) || defined(CONFIG_IA64) || defined(CONFIG_PARISC)
+ goal = BOUNDARY_MULTI_CACHELINE;
+#else
+#if defined(CONFIG_SPARC64) || defined(CONFIG_ALPHA)
+ goal = BOUNDARY_SINGLE_CACHELINE;
+#else
+ goal = 0;
+#endif
+#endif
+
+ if (!goal)
+ goto out;
+
+ /* PCI controllers on most RISC systems tend to disconnect
+ * when a device tries to burst across a cache-line boundary.
+ * Therefore, letting tg3 do so just wastes PCI bandwidth.
+ *
+ * Unfortunately, for PCI-E there are only limited
+ * write-side controls for this, and thus for reads
+ * we will still get the disconnects. We'll also waste
+ * these PCI cycles for both read and write for chips
+ * other than 5700 and 5701 which do not implement the
+ * boundary bits.
+ */
+ if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
+ !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) {
+ switch (cacheline_size) {
+ case 16:
+ case 32:
+ case 64:
+ case 128:
+ if (goal == BOUNDARY_SINGLE_CACHELINE) {
+ val |= (DMA_RWCTRL_READ_BNDRY_128_PCIX |
+ DMA_RWCTRL_WRITE_BNDRY_128_PCIX);
+ } else {
+ val |= (DMA_RWCTRL_READ_BNDRY_384_PCIX |
+ DMA_RWCTRL_WRITE_BNDRY_384_PCIX);
+ }
+ break;
+
+ case 256:
+ val |= (DMA_RWCTRL_READ_BNDRY_256_PCIX |
+ DMA_RWCTRL_WRITE_BNDRY_256_PCIX);
+ break;
+
+ default:
+ val |= (DMA_RWCTRL_READ_BNDRY_384_PCIX |
+ DMA_RWCTRL_WRITE_BNDRY_384_PCIX);
+ break;
+ };
+ } else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
+ switch (cacheline_size) {
+ case 16:
+ case 32:
+ case 64:
+ if (goal == BOUNDARY_SINGLE_CACHELINE) {
+ val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE;
+ val |= DMA_RWCTRL_WRITE_BNDRY_64_PCIE;
+ break;
+ }
+ /* fallthrough */
+ case 128:
+ default:
+ val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE;
+ val |= DMA_RWCTRL_WRITE_BNDRY_128_PCIE;
+ break;
+ };
+ } else {
+ switch (cacheline_size) {
+ case 16:
+ if (goal == BOUNDARY_SINGLE_CACHELINE) {
+ val |= (DMA_RWCTRL_READ_BNDRY_16 |
+ DMA_RWCTRL_WRITE_BNDRY_16);
+ break;
+ }
+ /* fallthrough */
+ case 32:
+ if (goal == BOUNDARY_SINGLE_CACHELINE) {
+ val |= (DMA_RWCTRL_READ_BNDRY_32 |
+ DMA_RWCTRL_WRITE_BNDRY_32);
+ break;
+ }
+ /* fallthrough */
+ case 64:
+ if (goal == BOUNDARY_SINGLE_CACHELINE) {
+ val |= (DMA_RWCTRL_READ_BNDRY_64 |
+ DMA_RWCTRL_WRITE_BNDRY_64);
+ break;
+ }
+ /* fallthrough */
+ case 128:
+ if (goal == BOUNDARY_SINGLE_CACHELINE) {
+ val |= (DMA_RWCTRL_READ_BNDRY_128 |
+ DMA_RWCTRL_WRITE_BNDRY_128);
+ break;
+ }
+ /* fallthrough */
+ case 256:
+ val |= (DMA_RWCTRL_READ_BNDRY_256 |
+ DMA_RWCTRL_WRITE_BNDRY_256);
+ break;
+ case 512:
+ val |= (DMA_RWCTRL_READ_BNDRY_512 |
+ DMA_RWCTRL_WRITE_BNDRY_512);
+ break;
+ case 1024:
+ default:
+ val |= (DMA_RWCTRL_READ_BNDRY_1024 |
+ DMA_RWCTRL_WRITE_BNDRY_1024);
+ break;
+ };
+ }
+
+out:
+ return val;
+}
+
static int __devinit tg3_do_test_dma(struct tg3 *tp, u32 *buf, dma_addr_t buf_dma, int size, int to_device)
{
struct tg3_internal_buffer_desc test_desc;
@@ -8861,7 +9001,7 @@ static int __devinit tg3_do_test_dma(struct tg3 *tp, u32 *buf, dma_addr_t buf_dm
static int __devinit tg3_test_dma(struct tg3 *tp)
{
dma_addr_t buf_dma;
- u32 *buf;
+ u32 *buf, saved_dma_rwctrl;
int ret;
buf = pci_alloc_consistent(tp->pdev, TEST_BUFFER_SIZE, &buf_dma);
@@ -8873,46 +9013,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
tp->dma_rwctrl = ((0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT));
-#ifndef CONFIG_X86
- {
- u8 byte;
- int cacheline_size;
- pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, &byte);
-
- if (byte == 0)
- cacheline_size = 1024;
- else
- cacheline_size = (int) byte * 4;
-
- switch (cacheline_size) {
- case 16:
- case 32:
- case 64:
- case 128:
- if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
- !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) {
- tp->dma_rwctrl |=
- DMA_RWCTRL_WRITE_BNDRY_384_PCIX;
- break;
- } else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
- tp->dma_rwctrl &=
- ~(DMA_RWCTRL_PCI_WRITE_CMD);
- tp->dma_rwctrl |=
- DMA_RWCTRL_WRITE_BNDRY_128_PCIE;
- break;
- }
- /* fallthrough */
- case 256:
- if (!(tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
- !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
- tp->dma_rwctrl |=
- DMA_RWCTRL_WRITE_BNDRY_256;
- else if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
- tp->dma_rwctrl |=
- DMA_RWCTRL_WRITE_BNDRY_256_PCIX;
- };
- }
-#endif
+ tp->dma_rwctrl = tg3_calc_dma_bndry(tp, tp->dma_rwctrl);
if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
/* DMA read watermark not used on PCIE */
@@ -8931,7 +9032,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
if (ccval == 0x6 || ccval == 0x7)
tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
- /* Set bit 23 to renable PCIX hw bug fix */
+ /* Set bit 23 to enable PCIX hw bug fix */
tp->dma_rwctrl |= 0x009f0000;
} else {
tp->dma_rwctrl |= 0x001b000f;
@@ -8972,6 +9073,13 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
goto out;
+ /* It is best to perform DMA test with maximum write burst size
+ * to expose the 5700/5701 write DMA bug.
+ */
+ saved_dma_rwctrl = tp->dma_rwctrl;
+ tp->dma_rwctrl &= ~DMA_RWCTRL_WRITE_BNDRY_MASK;
+ tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+
while (1) {
u32 *p = buf, i;
@@ -9010,8 +9118,9 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
if (p[i] == i)
continue;
- if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) ==
- DMA_RWCTRL_WRITE_BNDRY_DISAB) {
+ if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) !=
+ DMA_RWCTRL_WRITE_BNDRY_16) {
+ tp->dma_rwctrl &= ~DMA_RWCTRL_WRITE_BNDRY_MASK;
tp->dma_rwctrl |= DMA_RWCTRL_WRITE_BNDRY_16;
tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
break;
@@ -9028,6 +9137,14 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
break;
}
}
+ if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) !=
+ DMA_RWCTRL_WRITE_BNDRY_16) {
+ /* DMA test passed without adjusting DMA boundary,
+ * just restore the calculated DMA boundary
+ */
+ tp->dma_rwctrl = saved_dma_rwctrl;
+ tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+ }
out:
pci_free_consistent(tp->pdev, TEST_BUFFER_SIZE, buf, buf_dma);
@@ -9429,6 +9546,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
(tp->tg3_flags & TG3_FLAG_SPLIT_MODE) != 0,
(tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0,
(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0);
+ printk(KERN_INFO "%s: dma_rwctrl[%08x]\n",
+ dev->name, tp->dma_rwctrl);
return 0;