diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/pcnet.c | 279 |
1 files changed, 154 insertions, 125 deletions
diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c index 283cb48..5b248be 100644 --- a/drivers/net/pcnet.c +++ b/drivers/net/pcnet.c @@ -89,39 +89,39 @@ static pcnet_priv_t *lp; #define PCNET_RESET 0x14 #define PCNET_BDP 0x16 -static u16 pcnet_read_csr (struct eth_device *dev, int index) +static u16 pcnet_read_csr(struct eth_device *dev, int index) { - outw (index, dev->iobase + PCNET_RAP); - return inw (dev->iobase + PCNET_RDP); + outw(index, dev->iobase + PCNET_RAP); + return inw(dev->iobase + PCNET_RDP); } -static void pcnet_write_csr (struct eth_device *dev, int index, u16 val) +static void pcnet_write_csr(struct eth_device *dev, int index, u16 val) { - outw (index, dev->iobase + PCNET_RAP); - outw (val, dev->iobase + PCNET_RDP); + outw(index, dev->iobase + PCNET_RAP); + outw(val, dev->iobase + PCNET_RDP); } -static u16 pcnet_read_bcr (struct eth_device *dev, int index) +static u16 pcnet_read_bcr(struct eth_device *dev, int index) { - outw (index, dev->iobase + PCNET_RAP); - return inw (dev->iobase + PCNET_BDP); + outw(index, dev->iobase + PCNET_RAP); + return inw(dev->iobase + PCNET_BDP); } -static void pcnet_write_bcr (struct eth_device *dev, int index, u16 val) +static void pcnet_write_bcr(struct eth_device *dev, int index, u16 val) { - outw (index, dev->iobase + PCNET_RAP); - outw (val, dev->iobase + PCNET_BDP); + outw(index, dev->iobase + PCNET_RAP); + outw(val, dev->iobase + PCNET_BDP); } -static void pcnet_reset (struct eth_device *dev) +static void pcnet_reset(struct eth_device *dev) { - inw (dev->iobase + PCNET_RESET); + inw(dev->iobase + PCNET_RESET); } -static int pcnet_check (struct eth_device *dev) +static int pcnet_check(struct eth_device *dev) { - outw (88, dev->iobase + PCNET_RAP); - return (inw (dev->iobase + PCNET_RAP) == 88); + outw(88, dev->iobase + PCNET_RAP); + return inw(dev->iobase + PCNET_RAP) == 88; } static int pcnet_init (struct eth_device *dev, bd_t * bis); @@ -139,63 +139,64 @@ static struct pci_device_id supported[] = { }; -int pcnet_initialize (bd_t * bis) +int pcnet_initialize(bd_t *bis) { pci_dev_t devbusfn; struct eth_device *dev; u16 command, status; int dev_nr = 0; - PCNET_DEBUG1 ("\npcnet_initialize...\n"); + PCNET_DEBUG1("\npcnet_initialize...\n"); for (dev_nr = 0;; dev_nr++) { /* * Find the PCnet PCI device(s). */ - if ((devbusfn = pci_find_devices (supported, dev_nr)) < 0) { + devbusfn = pci_find_devices(supported, dev_nr); + if (devbusfn < 0) break; - } /* * Allocate and pre-fill the device structure. */ - dev = (struct eth_device *) malloc (sizeof *dev); + dev = (struct eth_device *)malloc(sizeof(*dev)); if (!dev) { printf("pcnet: Can not allocate memory\n"); break; } memset(dev, 0, sizeof(*dev)); - dev->priv = (void *) devbusfn; - sprintf (dev->name, "pcnet#%d", dev_nr); + dev->priv = (void *)devbusfn; + sprintf(dev->name, "pcnet#%d", dev_nr); /* * Setup the PCI device. */ - pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0, - (unsigned int *) &dev->iobase); - dev->iobase=pci_io_to_phys (devbusfn, dev->iobase); + pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, + (unsigned int *)&dev->iobase); + dev->iobase = pci_io_to_phys(devbusfn, dev->iobase); dev->iobase &= ~0xf; - PCNET_DEBUG1 ("%s: devbusfn=0x%x iobase=0x%x: ", - dev->name, devbusfn, dev->iobase); + PCNET_DEBUG1("%s: devbusfn=0x%x iobase=0x%x: ", + dev->name, devbusfn, dev->iobase); command = PCI_COMMAND_IO | PCI_COMMAND_MASTER; - pci_write_config_word (devbusfn, PCI_COMMAND, command); - pci_read_config_word (devbusfn, PCI_COMMAND, &status); + pci_write_config_word(devbusfn, PCI_COMMAND, command); + pci_read_config_word(devbusfn, PCI_COMMAND, &status); if ((status & command) != command) { - printf ("%s: Couldn't enable IO access or Bus Mastering\n", dev->name); - free (dev); + printf("%s: Couldn't enable IO access or Bus Mastering\n", + dev->name); + free(dev); continue; } - pci_write_config_byte (devbusfn, PCI_LATENCY_TIMER, 0x40); + pci_write_config_byte(devbusfn, PCI_LATENCY_TIMER, 0x40); /* * Probe the PCnet chip. */ - if (pcnet_probe (dev, bis, dev_nr) < 0) { - free (dev); + if (pcnet_probe(dev, bis, dev_nr) < 0) { + free(dev); continue; } @@ -207,15 +208,15 @@ int pcnet_initialize (bd_t * bis) dev->send = pcnet_send; dev->recv = pcnet_recv; - eth_register (dev); + eth_register(dev); } - udelay (10 * 1000); + udelay(10 * 1000); return dev_nr; } -static int pcnet_probe (struct eth_device *dev, bd_t * bis, int dev_nr) +static int pcnet_probe(struct eth_device *dev, bd_t *bis, int dev_nr) { int chip_version; char *chipname; @@ -225,17 +226,17 @@ static int pcnet_probe (struct eth_device *dev, bd_t * bis, int dev_nr) #endif /* Reset the PCnet controller */ - pcnet_reset (dev); + pcnet_reset(dev); /* Check if register access is working */ - if (pcnet_read_csr (dev, 0) != 4 || !pcnet_check (dev)) { - printf ("%s: CSR register access check failed\n", dev->name); + if (pcnet_read_csr(dev, 0) != 4 || !pcnet_check(dev)) { + printf("%s: CSR register access check failed\n", dev->name); return -1; } /* Identify the chip */ chip_version = - pcnet_read_csr (dev, 88) | (pcnet_read_csr (dev, 89) << 16); + pcnet_read_csr(dev, 88) | (pcnet_read_csr(dev, 89) << 16); if ((chip_version & 0xfff) != 0x003) return -1; chip_version = (chip_version >> 12) & 0xffff; @@ -254,12 +255,12 @@ static int pcnet_probe (struct eth_device *dev, bd_t * bis, int dev_nr) break; #endif default: - printf ("%s: PCnet version %#x not supported\n", - dev->name, chip_version); + printf("%s: PCnet version %#x not supported\n", + dev->name, chip_version); return -1; } - PCNET_DEBUG1 ("AMD %s\n", chipname); + PCNET_DEBUG1("AMD %s\n", chipname); #ifdef PCNET_HAS_PROM /* @@ -270,7 +271,7 @@ static int pcnet_probe (struct eth_device *dev, bd_t * bis, int dev_nr) for (i = 0; i < 3; i++) { unsigned int val; - val = pcnet_read_csr (dev, i + 12) & 0x0ffff; + val = pcnet_read_csr(dev, i + 12) & 0x0ffff; /* There may be endianness issues here. */ dev->enetaddr[2 * i] = val & 0x0ff; dev->enetaddr[2 * i + 1] = (val >> 8) & 0x0ff; @@ -280,35 +281,50 @@ static int pcnet_probe (struct eth_device *dev, bd_t * bis, int dev_nr) return 0; } -static int pcnet_init (struct eth_device *dev, bd_t * bis) +static int pcnet_init(struct eth_device *dev, bd_t *bis) { int i, val; u32 addr; - PCNET_DEBUG1 ("%s: pcnet_init...\n", dev->name); + PCNET_DEBUG1("%s: pcnet_init...\n", dev->name); /* Switch pcnet to 32bit mode */ - pcnet_write_bcr (dev, 20, 2); + pcnet_write_bcr(dev, 20, 2); #ifdef CONFIG_PN62 /* Setup LED registers */ - val = pcnet_read_bcr (dev, 2) | 0x1000; - pcnet_write_bcr (dev, 2, val); /* enable LEDPE */ - pcnet_write_bcr (dev, 4, 0x5080); /* 100MBit */ - pcnet_write_bcr (dev, 5, 0x40c0); /* LNKSE */ - pcnet_write_bcr (dev, 6, 0x4090); /* TX Activity */ - pcnet_write_bcr (dev, 7, 0x4084); /* RX Activity */ + val = pcnet_read_bcr(dev, 2) | 0x1000; + pcnet_write_bcr(dev, 2, val); /* enable LEDPE */ + pcnet_write_bcr(dev, 4, 0x5080); /* 100MBit */ + pcnet_write_bcr(dev, 5, 0x40c0); /* LNKSE */ + pcnet_write_bcr(dev, 6, 0x4090); /* TX Activity */ + pcnet_write_bcr(dev, 7, 0x4084); /* RX Activity */ #endif /* Set/reset autoselect bit */ - val = pcnet_read_bcr (dev, 2) & ~2; + val = pcnet_read_bcr(dev, 2) & ~2; val |= 2; - pcnet_write_bcr (dev, 2, val); + pcnet_write_bcr(dev, 2, val); /* Enable auto negotiate, setup, disable fd */ - val = pcnet_read_bcr (dev, 32) & ~0x98; + val = pcnet_read_bcr(dev, 32) & ~0x98; val |= 0x20; - pcnet_write_bcr (dev, 32, val); + pcnet_write_bcr(dev, 32, val); + + /* + * Enable NOUFLO on supported controllers, with the transmit + * start point set to the full packet. This will cause entire + * packets to be buffered by the ethernet controller before + * transmission, eliminating underflows which are common on + * slower devices. Controllers which do not support NOUFLO will + * simply be left with a larger transmit FIFO threshold. + */ + val = pcnet_read_bcr(dev, 18); + val |= 1 << 11; + pcnet_write_bcr(dev, 18, val); + val = pcnet_read_csr(dev, 80); + val |= 0x3 << 10; + pcnet_write_csr(dev, 80, val); /* * We only maintain one structure because the drivers will never @@ -316,12 +332,12 @@ static int pcnet_init (struct eth_device *dev, bd_t * bis) * must be aligned on 16-byte boundaries. */ if (lp == NULL) { - addr = (u32) malloc (sizeof (pcnet_priv_t) + 0x10); + addr = (u32)malloc(sizeof(pcnet_priv_t) + 0x10); addr = (addr + 0xf) & ~0xf; - lp = (pcnet_priv_t *) addr; + lp = (pcnet_priv_t *)addr; } - lp->init_block.mode = cpu_to_le16 (0x0000); + lp->init_block.mode = cpu_to_le16(0x0000); lp->init_block.filter[0] = 0x00000000; lp->init_block.filter[1] = 0x00000000; @@ -330,9 +346,9 @@ static int pcnet_init (struct eth_device *dev, bd_t * bis) */ lp->cur_rx = 0; for (i = 0; i < RX_RING_SIZE; i++) { - lp->rx_ring[i].base = PCI_TO_MEM_LE (dev, lp->rx_buf[i]); - lp->rx_ring[i].buf_length = cpu_to_le16 (-PKT_BUF_SZ); - lp->rx_ring[i].status = cpu_to_le16 (0x8000); + lp->rx_ring[i].base = PCI_TO_MEM_LE(dev, lp->rx_buf[i]); + lp->rx_ring[i].buf_length = cpu_to_le16(-PKT_BUF_SZ); + lp->rx_ring[i].status = cpu_to_le16(0x8000); PCNET_DEBUG1 ("Rx%d: base=0x%x buf_length=0x%hx status=0x%hx\n", i, lp->rx_ring[i].base, lp->rx_ring[i].buf_length, @@ -352,48 +368,49 @@ static int pcnet_init (struct eth_device *dev, bd_t * bis) /* * Setup Init Block. */ - PCNET_DEBUG1 ("Init block at 0x%p: MAC", &lp->init_block); + PCNET_DEBUG1("Init block at 0x%p: MAC", &lp->init_block); for (i = 0; i < 6; i++) { lp->init_block.phys_addr[i] = dev->enetaddr[i]; - PCNET_DEBUG1 (" %02x", lp->init_block.phys_addr[i]); + PCNET_DEBUG1(" %02x", lp->init_block.phys_addr[i]); } - lp->init_block.tlen_rlen = cpu_to_le16 (TX_RING_LEN_BITS | - RX_RING_LEN_BITS); - lp->init_block.rx_ring = PCI_TO_MEM_LE (dev, lp->rx_ring); - lp->init_block.tx_ring = PCI_TO_MEM_LE (dev, lp->tx_ring); + lp->init_block.tlen_rlen = cpu_to_le16(TX_RING_LEN_BITS | + RX_RING_LEN_BITS); + lp->init_block.rx_ring = PCI_TO_MEM_LE(dev, lp->rx_ring); + lp->init_block.tx_ring = PCI_TO_MEM_LE(dev, lp->tx_ring); + flush_dcache_range((unsigned long)lp, (unsigned long)&lp->rx_buf); - PCNET_DEBUG1 ("\ntlen_rlen=0x%x rx_ring=0x%x tx_ring=0x%x\n", - lp->init_block.tlen_rlen, - lp->init_block.rx_ring, lp->init_block.tx_ring); + PCNET_DEBUG1("\ntlen_rlen=0x%x rx_ring=0x%x tx_ring=0x%x\n", + lp->init_block.tlen_rlen, + lp->init_block.rx_ring, lp->init_block.tx_ring); /* * Tell the controller where the Init Block is located. */ - addr = PCI_TO_MEM (dev, &lp->init_block); - pcnet_write_csr (dev, 1, addr & 0xffff); - pcnet_write_csr (dev, 2, (addr >> 16) & 0xffff); + addr = PCI_TO_MEM(dev, &lp->init_block); + pcnet_write_csr(dev, 1, addr & 0xffff); + pcnet_write_csr(dev, 2, (addr >> 16) & 0xffff); - pcnet_write_csr (dev, 4, 0x0915); - pcnet_write_csr (dev, 0, 0x0001); /* start */ + pcnet_write_csr(dev, 4, 0x0915); + pcnet_write_csr(dev, 0, 0x0001); /* start */ /* Wait for Init Done bit */ for (i = 10000; i > 0; i--) { - if (pcnet_read_csr (dev, 0) & 0x0100) + if (pcnet_read_csr(dev, 0) & 0x0100) break; - udelay (10); + udelay(10); } if (i <= 0) { - printf ("%s: TIMEOUT: controller init failed\n", dev->name); - pcnet_reset (dev); + printf("%s: TIMEOUT: controller init failed\n", dev->name); + pcnet_reset(dev); return -1; } /* * Finally start network controller operation. */ - pcnet_write_csr (dev, 0, 0x0002); + pcnet_write_csr(dev, 0, 0x0002); return 0; } @@ -403,20 +420,25 @@ static int pcnet_send(struct eth_device *dev, void *packet, int pkt_len) int i, status; struct pcnet_tx_head *entry = &lp->tx_ring[lp->cur_tx]; - PCNET_DEBUG2 ("Tx%d: %d bytes from 0x%p ", lp->cur_tx, pkt_len, - packet); + PCNET_DEBUG2("Tx%d: %d bytes from 0x%p ", lp->cur_tx, pkt_len, + packet); + + flush_dcache_range((unsigned long)packet, + (unsigned long)packet + pkt_len); /* Wait for completion by testing the OWN bit */ for (i = 1000; i > 0; i--) { - status = le16_to_cpu (entry->status); + invalidate_dcache_range((unsigned long)entry, + (unsigned long)entry + sizeof(*entry)); + status = le16_to_cpu(entry->status); if ((status & 0x8000) == 0) break; - udelay (100); - PCNET_DEBUG2 ("."); + udelay(100); + PCNET_DEBUG2("."); } if (i <= 0) { - printf ("%s: TIMEOUT: Tx%d failed (status = 0x%x)\n", - dev->name, lp->cur_tx, status); + printf("%s: TIMEOUT: Tx%d failed (status = 0x%x)\n", + dev->name, lp->cur_tx, status); pkt_len = 0; goto failure; } @@ -426,19 +448,21 @@ static int pcnet_send(struct eth_device *dev, void *packet, int pkt_len) * set the status with the "ownership" bits last. */ status = 0x8300; - entry->length = le16_to_cpu (-pkt_len); + entry->length = cpu_to_le16(-pkt_len); entry->misc = 0x00000000; - entry->base = PCI_TO_MEM_LE (dev, packet); - entry->status = le16_to_cpu (status); + entry->base = PCI_TO_MEM_LE(dev, packet); + entry->status = cpu_to_le16(status); + flush_dcache_range((unsigned long)entry, + (unsigned long)entry + sizeof(*entry)); /* Trigger an immediate send poll. */ - pcnet_write_csr (dev, 0, 0x0008); + pcnet_write_csr(dev, 0, 0x0008); failure: if (++lp->cur_tx >= TX_RING_SIZE) lp->cur_tx = 0; - PCNET_DEBUG2 ("done\n"); + PCNET_DEBUG2("done\n"); return pkt_len; } @@ -450,43 +474,49 @@ static int pcnet_recv (struct eth_device *dev) while (1) { entry = &lp->rx_ring[lp->cur_rx]; + invalidate_dcache_range((unsigned long)entry, + (unsigned long)entry + sizeof(*entry)); /* * If we own the next entry, it's a new packet. Send it up. */ - if (((status = le16_to_cpu (entry->status)) & 0x8000) != 0) { + status = le16_to_cpu(entry->status); + if ((status & 0x8000) != 0) break; - } status >>= 8; if (status != 0x03) { /* There was an error. */ - - printf ("%s: Rx%d", dev->name, lp->cur_rx); - PCNET_DEBUG1 (" (status=0x%x)", status); + printf("%s: Rx%d", dev->name, lp->cur_rx); + PCNET_DEBUG1(" (status=0x%x)", status); if (status & 0x20) - printf (" Frame"); + printf(" Frame"); if (status & 0x10) - printf (" Overflow"); + printf(" Overflow"); if (status & 0x08) - printf (" CRC"); + printf(" CRC"); if (status & 0x04) - printf (" Fifo"); - printf (" Error\n"); - entry->status &= le16_to_cpu (0x03ff); + printf(" Fifo"); + printf(" Error\n"); + entry->status &= le16_to_cpu(0x03ff); } else { - - pkt_len = - (le32_to_cpu (entry->msg_length) & 0xfff) - 4; + pkt_len = (le32_to_cpu(entry->msg_length) & 0xfff) - 4; if (pkt_len < 60) { - printf ("%s: Rx%d: invalid packet length %d\n", dev->name, lp->cur_rx, pkt_len); + printf("%s: Rx%d: invalid packet length %d\n", + dev->name, lp->cur_rx, pkt_len); } else { - NetReceive (lp->rx_buf[lp->cur_rx], pkt_len); - PCNET_DEBUG2 ("Rx%d: %d bytes from 0x%p\n", - lp->cur_rx, pkt_len, - lp->rx_buf[lp->cur_rx]); + invalidate_dcache_range( + (unsigned long)lp->rx_buf[lp->cur_rx], + (unsigned long)lp->rx_buf[lp->cur_rx] + + pkt_len); + NetReceive(lp->rx_buf[lp->cur_rx], pkt_len); + PCNET_DEBUG2("Rx%d: %d bytes from 0x%p\n", + lp->cur_rx, pkt_len, + lp->rx_buf[lp->cur_rx]); } } - entry->status |= cpu_to_le16 (0x8000); + entry->status |= cpu_to_le16(0x8000); + flush_dcache_range((unsigned long)entry, + (unsigned long)entry + sizeof(*entry)); if (++lp->cur_rx >= RX_RING_SIZE) lp->cur_rx = 0; @@ -494,22 +524,21 @@ static int pcnet_recv (struct eth_device *dev) return pkt_len; } -static void pcnet_halt (struct eth_device *dev) +static void pcnet_halt(struct eth_device *dev) { int i; - PCNET_DEBUG1 ("%s: pcnet_halt...\n", dev->name); + PCNET_DEBUG1("%s: pcnet_halt...\n", dev->name); /* Reset the PCnet controller */ - pcnet_reset (dev); + pcnet_reset(dev); /* Wait for Stop bit */ for (i = 1000; i > 0; i--) { - if (pcnet_read_csr (dev, 0) & 0x4) + if (pcnet_read_csr(dev, 0) & 0x4) break; - udelay (10); - } - if (i <= 0) { - printf ("%s: TIMEOUT: controller reset failed\n", dev->name); + udelay(10); } + if (i <= 0) + printf("%s: TIMEOUT: controller reset failed\n", dev->name); } |