/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2001 Patton Electronics Company * Copyright (C) 2002 Momentum Computer * * Copyright 2000 MontaVista Software Inc. * Author: MontaVista Software, Inc. * stevel@mvista.com or support@mvista.com * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * * Ethernet driver for the MIPS GT96100 Advanced Communication Controller. * * Modified for the Gallileo/Marvell GT-64240 Communication Controller. * * Support for Rx NAPI, Rx checksum offload, IOCTL and ETHTOOL added * Manish Lachwani (lachwani@pmc-sierra.com) - 09/16/2003 * * Modified for later version of Linux 2.4 kernel * Manish Lachwani (lachwani@pmc-sierra.com) - 04/29/2004 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DESC_DATA_BE 1 #include "gt64240eth.h" // enable this port (set hash size to 1/2K) //- #define PORT_CONFIG pcrHS #define PORT_CONFIG (pcrHS | pcrHD) //- #define PORT_CONFIG pcrHS |pcrPM |pcrPBF|pcrHDM //- GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, pcrEN | pcrHS); //- GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, pcrEN | pcrHS | pcrPM); //- GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, pcrEN | pcrHS | pcrPM | 1< 2 some warnings such as queue full, ..... * > 3 lots of change-of-state messages. * > 4 EXTENSIVE data/descriptor dumps. */ #ifdef GT64240_DEBUG static int gt64240_debug = GT64240_DEBUG; #else static int gt64240_debug = 0; #endif static int debug = -1; #define GT64240_MSG_ENABLE (NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ NETIF_MSG_LINK) /********************************************************/ // prototypes static void *dmaalloc(size_t size, dma_addr_t * dma_handle); static void dmafree(size_t size, void *vaddr); static void gt64240_delay(int msec); static int gt64240_add_hash_entry(struct net_device *dev, unsigned char *addr); static void read_mib_counters(struct gt64240_private *gp); static int read_MII(struct net_device *dev, u32 reg); static int write_MII(struct net_device *dev, u32 reg, u16 data); #if 1 static void dump_tx_ring(struct net_device *dev); static void dump_rx_ring(struct net_device *dev); #endif static void dump_MII(struct net_device *dev); static void dump_tx_desc(struct net_device *dev, int i); static void dump_rx_desc(struct net_device *dev, int i); static void dump_skb(struct net_device *dev, struct sk_buff *skb); static void dump_hw_addr(unsigned char *addr_str); static void update_stats(struct gt64240_private *gp); static void abort(struct net_device *dev, u32 abort_bits); static void hard_stop(struct net_device *dev); static void enable_ether_irq(struct net_device *dev); static void disable_ether_irq(struct net_device *dev); static int __init gt64240_probe1(uint32_t ioaddr, int irq, int port_num); static void reset_tx(struct net_device *dev); static void reset_rx(struct net_device *dev); static int gt64240_init(struct net_device *dev); static int gt64240_open(struct net_device *dev); static int gt64240_close(struct net_device *dev); static int gt64240_tx(struct sk_buff *skb, struct net_device *dev); #ifdef GT64240_NAPI static int gt64240_poll(struct net_device *dev, int *budget); static int gt64240_rx(struct net_device *dev, u32 status, int budget); #else static int gt64240_rx(struct net_device *dev, u32 status); #endif static void gt64240_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void gt64240_tx_timeout(struct net_device *dev); static void gt64240_set_rx_mode(struct net_device *dev); static struct net_device_stats *gt64240_get_stats(struct net_device *dev); extern char *__init prom_getcmdline(void); extern int prom_get_mac_addrs(unsigned char station_addr[NUM_INTERFACES][6]); static char version[] __devinitdata = "gt64240eth.o: version 0.1, \n"; // PHY device addresses static u32 gt64240_phy_addr[NUM_INTERFACES] __devinitdata = { 0x8, 0x1, 0xa }; // Need real Ethernet addresses -- in parse_mac_addr_options(), // these will be replaced by prom_get_mac_addrs() and/or prom_getcmdline(). static unsigned char gt64240_station_addr[NUM_INTERFACES][6] = { {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {0x02, 0x03, 0x04, 0x05, 0x06, 0x07} }; static int max_interrupt_work = 32; /* * Base address and interupt of the GT64240 ethernet controllers */ static struct { unsigned int port; int irq; } gt64240_iflist[NUM_INTERFACES] = { { GT64240_ETH0_BASE, 8}, { GT64240_ETH1_BASE, 8}, { GT64240_ETH2_BASE, 8} }; /* DMA memory allocation, derived from pci_alloc_consistent. */ static void *dmaalloc(size_t size, dma_addr_t * dma_handle) { void *ret; ret = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, get_order(size)); if (ret != NULL) { dma_cache_inv((unsigned long) ret, size); if (dma_handle != NULL) *dma_handle = virt_to_phys(ret); /* bump virtual address up to non-cached area */ ret = (void *) KSEG1ADDR(ret); } return ret; } static void dmafree(size_t size, void *vaddr) { vaddr = (void *) KSEG0ADDR(vaddr); free_pages((unsigned long) vaddr, get_order(size)); } static void gt64240_delay(int ms) { if (in_interrupt()) return; else { current->state = TASK_INTERRUPTIBLE; schedule_timeout(ms * HZ / 1000); } } unsigned char prom_mac_addr_base[6]; int prom_get_mac_addrs(unsigned char station_addr[NUM_INTERFACES][6]) { memcpy(station_addr[0], prom_mac_addr_base, 6); memcpy(station_addr[1], prom_mac_addr_base, 6); memcpy(station_addr[2], prom_mac_addr_base, 6); station_addr[1][5] += 1; station_addr[2][5] += 2; return 0; } void parse_mac_addr_options(void) { prom_get_mac_addrs(gt64240_station_addr); } static int read_MII(struct net_device *dev, u32 reg) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; int timedout = 20; u32 smir = smirOpCode | (gp->phy_addr << smirPhyAdBit) | (reg << smirRegAdBit); // wait for last operation to complete while ((GT64240_READ(GT64240_ETH_SMI_REG)) & smirBusy) { // snooze for 1 msec and check again gt64240_delay(1); if (--timedout == 0) { printk("%s: read_MII busy timeout!!\n", dev->name); return -1; } } GT64240_WRITE(GT64240_ETH_SMI_REG, smir); timedout = 20; // wait for read to complete while (! ((smir = GT64240_READ(GT64240_ETH_SMI_REG)) & smirReadValid)) { // snooze for 1 msec and check again gt64240_delay(1); if (--timedout == 0) { printk("%s: read_MII timeout!!\n", dev->name); return -1; } } return (int) (smir & smirDataMask); } static void gp_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) { strcpy(info->driver, "gt64260"); strcpy(info->version, version); } static int gp_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; int rc; spin_lock_irq(&gp->lock); rc = mii_ethtool_gset(&gp->mii_if, cmd); spin_unlock_irq(&gp->lock); return rc; } static int gp_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; int rc; spin_lock_irq(&gp->lock); rc = mii_ethtool_sset(&gp->mii_if, cmd); spin_unlock_irq(&gp->lock); return rc; } static int gp_nway_reset(struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; return mii_nway_restart(&gp->mii_if); } static u32 gp_get_link(struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; return mii_link_ok(&gp->mii_if); } static u32 gp_get_msglevel(struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; return gp->msg_enable; } static void gp_set_msglevel(struct net_device *dev, u32 value) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; gp->msg_enable = value; } static struct ethtool_ops gp_ethtool_ops = { .get_drvinfo = gp_get_drvinfo, .get_settings = gp_get_settings, .set_settings = gp_set_settings, .nway_reset = gp_nway_reset, .get_link = gp_get_link, .get_msglevel = gp_get_msglevel, .set_msglevel = gp_set_msglevel, }; static int gt64240_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; struct mii_ioctl_data *data = (struct mii_ioctl_data *) &rq->ifr_data; int retval; if (!netif_running(dev)) return -EINVAL; spin_lock_irq(&gp->lock); retval = generic_mii_ioctl(&gp->mii_if, data, cmd, NULL); spin_unlock_irq(&gp->lock); return retval; } static void dump_tx_desc(struct net_device *dev, int i) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; gt64240_td_t *td = &gp->tx_ring[i]; printk ("%s:tx[%d]: self=%08x cmd=%08x, cnt=%4d. bufp=%08x, next=%08x\n", dev->name, i, td, td->cmdstat, td->byte_cnt, td->buff_ptr, td->next); } static void dump_rx_desc(struct net_device *dev, int i) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; gt64240_rd_t *rd = &gp->rx_ring[i]; printk ("%s:rx_dsc[%d]: self=%08x cst=%08x,size=%4d. cnt=%4d. bufp=%08x, next=%08x\n", dev->name, i, rd, rd->cmdstat, rd->buff_sz, rd->byte_cnt, rd->buff_ptr, rd->next); } // These routines work, just disabled to avoid compile warnings static int write_MII(struct net_device *dev, u32 reg, u16 data) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; int timedout = 20; u32 smir = (gp->phy_addr << smirPhyAdBit) | (reg << smirRegAdBit) | data; // wait for last operation to complete while (GT64240_READ(GT64240_ETH_SMI_REG) & smirBusy) { // snooze for 1 msec and check again gt64240_delay(1); if (--timedout == 0) { printk("%s: write_MII busy timeout!!\n", dev->name); return -1; } } GT64240_WRITE(GT64240_ETH_SMI_REG, smir); return 0; } static void dump_tx_ring(struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; int i; printk("%s: dump_tx_ring: txno/txni/cnt=%d/%d/%d\n", dev->name, gp->tx_next_out, gp->tx_next_in, gp->tx_count); for (i = 0; i < TX_RING_SIZE; i++) dump_tx_desc(dev, i); } static void dump_rx_ring(struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; int i; printk("%s: dump_rx_ring: rxno=%d\n", dev->name, gp->rx_next_out); for (i = 0; i < RX_RING_SIZE; i++) dump_rx_desc(dev, i); } static void dump_MII(struct net_device *dev) { int i, val; for (i = 0; i < 7; i++) { if ((val = read_MII(dev, i)) >= 0) printk("%s: MII Reg %d=%x\n", dev->name, i, val); } for (i = 16; i < 21; i++) { if ((val = read_MII(dev, i)) >= 0) printk("%s: MII Reg %d=%x\n", dev->name, i, val); } } static void dump_hw_addr(unsigned char *addr_str) { int i; for (i = 0; i < 6; i++) { printk("%2.2x", addr_str[i]); printk(i < 5 ? ":" : "\n"); } } static void dump_skb(struct net_device *dev, struct sk_buff *skb) { int i; unsigned char *skbdata; printk("%s: dump_skb: skb=%p, skb->data=%p, skb->len=%d.", dev->name, skb, skb->data, skb->len); skbdata = (unsigned char *) KSEG1ADDR(skb->data); for (i = 0; i < skb->len; i++) { if (!(i % 16)) printk("\r\n %3.3x: %2.2x,", i, skbdata[i]); else printk("%2.2x,", skbdata[i]); } printk("\r\n"); } static void dump_data(struct net_device *dev, char *ptr, int len) { int i; unsigned char *data; printk("%s: dump_data: ptr=%p, len=%d.", dev->name, ptr, len); data = (unsigned char *) KSEG1ADDR(ptr); for (i = 0; i < len; i++) { if (!(i % 16)) printk("\n %3.3x: %2.2x,", i, data[i]); else printk("%2.2x,", data[i]); } printk("\n"); } /*--------------------------------------------------------------*/ /* A D D H A S H E N T R Y */ /*--------------------------------------------------------------*/ static int gt64240_add_hash_entry(struct net_device *dev, unsigned char *addr) { struct gt64240_private *gp; int i; u32 value1, value0, *entry; u16 hashResult; unsigned char hash_ea[6]; static int flag = 0; static unsigned char swapped[256]; if (flag == 0) { /* Create table to swap bits in a byte */ flag = 1; for (i = 0; i < 256; i++) { swapped[i] = (i & 0x01) << 7; swapped[i] |= (i & 0x02) << 5; swapped[i] |= (i & 0x04) << 3; swapped[i] |= (i & 0x08) << 1; swapped[i] |= (i & 0x10) >> 1; swapped[i] |= (i & 0x20) >> 3; swapped[i] |= (i & 0x40) >> 5; swapped[i] |= (i & 0x80) >> 7; } } for (i = 0; i < 6; i++) { /* swap bits from mac to create hash mac */ hash_ea[i] = swapped[addr[i]]; } gp = (struct gt64240_private *) dev->priv; /* create hash entry address */ hashResult = (((hash_ea[5] >> 2) & 0x3F) << 9) & 0x7E00; hashResult |= ((hash_ea[4] & 0x7F) << 2) | (hash_ea[5] & 0x03); hashResult ^= ((hash_ea[3] & 0xFF) << 1) | ((hash_ea[4] >> 7) & 0x01); hashResult ^= ((hash_ea[1] & 0x01) << 8) | (hash_ea[2] & 0xFF); value0 = hteValid | hteRD; /* Create hash table entry value */ value0 |= (u32) addr[0] << 3; value0 |= (u32) addr[1] << 11; value0 |= (u32) addr[2] << 19; value0 |= ((u32) addr[3] & 0x1f) << 27; value1 = ((u32) addr[3] >> 5) & 0x07; value1 |= (u32) addr[4] << 3; value1 |= (u32) addr[5] << 11; /* Inset entry value into hash table */ for (i = 0; i < HASH_HOP_NUMBER; i++) { entry = (u32 *) ((u32) gp->hash_table + (((u32) hashResult & 0x07ff) << 3)); if ((*entry & hteValid) && !(*entry & hteSkip)) { hashResult += 2; /* oops, occupied, go to next entry */ } else { #ifdef __LITTLE_ENDIAN entry[1] = value1; entry[0] = value0; #else entry[0] = value1; entry[1] = value0; #endif break; } } if (i >= HASH_HOP_NUMBER) { printk("%s: gt64240_add_hash_entry expired!\n", dev->name); return (-1); } return (0); } static void read_mib_counters(struct gt64240_private *gp) { u32 *mib_regs = (u32 *) & gp->mib; int i; for (i = 0; i < sizeof(mib_counters_t) / sizeof(u32); i++) mib_regs[i] = GT64240ETH_READ(gp, GT64240_ETH_MIB_COUNT_BASE + i * sizeof(u32)); } static void update_stats(struct gt64240_private *gp) { mib_counters_t *mib = &gp->mib; struct net_device_stats *stats = &gp->stats; read_mib_counters(gp); stats->rx_packets = mib->totalFramesReceived; stats->tx_packets = mib->framesSent; stats->rx_bytes = mib->totalByteReceived; stats->tx_bytes = mib->byteSent; stats->rx_errors = mib->totalFramesReceived - mib->framesReceived; //the tx error counters are incremented by the ISR //rx_dropped incremented by gt64240_rx //tx_dropped incremented by gt64240_tx stats->multicast = mib->multicastFramesReceived; // collisions incremented by gt64240_tx_complete stats->rx_length_errors = mib->oversizeFrames + mib->fragments; // The RxError condition means the Rx DMA encountered a // CPU owned descriptor, which, if things are working as // they should, means the Rx ring has overflowed. stats->rx_over_errors = mib->macRxError; stats->rx_crc_errors = mib->cRCError; } static void abort(struct net_device *dev, u32 abort_bits) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; int timedout = 100; // wait up to 100 msec for hard stop to complete if (gt64240_debug > 3) printk("%s: abort\n", dev->name); // Return if neither Rx or Tx abort bits are set if (!(abort_bits & (sdcmrAR | sdcmrAT))) return; // make sure only the Rx/Tx abort bits are set abort_bits &= (sdcmrAR | sdcmrAT); spin_lock(&gp->lock); // abort any Rx/Tx DMA immediately GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, abort_bits); if (gt64240_debug > 3) printk("%s: abort: SDMA cmd = %x/%x\n", dev->name, abort_bits, GT64240ETH_READ(gp, GT64240_ETH_SDMA_COMM)); // wait for abort to complete while ((GT64240ETH_READ(gp, GT64240_ETH_SDMA_COMM)) & abort_bits) { // snooze for 20 msec and check again gt64240_delay(1); if (--timedout == 0) { printk("%s: abort timeout!!\n", dev->name); break; } } spin_unlock(&gp->lock); } static void hard_stop(struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; if (gt64240_debug > 3) printk("%s: hard stop\n", dev->name); disable_ether_irq(dev); abort(dev, sdcmrAR | sdcmrAT); // disable port GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, 0); if (gt64240_debug > 3) printk("%s: gt64240_hard_stop: Port Config=%x\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_PORT_CONFIG)); } static void enable_ether_irq(struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; u32 intMask; intMask = icrTxBufferLow | icrTxEndLow | icrTxErrorLow | icrTxBufferHigh | icrTxEndHigh | icrTxErrorHigh | icrTxUdr | icrRxBuffer | icrRxOVR | icrRxError | icrMIIPhySTC | icrEtherIntSum; //- GT64240ETH_WRITE(gp, GT64240_ETH_INT_CAUSE, 0); /* CLEAR existing ints */ // unmask device interrupts: GT64240ETH_WRITE(gp, GT64240_ETH_INT_MASK, intMask); // now route ethernet interrupts to GT PCI1 (eth0 and eth1 will be // sharing it). GT_READ(PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH, &intMask); intMask |= 1 << gp->port_num; GT_WRITE(PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH, intMask); } static void disable_ether_irq(struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; u32 intMask; GT_READ(PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH, &intMask); intMask &= ~(1 << gp->port_num); GT_WRITE(PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH, intMask); // mask all device interrupts: GT64240ETH_WRITE(gp, GT64240_ETH_INT_MASK, 0); } /* * Probe for a GT64240 ethernet controller. */ static int __init gt64240_probe(void) { unsigned int base_addr = 0; int i; int found = 0; if (gt64240_debug > 2) printk("gt64240_probe at 0x%08x\n", base_addr); parse_mac_addr_options(); for (i = 0; i < NUM_INTERFACES; i++) { int base_addr = gt64240_iflist[i].port; if (check_region(base_addr, GT64240_ETH_IO_SIZE)) { printk("gt64240_probe: ioaddr 0x%lx taken?\n", base_addr); continue; } if (gt64240_probe1(base_addr, gt64240_iflist[i].irq, i) == 0) { /* Does not seem to be the "traditional" way folks do this, */ /* but I want to init both eth ports if at all possible! */ /* So, until I find out the "correct" way to do this: */ if (++found == NUM_INTERFACES) /* That's all of them! */ return 0; } } if (found) return 0; /* as long as we found at least one! */ return -ENODEV; } module_init(gt64240_probe); static int __init gt64240_probe1(uint32_t ioaddr, int irq, int port_num) { struct net_device *dev = NULL; static unsigned version_printed = 0; struct gt64240_private *gp = NULL; int retval; u32 cpuConfig; unsigned char chip_rev; dev = alloc_etherdev(sizeof(struct gt64240_private)); if (!dev) return -ENOMEM; if (irq < 0) { printk ("gt64240_probe1: irq unknown - probing not supported\n"); return -ENODEV; } #if 1 /* KLUDGE Alert: no check on return value: */ if (!request_region(ioaddr, GT64240_ETH_IO_SIZE, "gt64240eth")) printk("*** request_region() failed!\n"); #endif cpuConfig = GT64240_READ(CPU_CONFIGURATION); printk("gt64240_probe1: cpu in %s-endian mode\n", (cpuConfig & (1 << 12)) ? "little" : "big"); printk ("%s: GT64240 found at ioaddr 0x%lx, irq %d.\n", dev->name, ioaddr, irq); if (gt64240_debug && version_printed++ == 0) printk("%s: %s", dev->name, version); /* private struct aligned and zeroed by init_etherdev */ /* Fill in the 'dev' fields. */ dev->base_addr = ioaddr; dev->irq = irq; memcpy(dev->dev_addr, gt64240_station_addr[port_num], sizeof(dev->dev_addr)); printk("%s: HW Address ", dev->name); dump_hw_addr(dev->dev_addr); gp = dev->priv; gp->msg_enable = (debug < 0 ? GT64240_MSG_ENABLE : debug); gp->port_num = port_num; gp->io_size = GT64240_ETH_IO_SIZE; gp->port_offset = port_num * GT64240_ETH_IO_SIZE; gp->phy_addr = gt64240_phy_addr[port_num]; pcibios_read_config_byte(0, 0, PCI_REVISION_ID, &chip_rev); gp->chip_rev = chip_rev; printk("%s: GT64240 chip revision=%d\n", dev->name, gp->chip_rev); printk("%s: GT64240 ethernet port %d\n", dev->name, gp->port_num); #ifdef GT64240_NAPI printk("Rx NAPI supported \n"); #endif /* MII Initialization */ gp->mii_if.dev = dev; gp->mii_if.phy_id = dev->base_addr; gp->mii_if.mdio_read = read_MII; gp->mii_if.mdio_write = write_MII; gp->mii_if.advertising = read_MII(dev, MII_ADVERTISE); // Allocate Rx and Tx descriptor rings if (gp->rx_ring == NULL) { // All descriptors in ring must be 16-byte aligned gp->rx_ring = dmaalloc(sizeof(gt64240_rd_t) * RX_RING_SIZE + sizeof(gt64240_td_t) * TX_RING_SIZE, &gp->rx_ring_dma); if (gp->rx_ring == NULL) { retval = -ENOMEM; goto free_region; } gp->tx_ring = (gt64240_td_t *) (gp->rx_ring + RX_RING_SIZE); gp->tx_ring_dma = gp->rx_ring_dma + sizeof(gt64240_rd_t) * RX_RING_SIZE; } // Allocate the Rx Data Buffers if (gp->rx_buff == NULL) { gp->rx_buff = dmaalloc(PKT_BUF_SZ * RX_RING_SIZE, &gp->rx_buff_dma); if (gp->rx_buff == NULL) { dmafree(sizeof(gt64240_rd_t) * RX_RING_SIZE + sizeof(gt64240_td_t) * TX_RING_SIZE, gp->rx_ring); retval = -ENOMEM; goto free_region; } } if (gt64240_debug > 3) printk("%s: gt64240_probe1, rx_ring=%p, tx_ring=%p\n", dev->name, gp->rx_ring, gp->tx_ring); // Allocate Rx Hash Table if (gp->hash_table == NULL) { gp->hash_table = (char *) dmaalloc(RX_HASH_TABLE_SIZE, &gp->hash_table_dma); if (gp->hash_table == NULL) { dmafree(sizeof(gt64240_rd_t) * RX_RING_SIZE + sizeof(gt64240_td_t) * TX_RING_SIZE, gp->rx_ring); dmafree(PKT_BUF_SZ * RX_RING_SIZE, gp->rx_buff); retval = -ENOMEM; goto free_region; } } if (gt64240_debug > 3) printk("%s: gt64240_probe1, hash=%p\n", dev->name, gp->hash_table); spin_lock_init(&gp->lock); dev->open = gt64240_open; dev->hard_start_xmit = gt64240_tx; dev->stop = gt64240_close; dev->get_stats = gt64240_get_stats; dev->do_ioctl = gt64240_ioctl; dev->set_multicast_list = gt64240_set_rx_mode; dev->tx_timeout = gt64240_tx_timeout; dev->watchdog_timeo = GT64240ETH_TX_TIMEOUT; #ifdef GT64240_NAPI dev->poll = gt64240_poll; dev->weight = 64; #endif dev->ethtool_ops = &gp_ethtool_ops; /* Fill in the fields of the device structure with ethernet values. */ return 0; free_region: release_region(ioaddr, gp->io_size); unregister_netdev(dev); if (dev->priv != NULL) kfree(dev->priv); kfree(dev); printk("%s: gt64240_probe1 failed. Returns %d\n", dev->name, retval); return retval; } static void reset_tx(struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; int i; abort(dev, sdcmrAT); for (i = 0; i < TX_RING_SIZE; i++) { if (gp->tx_skbuff[i]) { if (in_interrupt()) dev_kfree_skb_irq(gp->tx_skbuff[i]); else dev_kfree_skb(gp->tx_skbuff[i]); gp->tx_skbuff[i] = NULL; } //- gp->tx_ring[i].cmdstat = 0; // CPU owns gp->tx_ring[i].cmdstat = (u32) (txGenCRC | txEI | txPad | txFirst | txLast); gp->tx_ring[i].byte_cnt = 0; gp->tx_ring[i].buff_ptr = 0; gp->tx_ring[i].next = gp->tx_ring_dma + sizeof(gt64240_td_t) * (i + 1); if (gt64240_debug > 4) dump_tx_desc(dev, i); } /* Wrap the ring. */ gp->tx_ring[i - 1].next = gp->tx_ring_dma; if (gt64240_debug > 4) dump_tx_desc(dev, i - 1); // setup only the lowest priority TxCDP reg GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR0, gp->tx_ring_dma); //- GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR0, 0); /* ROLLINS */ //- GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR0,virt_to_phys(&gp->tx_ring[0])); /* ROLLINS */ GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR1, 0); // init Tx indeces and pkt counter gp->tx_next_in = gp->tx_next_out = 0; gp->tx_count = 0; } static void reset_rx(struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; int i; abort(dev, sdcmrAR); for (i = 0; i < RX_RING_SIZE; i++) { gp->rx_ring[i].next = gp->rx_ring_dma + sizeof(gt64240_rd_t) * (i + 1); gp->rx_ring[i].buff_ptr = gp->rx_buff_dma + i * PKT_BUF_SZ; gp->rx_ring[i].buff_sz = PKT_BUF_SZ; gp->rx_ring[i].byte_cnt = 0; /* just for debug printk's */ // Give ownership to device, set first and last, enable interrupt gp->rx_ring[i].cmdstat = (uint32_t) (rxFirst | rxLast | rxOwn | rxEI); if (gt64240_debug > 4) dump_rx_desc(dev, i); } /* Wrap the ring. */ gp->rx_ring[i - 1].next = gp->rx_ring_dma; if (gt64240_debug > 4) dump_rx_desc(dev, i - 1); // Setup only the lowest priority RxFDP and RxCDP regs for (i = 0; i < 4; i++) { if (i == 0) { GT64240ETH_WRITE(gp, GT64240_ETH_1ST_RX_DESC_PTR0, gp->rx_ring_dma); GT64240ETH_WRITE(gp, GT64240_ETH_CURR_RX_DESC_PTR0, gp->rx_ring_dma); } else { GT64240ETH_WRITE(gp, GT64240_ETH_1ST_RX_DESC_PTR0 + i * 4, 0); GT64240ETH_WRITE(gp, GT64240_ETH_CURR_RX_DESC_PTR0 + i * 4, 0); } } // init Rx NextOut index gp->rx_next_out = 0; } static int gt64240_init(struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; if (gt64240_debug > 3) { printk("%s: gt64240_init: dev=%p\n", dev->name, dev); printk("%s: gt64240_init: scs0_lo=%04x, scs0_hi=%04x\n", dev->name, GT64240_READ(0x008), GT64240_READ(0x010)); printk("%s: gt64240_init: scs1_lo=%04x, scs1_hi=%04x\n", dev->name, GT64240_READ(0x208), GT64240_READ(0x210)); printk("%s: gt64240_init: scs2_lo=%04x, scs2_hi=%04x\n", dev->name, GT64240_READ(0x018), GT64240_READ(0x020)); printk("%s: gt64240_init: scs3_lo=%04x, scs3_hi=%04x\n", dev->name, GT64240_READ(0x218), GT64240_READ(0x220)); } // Stop and disable Port hard_stop(dev); GT64240_WRITE(COMM_UNIT_INTERRUPT_MASK, 0x07070777); /*+prk21aug01 */ if (gt64240_debug > 2) printk ("%s: gt64240_init: CIU Cause=%08x, Mask=%08x, EAddr=%08x\n", dev->name, GT64240_READ(COMM_UNIT_INTERRUPT_CAUSE), GT64240_READ(COMM_UNIT_INTERRUPT_MASK), GT64240_READ(COMM_UNIT_ERROR_ADDRESS)); // Set-up hash table memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear it gp->hash_mode = 0; // Add a single entry to hash table - our ethernet address gt64240_add_hash_entry(dev, dev->dev_addr); // Set-up DMA ptr to hash table GT64240ETH_WRITE(gp, GT64240_ETH_HASH_TBL_PTR, gp->hash_table_dma); if (gt64240_debug > 3) printk("%s: gt64240_init: Hash Tbl Ptr=%x\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_HASH_TBL_PTR)); // Setup Tx reset_tx(dev); if (gt64240_debug > 3) printk("%s: gt64240_init: Curr Tx Desc Ptr0=%x\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_CURR_TX_DESC_PTR0)); // Setup Rx reset_rx(dev); if (gt64240_debug > 3) printk("%s: gt64240_init: 1st/Curr Rx Desc Ptr0=%x/%x\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_1ST_RX_DESC_PTR0), GT64240ETH_READ(gp, GT64240_ETH_CURR_RX_DESC_PTR0)); if (gt64240_debug > 3) dump_MII(dev); write_MII(dev, 0, 0x8000); /* force a PHY reset -- self-clearing! */ if (gt64240_debug > 3) printk("%s: gt64240_init: PhyAD=%x\n", dev->name, GT64240_READ(GT64240_ETH_PHY_ADDR_REG)); // setup DMA // We want the Rx/Tx DMA to write/read data to/from memory in // Big Endian mode. Also set DMA Burst Size to 8 64Bit words. #ifdef DESC_DATA_BE GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_CONFIG, (0xf << sdcrRCBit) | sdcrRIFB | (3 << sdcrBSZBit)); #else GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_CONFIG, sdcrBLMR | sdcrBLMT | //- (0xf< 3) printk("%s: gt64240_init: SDMA Config=%x\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_SDMA_CONFIG)); #if 0 // start Rx DMA GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, sdcmrERD); #endif if (gt64240_debug > 3) printk("%s: gt64240_init: SDMA Cmd =%x\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_SDMA_COMM)); #if 1 GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, PORT_CONFIG); #endif if (gt64240_debug > 3) printk("%s: gt64240_init: Port Config=%x\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_PORT_CONFIG)); /* * Disable all Type-of-Service queueing. All Rx packets will be * treated normally and will be sent to the lowest priority * queue. * * Disable flow-control for now. FIX! support flow control? */ #if 1 // clear all the MIB ctr regs GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG_EXT, EXT_CONFIG_CLEAR); read_mib_counters(gp); GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG_EXT, EXT_CONFIG_CLEAR | pcxrMIBclrMode); #endif if (gt64240_debug > 3) printk("%s: gt64240_init: Port Config Ext=%x\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_PORT_CONFIG_EXT)); if (gt64240_debug > 3) printk("%s: gt64240_init: Port Command=%x\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_PORT_COMMAND)); GT64240ETH_WRITE(gp, GT64240_ETH_PORT_COMMAND, 0x0); netif_start_queue(dev); /* enable the port */ GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, (PORT_CONFIG | pcrEN)); if (gt64240_debug > 3) printk("%s: gt64240_init: Port Config=%x\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_PORT_CONFIG)); #if 1 // start Rx DMA GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, sdcmrERD); #endif // enable interrupts enable_ether_irq(dev); //--- gp->last_psr |= psrLink; /* KLUDGE ALERT */ // we should now be receiving frames return 0; } static int gt64240_open(struct net_device *dev) { int retval; MOD_INC_USE_COUNT; if (gt64240_debug > 3) printk("%s: gt64240_open: dev=%p\n", dev->name, dev); if ((retval = request_irq(dev->irq, >64240_interrupt, SA_SHIRQ, dev->name, dev))) { printk("%s: unable to get IRQ %d\n", dev->name, dev->irq); MOD_DEC_USE_COUNT; return retval; } // Initialize and startup the GT-64240 ethernet port if ((retval = gt64240_init(dev))) { printk("%s: error in gt64240_open\n", dev->name); free_irq(dev->irq, dev); MOD_DEC_USE_COUNT; return retval; } if (gt64240_debug > 3) printk("%s: gt64240_open: Initialization done.\n", dev->name); return 0; } static int gt64240_close(struct net_device *dev) { if (gt64240_debug > 3) printk("%s: gt64240_close: dev=%p\n", dev->name, dev); // stop the device if (netif_device_present(dev)) { netif_stop_queue(dev); hard_stop(dev); } free_irq(dev->irq, dev); MOD_DEC_USE_COUNT; return 0; } #ifdef GT64240_NAPI /* * Function will release Tx skbs which are now complete */ static void gt64240_tx_fill(struct net_device *netdev, u32 status) { struct gt64240_private *gp = (struct gt64240_private *) netdev->priv; int nextOut, cdp; gt64240_td_t *td; u32 cmdstat; cdp = (GT64240ETH_READ(gp, GT64240_ETH_CURR_TX_DESC_PTR0) - gp->tx_ring_dma) / sizeof(gt64240_td_t); for (nextOut = gp->tx_next_out; nextOut != cdp; nextOut = (nextOut + 1) % TX_RING_SIZE) { if (--gp->intr_work_done == 0) break; td = &gp->tx_ring[nextOut]; cmdstat = td->cmdstat; if (cmdstat & (u32) txOwn) break; if (gp->tx_full) { gp->tx_full = 0; if (gp->last_psr & psrLink) { netif_wake_queue(netdev); } } // decrement tx ring buffer count if (gp->tx_count) gp->tx_count--; // free the skb if (gp->tx_skbuff[nextOut]) { dev_kfree_skb_irq(gp->tx_skbuff[nextOut]); gp->tx_skbuff[nextOut] = NULL; } } gp->tx_next_out = nextOut; if ((status & icrTxEndLow) && gp->tx_count != 0) // we must restart the DMA GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, sdcmrERD | sdcmrTXDL); } /* * Main function for NAPI */ static int gt64240_poll(struct net_device *netdev, int *budget) { struct gt64240_private *gp = (struct gt64240_private *) netdev->priv; unsigned long flags; int done = 1, orig_budget, work_done; u32 status = GT64240ETH_READ(gp, GT64240_ETH_INT_CAUSE); spin_lock_irqsave(&gp->lock, flags); gt64240_tx_fill(netdev, status); if (GT64240ETH_READ(gp, GT64240_ETH_CURR_RX_DESC_PTR0) != gp->rx_next_out) { orig_budget = *budget; if (orig_budget > netdev->quota) orig_budget = netdev->quota; work_done = gt64240_rx(netdev, status, orig_budget); *budget -= work_done; netdev->quota -= work_done; if (work_done >= orig_budget) done = 0; if (done) { __netif_rx_complete(netdev); enable_ether_irq(netdev); } } spin_unlock_irqrestore(&gp->lock, flags); return (done ? 0 : 1); } #endif static int gt64240_tx(struct sk_buff *skb, struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; unsigned long flags; int nextIn; spin_lock_irqsave(&gp->lock, flags); nextIn = gp->tx_next_in; if (gt64240_debug > 3) { printk("%s: gt64240_tx: nextIn=%d.\n", dev->name, nextIn); } if (gp->tx_count >= TX_RING_SIZE) { printk("%s: Tx Ring full, pkt dropped.\n", dev->name); gp->stats.tx_dropped++; spin_unlock_irqrestore(&gp->lock, flags); return 1; } if (!(gp->last_psr & psrLink)) { printk("%s: gt64240_tx: Link down, pkt dropped.\n", dev->name); gp->stats.tx_dropped++; spin_unlock_irqrestore(&gp->lock, flags); //--- dump_MII(dev); /* KLUDGE ALERT !!! */ return 1; } if (gp->tx_ring[nextIn].cmdstat & txOwn) { printk ("%s: gt64240_tx: device owns descriptor, pkt dropped.\n", dev->name); gp->stats.tx_dropped++; // stop the queue, so Tx timeout can fix it netif_stop_queue(dev); spin_unlock_irqrestore(&gp->lock, flags); return 1; } // Prepare the Descriptor at tx_next_in gp->tx_skbuff[nextIn] = skb; gp->tx_ring[nextIn].byte_cnt = skb->len; gp->tx_ring[nextIn].buff_ptr = virt_to_phys(skb->data); // make sure packet gets written back to memory dma_cache_wback_inv((unsigned long) (skb->data), skb->len); mb(); // Give ownership to device, set first and last desc, enable interrupt // Setting of ownership bit must be *last*! gp->tx_ring[nextIn].cmdstat = txOwn | txGenCRC | txEI | txPad | txFirst | txLast; if (gt64240_debug > 5) { dump_tx_desc(dev, nextIn); dump_skb(dev, skb); } // increment tx_next_in with wrap gp->tx_next_in = (nextIn + 1) % TX_RING_SIZE; //+prk20aug01: if (0) { /* ROLLINS */ GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR0, virt_to_phys(&gp->tx_ring[nextIn])); } if (gt64240_debug > 3) { /*+prk17aug01 */ printk ("%s: gt64240_tx: TX_PTR0=0x%08x, EthPortStatus=0x%08x\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_CURR_TX_DESC_PTR0), GT64240ETH_READ(gp, GT64240_ETH_PORT_STATUS)); } // If DMA is stopped, restart if (!((GT64240ETH_READ(gp, GT64240_ETH_PORT_STATUS)) & psrTxLow)) { GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, sdcmrERD | sdcmrTXDL); } if (gt64240_debug > 3) { /*+prk17aug01 */ printk ("%s: gt64240_tx: TX_PTR0=0x%08x, EthPortStatus=0x%08x\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_CURR_TX_DESC_PTR0), GT64240ETH_READ(gp, GT64240_ETH_PORT_STATUS)); } // increment count and stop queue if full if (++gp->tx_count >= TX_RING_SIZE) { gp->tx_full = 1; netif_stop_queue(dev); } dev->trans_start = jiffies; spin_unlock_irqrestore(&gp->lock, flags); return 0; } static int #ifdef GT64240_NAPI gt64240_rx(struct net_device *dev, u32 status, int budget) #else gt64240_rx(struct net_device *dev, u32 status) #endif { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; struct sk_buff *skb; int pkt_len, nextOut, cdp; gt64240_rd_t *rd; u32 cmdstat; if (gt64240_debug > 3) printk("%s: gt64240_rx: dev=%p, status=%x\n", dev->name, dev, status); cdp = (GT64240ETH_READ(gp, GT64240_ETH_CURR_RX_DESC_PTR0) - gp->rx_ring_dma) / sizeof(gt64240_rd_t); // Continue until we reach the current descriptor pointer for (nextOut = gp->rx_next_out; nextOut != cdp; nextOut = (nextOut + 1) % RX_RING_SIZE) { #ifdef GT64240_NAPI if (budget <= 0) break; budget--; #endif if (--gp->intr_work_done == 0) break; if (gt64240_debug > 4) dump_rx_desc(dev, nextOut); rd = &gp->rx_ring[nextOut]; cmdstat = rd->cmdstat; if (gt64240_debug > 3) printk("%s: isr: Rx desc cmdstat=%x, nextOut=%d\n", dev->name, cmdstat, nextOut); if (cmdstat & (u32) rxOwn) { if (gt64240_debug > 2) printk ("%s: gt64240_rx: device owns descriptor!\n", dev->name); // DMA is not finished updating descriptor??? // Leave and come back later to pick-up where we left off. break; } // must be first and last (ie only) buffer of packet if (!(cmdstat & (u32) rxFirst) || !(cmdstat & (u32) rxLast)) { printk ("%s: gt64240_rx: desc not first and last!\n", dev->name); cmdstat |= (u32) rxOwn; rd->cmdstat = cmdstat; continue; } // Drop this received pkt if there were any errors if ((cmdstat & (u32) rxErrorSummary) || (status & icrRxError)) { // update the detailed rx error counters that are not covered // by the MIB counters. if (cmdstat & (u32) rxOverrun) gp->stats.rx_fifo_errors++; cmdstat |= (u32) rxOwn; rd->cmdstat = cmdstat; continue; } pkt_len = rd->byte_cnt; /* Create new skb. */ // skb = dev_alloc_skb(pkt_len+2); skb = dev_alloc_skb(1538); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); gp->stats.rx_dropped++; cmdstat |= (u32) rxOwn; rd->cmdstat = cmdstat; continue; } skb->dev = dev; skb_reserve(skb, 2); /* 16 byte IP header align */ memcpy(skb_put(skb, pkt_len), &gp->rx_buff[nextOut * PKT_BUF_SZ], pkt_len); skb->protocol = eth_type_trans(skb, dev); if (gt64240_debug > 4) /* will probably Oops! */ dump_data(dev, &gp->rx_buff[nextOut * PKT_BUF_SZ], pkt_len); if (gt64240_debug > 4) dump_skb(dev, skb); /* NIC performed some checksum computation */ skb->ip_summed = CHECKSUM_UNNECESSARY; #ifdef GT64240_NAPI netif_receive_skb(skb); #else netif_rx(skb); /* pass the packet to upper layers */ #endif // now we can release ownership of this desc back to device cmdstat |= (u32) rxOwn; rd->cmdstat = cmdstat; dev->last_rx = jiffies; } if (gt64240_debug > 3 && nextOut == gp->rx_next_out) printk("%s: gt64240_rx: RxCDP did not increment?\n", dev->name); gp->rx_next_out = nextOut; return 0; } static void gt64240_tx_complete(struct net_device *dev, u32 status) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; int nextOut, cdp; gt64240_td_t *td; u32 cmdstat; cdp = (GT64240ETH_READ(gp, GT64240_ETH_CURR_TX_DESC_PTR0) - gp->tx_ring_dma) / sizeof(gt64240_td_t); if (gt64240_debug > 3) { /*+prk17aug01 */ nextOut = gp->tx_next_out; printk ("%s: tx_complete: TX_PTR0=0x%08x, cdp=%d. nextOut=%d.\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_CURR_TX_DESC_PTR0), cdp, nextOut); td = &gp->tx_ring[nextOut]; } /*** NEED to check and CLEAR these errors every time thru here: ***/ if (gt64240_debug > 2) { if (GT64240_READ(COMM_UNIT_INTERRUPT_CAUSE)) printk ("%s: gt64240_tx_complete: CIU Cause=%08x, Mask=%08x, EAddr=%08x\n", dev->name, GT64240_READ(COMM_UNIT_INTERRUPT_CAUSE), GT64240_READ(COMM_UNIT_INTERRUPT_MASK), GT64240_READ(COMM_UNIT_ERROR_ADDRESS)); GT64240_WRITE(COMM_UNIT_INTERRUPT_CAUSE, 0); } // Continue until we reach the current descriptor pointer for (nextOut = gp->tx_next_out; nextOut != cdp; nextOut = (nextOut + 1) % TX_RING_SIZE) { if (--gp->intr_work_done == 0) break; td = &gp->tx_ring[nextOut]; cmdstat = td->cmdstat; if (cmdstat & (u32) txOwn) { // DMA is not finished writing descriptor??? // Leave and come back later to pick-up where we left off. break; } // increment Tx error stats if (cmdstat & (u32) txErrorSummary) { if (gt64240_debug > 2) printk ("%s: tx_complete: Tx error, cmdstat = %x\n", dev->name, cmdstat); gp->stats.tx_errors++; if (cmdstat & (u32) txReTxLimit) gp->stats.tx_aborted_errors++; if (cmdstat & (u32) txUnderrun) gp->stats.tx_fifo_errors++; if (cmdstat & (u32) txLateCollision) gp->stats.tx_window_errors++; } if (cmdstat & (u32) txCollision) gp->stats.collisions += (unsigned long) ((cmdstat & txReTxCntMask) >> txReTxCntBit); // Wake the queue if the ring was full if (gp->tx_full) { gp->tx_full = 0; if (gp->last_psr & psrLink) { netif_wake_queue(dev); } } // decrement tx ring buffer count if (gp->tx_count) gp->tx_count--; // free the skb if (gp->tx_skbuff[nextOut]) { if (gt64240_debug > 3) printk ("%s: tx_complete: good Tx, skb=%p\n", dev->name, gp->tx_skbuff[nextOut]); dev_kfree_skb_irq(gp->tx_skbuff[nextOut]); gp->tx_skbuff[nextOut] = NULL; } else { printk("%s: tx_complete: no skb!\n", dev->name); } } gp->tx_next_out = nextOut; if ((status & icrTxEndLow) && gp->tx_count != 0) { // we must restart the DMA GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, sdcmrERD | sdcmrTXDL); } } static void gt64240_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; struct gt64240_private *gp = (struct gt64240_private *) dev->priv; u32 status; if (dev == NULL) { printk("%s: isr: null dev ptr\n", dev->name); return; } spin_lock(&gp->lock); if (gt64240_debug > 3) printk("%s: isr: entry\n", dev->name); gp->intr_work_done = max_interrupt_work; while (gp->intr_work_done > 0) { status = GT64240ETH_READ(gp, GT64240_ETH_INT_CAUSE); #ifdef GT64240_NAPI /* dont ack Rx interrupts */ if (!(status & icrRxBuffer)) GT64240ETH_WRITE(gp, GT64240_ETH_INT_CAUSE, 0); #else // ACK interrupts GT64240ETH_WRITE(gp, GT64240_ETH_INT_CAUSE, 0); #endif if (gt64240_debug > 3) printk("%s: isr: work=%d., icr=%x\n", dev->name, gp->intr_work_done, status); if ((status & icrEtherIntSum) == 0) { if (!(status & (icrTxBufferLow | icrTxBufferHigh | icrRxBuffer))) { /* exit from the while() loop */ break; } } if (status & icrMIIPhySTC) { u32 psr = GT64240ETH_READ(gp, GT64240_ETH_PORT_STATUS); if (gp->last_psr != psr) { printk("%s: port status: 0x%08x\n", dev->name, psr); printk ("%s: %s MBit/s, %s-duplex, flow-control %s, link is %s,\n", dev->name, psr & psrSpeed ? "100" : "10", psr & psrDuplex ? "full" : "half", psr & psrFctl ? "disabled" : "enabled", psr & psrLink ? "up" : "down"); printk ("%s: TxLowQ is %s, TxHighQ is %s, Transmitter is %s\n", dev->name, psr & psrTxLow ? "running" : "stopped", psr & psrTxHigh ? "running" : "stopped", psr & psrTxInProg ? "on" : "off"); if ((psr & psrLink) && !gp->tx_full && netif_queue_stopped(dev)) { printk ("%s: isr: Link up, waking queue.\n", dev->name); netif_wake_queue(dev); } else if (!(psr & psrLink) && !netif_queue_stopped(dev)) { printk ("%s: isr: Link down, stopping queue.\n", dev->name); netif_stop_queue(dev); } gp->last_psr = psr; } } if (status & (icrTxBufferLow | icrTxEndLow)) gt64240_tx_complete(dev, status); if (status & icrRxBuffer) { #ifdef GT64240_NAPI if (netif_rx_schedule_prep(dev)) { disable_ether_irq(dev); __netif_rx_schedule(dev); } #else gt64240_rx(dev, status); #endif } // Now check TX errors (RX errors were handled in gt64240_rx) if (status & icrTxErrorLow) { printk("%s: isr: Tx resource error\n", dev->name); } if (status & icrTxUdr) { printk("%s: isr: Tx underrun error\n", dev->name); } } if (gp->intr_work_done == 0) { // ACK any remaining pending interrupts GT64240ETH_WRITE(gp, GT64240_ETH_INT_CAUSE, 0); if (gt64240_debug > 3) printk("%s: isr: hit max work\n", dev->name); } if (gt64240_debug > 3) printk("%s: isr: exit, icr=%x\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_INT_CAUSE)); spin_unlock(&gp->lock); } static void gt64240_tx_timeout(struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; unsigned long flags; spin_lock_irqsave(&gp->lock, flags); if (!(gp->last_psr & psrLink)) { spin_unlock_irqrestore(&gp->lock, flags); } else { printk("======------> gt64240_tx_timeout: %d jiffies \n", GT64240ETH_TX_TIMEOUT); disable_ether_irq(dev); spin_unlock_irqrestore(&gp->lock, flags); reset_tx(dev); enable_ether_irq(dev); netif_wake_queue(dev); } } static void gt64240_set_rx_mode(struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; unsigned long flags; struct dev_mc_list *mcptr; if (gt64240_debug > 3) printk("%s: gt64240_set_rx_mode: dev=%p, flags=%x\n", dev->name, dev, dev->flags); // stop the Receiver DMA abort(dev, sdcmrAR); spin_lock_irqsave(&gp->lock, flags); if (dev->flags & IFF_PROMISC) GT64240ETH_SETBIT(gp, GT64240_ETH_PORT_CONFIG, pcrPM); else GT64240ETH_CLRBIT(gp, GT64240_ETH_PORT_CONFIG, pcrPM); /* GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, (PORT_CONFIG | pcrPM | pcrEN)); */ memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear hash table // Add our ethernet address gt64240_add_hash_entry(dev, dev->dev_addr); if (dev->mc_count) { for (mcptr = dev->mc_list; mcptr; mcptr = mcptr->next) { if (gt64240_debug > 2) { printk("%s: gt64240_set_rx_mode: addr=\n", dev->name); dump_hw_addr(mcptr->dmi_addr); } gt64240_add_hash_entry(dev, mcptr->dmi_addr); } } if (gt64240_debug > 3) printk("%s: gt64240_set_rx: Port Config=%x\n", dev->name, GT64240ETH_READ(gp, GT64240_ETH_PORT_CONFIG)); // restart Rx DMA GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, sdcmrERD); spin_unlock_irqrestore(&gp->lock, flags); } static struct net_device_stats *gt64240_get_stats(struct net_device *dev) { struct gt64240_private *gp = (struct gt64240_private *) dev->priv; unsigned long flags; if (gt64240_debug > 3) printk("%s: gt64240_get_stats: dev=%p\n", dev->name, dev); if (netif_device_present(dev)) { spin_lock_irqsave(&gp->lock, flags); update_stats(gp); spin_unlock_irqrestore(&gp->lock, flags); } return &gp->stats; } MODULE_AUTHOR("MontaVista Software, Inc."); MODULE_DESCRIPTION("Ethernet driver for the MIPS GT96100 Advanced Communication Controller. Modified for the Gallileo/Marvell GT-64240 Communication Controller."); MODULE_LICENSE("GPL");