diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig --- a/drivers/net/Kconfig 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/Kconfig 2005-03-08 14:29:45 -05:00 @@ -2066,10 +2066,11 @@ config MV643XX_ETH tristate "MV-643XX Ethernet support" - depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MOMENCO_OCELOT_3 + depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 help This driver supports the gigabit Ethernet on the Marvell MV643XX - chipset which is used in the Momenco Ocelot C and Jaguar ATX. + chipset which is used in the Momenco Ocelot C and Jaguar ATX and + Pegasos II, amongst other PPC and MIPS boards. config MV643XX_ETH_0 bool "MV-643XX Port 0" diff -Nru a/drivers/net/fealnx.c b/drivers/net/fealnx.c --- a/drivers/net/fealnx.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/fealnx.c 2005-03-08 14:29:45 -05:00 @@ -102,21 +102,6 @@ #define USE_IO_OPS #endif -#ifdef USE_IO_OPS -#undef readb -#undef readw -#undef readl -#undef writeb -#undef writew -#undef writel -#define readb inb -#define readw inw -#define readl inl -#define writeb outb -#define writew outw -#define writel outl -#endif - /* Kernel compatibility defines, some common to David Hinds' PCMCIA package. */ /* This is only in the support-all-kernels source code. */ @@ -444,6 +429,7 @@ int mii_cnt; /* MII device addresses. */ unsigned char phys[2]; /* MII device addresses. */ struct mii_if_info mii; + void __iomem *mem; }; @@ -468,23 +454,23 @@ static void reset_rx_descriptors(struct net_device *dev); static void reset_tx_descriptors(struct net_device *dev); -static void stop_nic_rx(long ioaddr, long crvalue) +static void stop_nic_rx(void __iomem *ioaddr, long crvalue) { int delay = 0x1000; - writel(crvalue & ~(CR_W_RXEN), ioaddr + TCRRCR); + iowrite32(crvalue & ~(CR_W_RXEN), ioaddr + TCRRCR); while (--delay) { - if ( (readl(ioaddr + TCRRCR) & CR_R_RXSTOP) == CR_R_RXSTOP) + if ( (ioread32(ioaddr + TCRRCR) & CR_R_RXSTOP) == CR_R_RXSTOP) break; } } -static void stop_nic_rxtx(long ioaddr, long crvalue) +static void stop_nic_rxtx(void __iomem *ioaddr, long crvalue) { int delay = 0x1000; - writel(crvalue & ~(CR_W_RXEN+CR_W_TXEN), ioaddr + TCRRCR); + iowrite32(crvalue & ~(CR_W_RXEN+CR_W_TXEN), ioaddr + TCRRCR); while (--delay) { - if ( (readl(ioaddr + TCRRCR) & (CR_R_RXSTOP+CR_R_TXSTOP)) + if ( (ioread32(ioaddr + TCRRCR) & (CR_R_RXSTOP+CR_R_TXSTOP)) == (CR_R_RXSTOP+CR_R_TXSTOP) ) break; } @@ -498,11 +484,17 @@ int i, option, err, irq; static int card_idx = -1; char boardname[12]; - long ioaddr; + void __iomem *ioaddr; + unsigned long len; unsigned int chip_id = ent->driver_data; struct net_device *dev; void *ring_space; dma_addr_t ring_dma; +#ifdef USE_IO_OPS + int bar = 0; +#else + int bar = 1; +#endif /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -520,14 +512,10 @@ if (i) return i; pci_set_master(pdev); -#ifdef USE_IO_OPS - ioaddr = pci_resource_len(pdev, 0); -#else - ioaddr = pci_resource_len(pdev, 1); -#endif - if (ioaddr < MIN_REGION_SIZE) { + len = pci_resource_len(pdev, bar); + if (len < MIN_REGION_SIZE) { printk(KERN_ERR "%s: region size %ld too small, aborting\n", - boardname, ioaddr); + boardname, len); return -ENODEV; } @@ -536,17 +524,12 @@ irq = pdev->irq; -#ifdef USE_IO_OPS - ioaddr = pci_resource_start(pdev, 0); -#else - ioaddr = (long) ioremap(pci_resource_start(pdev, 1), - pci_resource_len(pdev, 1)); + ioaddr = pci_iomap(pdev, bar, len); if (!ioaddr) { err = -ENOMEM; goto err_out_res; } -#endif - + dev = alloc_etherdev(sizeof(struct netdev_private)); if (!dev) { err = -ENOMEM; @@ -557,16 +540,17 @@ /* read ethernet id */ for (i = 0; i < 6; ++i) - dev->dev_addr[i] = readb(ioaddr + PAR0 + i); + dev->dev_addr[i] = ioread8(ioaddr + PAR0 + i); /* Reset the chip to erase previous misconfiguration. */ - writel(0x00000001, ioaddr + BCR); + iowrite32(0x00000001, ioaddr + BCR); - dev->base_addr = ioaddr; + dev->base_addr = (unsigned long)ioaddr; dev->irq = irq; /* Make certain the descriptor lists are aligned. */ - np = dev->priv; + np = netdev_priv(dev); + np->mem = ioaddr; spin_lock_init(&np->lock); np->pci_dev = pdev; np->flags = skel_netdrv_tbl[chip_id].flags; @@ -635,7 +619,7 @@ np->phys[0] = 32; /* 89/6/23 add, (begin) */ /* get phy type */ - if (readl(ioaddr + PHYIDENTIFIER) == MysonPHYID) + if (ioread32(ioaddr + PHYIDENTIFIER) == MysonPHYID) np->PHYType = MysonPHY; else np->PHYType = OtherPHY; @@ -670,7 +654,7 @@ if (np->flags == HAS_MII_XCVR) mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL); else - writel(ADVERTISE_FULL, ioaddr + ANARANLPAR); + iowrite32(ADVERTISE_FULL, ioaddr + ANARANLPAR); np->mii.force_media = 1; } @@ -689,7 +673,7 @@ if (err) goto err_out_free_tx; - printk(KERN_INFO "%s: %s at 0x%lx, ", + printk(KERN_INFO "%s: %s at %p, ", dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); @@ -704,10 +688,8 @@ err_out_free_dev: free_netdev(dev); err_out_unmap: -#ifndef USE_IO_OPS - iounmap((void *)ioaddr); + pci_iounmap(pdev, ioaddr); err_out_res: -#endif pci_release_regions(pdev); return err; } @@ -718,16 +700,14 @@ struct net_device *dev = pci_get_drvdata(pdev); if (dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma); pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma); unregister_netdev(dev); -#ifndef USE_IO_OPS - iounmap((void *)dev->base_addr); -#endif + pci_iounmap(pdev, np->mem); free_netdev(dev); pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); @@ -736,14 +716,14 @@ } -static ulong m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad) +static ulong m80x_send_cmd_to_phy(void __iomem *miiport, int opcode, int phyad, int regad) { ulong miir; int i; unsigned int mask, data; /* enable MII output */ - miir = (ulong) readl(miiport); + miir = (ulong) ioread32(miiport); miir &= 0xfffffff0; miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO; @@ -752,11 +732,11 @@ for (i = 0; i < 32; i++) { /* low MDC; MDO is already high (miir) */ miir &= ~MASK_MIIR_MII_MDC; - writel(miir, miiport); + iowrite32(miir, miiport); /* high MDC */ miir |= MASK_MIIR_MII_MDC; - writel(miir, miiport); + iowrite32(miir, miiport); } /* calculate ST+OP+PHYAD+REGAD+TA */ @@ -770,10 +750,10 @@ if (mask & data) miir |= MASK_MIIR_MII_MDO; - writel(miir, miiport); + iowrite32(miir, miiport); /* high MDC */ miir |= MASK_MIIR_MII_MDC; - writel(miir, miiport); + iowrite32(miir, miiport); udelay(30); /* next */ @@ -787,7 +767,8 @@ static int mdio_read(struct net_device *dev, int phyad, int regad) { - long miiport = dev->base_addr + MANAGEMENT; + struct netdev_private *np = netdev_priv(dev); + void __iomem *miiport = np->mem + MANAGEMENT; ulong miir; unsigned int mask, data; @@ -799,16 +780,16 @@ while (mask) { /* low MDC */ miir &= ~MASK_MIIR_MII_MDC; - writel(miir, miiport); + iowrite32(miir, miiport); /* read MDI */ - miir = readl(miiport); + miir = ioread32(miiport); if (miir & MASK_MIIR_MII_MDI) data |= mask; /* high MDC, and wait */ miir |= MASK_MIIR_MII_MDC; - writel(miir, miiport); + iowrite32(miir, miiport); udelay(30); /* next */ @@ -817,7 +798,7 @@ /* low MDC */ miir &= ~MASK_MIIR_MII_MDC; - writel(miir, miiport); + iowrite32(miir, miiport); return data & 0xffff; } @@ -825,7 +806,8 @@ static void mdio_write(struct net_device *dev, int phyad, int regad, int data) { - long miiport = dev->base_addr + MANAGEMENT; + struct netdev_private *np = netdev_priv(dev); + void __iomem *miiport = np->mem + MANAGEMENT; ulong miir; unsigned int mask; @@ -838,11 +820,11 @@ miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); if (mask & data) miir |= MASK_MIIR_MII_MDO; - writel(miir, miiport); + iowrite32(miir, miiport); /* high MDC */ miir |= MASK_MIIR_MII_MDC; - writel(miir, miiport); + iowrite32(miir, miiport); /* next */ mask >>= 1; @@ -850,29 +832,29 @@ /* low MDC */ miir &= ~MASK_MIIR_MII_MDC; - writel(miir, miiport); + iowrite32(miir, miiport); } static int netdev_open(struct net_device *dev) { - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->mem; int i; - writel(0x00000001, ioaddr + BCR); /* Reset */ + iowrite32(0x00000001, ioaddr + BCR); /* Reset */ if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) return -EAGAIN; for (i = 0; i < 3; i++) - writew(((unsigned short*)dev->dev_addr)[i], + iowrite16(((unsigned short*)dev->dev_addr)[i], ioaddr + PAR0 + i*2); init_ring(dev); - writel(np->rx_ring_dma, ioaddr + RXLBA); - writel(np->tx_ring_dma, ioaddr + TXLBA); + iowrite32(np->rx_ring_dma, ioaddr + RXLBA); + iowrite32(np->tx_ring_dma, ioaddr + TXLBA); /* Initialize other registers. */ /* Configure the PCI bus bursts and FIFO thresholds. @@ -933,12 +915,12 @@ np->crvalue |= CR_W_ENH; /* set enhanced bit */ np->imrvalue |= ETI; } - writel(np->bcrvalue, ioaddr + BCR); + iowrite32(np->bcrvalue, ioaddr + BCR); if (dev->if_port == 0) dev->if_port = np->default_port; - writel(0, ioaddr + RXPDR); + iowrite32(0, ioaddr + RXPDR); // 89/9/1 modify, // np->crvalue = 0x00e40001; /* tx store and forward, tx/rx enable */ np->crvalue |= 0x00e40001; /* tx store and forward, tx/rx enable */ @@ -951,8 +933,8 @@ netif_start_queue(dev); /* Clear and Enable interrupts by setting the interrupt mask. */ - writel(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR); - writel(np->imrvalue, ioaddr + IMR); + iowrite32(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR); + iowrite32(np->imrvalue, ioaddr + IMR); if (debug) printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name); @@ -980,14 +962,14 @@ /* input : dev... pointer to the adapter block. */ /* output : none. */ { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); unsigned int i, DelayTime = 0x1000; np->linkok = 0; if (np->PHYType == MysonPHY) { for (i = 0; i < DelayTime; ++i) { - if (readl(dev->base_addr + BMCRSR) & LinkIsUp2) { + if (ioread32(np->mem + BMCRSR) & LinkIsUp2) { np->linkok = 1; return; } @@ -1007,14 +989,14 @@ static void getlinktype(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); if (np->PHYType == MysonPHY) { /* 3-in-1 case */ - if (readl(dev->base_addr + TCRRCR) & CR_R_FD) + if (ioread32(np->mem + TCRRCR) & CR_R_FD) np->duplexmode = 2; /* full duplex */ else np->duplexmode = 1; /* half duplex */ - if (readl(dev->base_addr + TCRRCR) & CR_R_PS10) + if (ioread32(np->mem + TCRRCR) & CR_R_PS10) np->line_speed = 1; /* 10M */ else np->line_speed = 2; /* 100M */ @@ -1110,7 +1092,7 @@ /* Take lock before calling this */ static void allocate_rx_buffers(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); /* allocate skb for rx buffers */ while (np->really_rx_count != RX_RING_SIZE) { @@ -1136,16 +1118,16 @@ static void netdev_timer(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->mem; int old_crvalue = np->crvalue; unsigned int old_linkok = np->linkok; unsigned long flags; if (debug) printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x " - "config %8.8x.\n", dev->name, readl(ioaddr + ISR), - readl(ioaddr + TCRRCR)); + "config %8.8x.\n", dev->name, ioread32(ioaddr + ISR), + ioread32(ioaddr + TCRRCR)); spin_lock_irqsave(&np->lock, flags); @@ -1155,7 +1137,7 @@ getlinktype(dev); if (np->crvalue != old_crvalue) { stop_nic_rxtx(ioaddr, np->crvalue); - writel(np->crvalue, ioaddr + TCRRCR); + iowrite32(np->crvalue, ioaddr + TCRRCR); } } } @@ -1173,22 +1155,23 @@ /* Reset chip and disable rx, tx and interrupts */ static void reset_and_disable_rxtx(struct net_device *dev) { - long ioaddr = dev->base_addr; + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->mem; int delay=51; /* Reset the chip's Tx and Rx processes. */ stop_nic_rxtx(ioaddr, 0); /* Disable interrupts by clearing the interrupt mask. */ - writel(0, ioaddr + IMR); + iowrite32(0, ioaddr + IMR); /* Reset the chip to erase previous misconfiguration. */ - writel(0x00000001, ioaddr + BCR); + iowrite32(0x00000001, ioaddr + BCR); /* Ueimor: wait for 50 PCI cycles (and flush posted writes btw). We surely wait too long (address+data phase). Who cares? */ while (--delay) { - readl(ioaddr + BCR); + ioread32(ioaddr + BCR); rmb(); } } @@ -1198,33 +1181,33 @@ /* Restore chip after reset */ static void enable_rxtx(struct net_device *dev) { - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->mem; reset_rx_descriptors(dev); - writel(np->tx_ring_dma + ((char*)np->cur_tx - (char*)np->tx_ring), + iowrite32(np->tx_ring_dma + ((char*)np->cur_tx - (char*)np->tx_ring), ioaddr + TXLBA); - writel(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring), + iowrite32(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring), ioaddr + RXLBA); - writel(np->bcrvalue, ioaddr + BCR); + iowrite32(np->bcrvalue, ioaddr + BCR); - writel(0, ioaddr + RXPDR); + iowrite32(0, ioaddr + RXPDR); __set_rx_mode(dev); /* changes np->crvalue, writes it into TCRRCR */ /* Clear and Enable interrupts by setting the interrupt mask. */ - writel(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR); - writel(np->imrvalue, ioaddr + IMR); + iowrite32(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR); + iowrite32(np->imrvalue, ioaddr + IMR); - writel(0, ioaddr + TXPDR); + iowrite32(0, ioaddr + TXPDR); } static void reset_timer(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); unsigned long flags; printk(KERN_WARNING "%s: resetting tx and rx machinery\n", dev->name); @@ -1247,13 +1230,13 @@ static void tx_timeout(struct net_device *dev) { - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->mem; unsigned long flags; int i; printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," - " resetting...\n", dev->name, readl(ioaddr + ISR)); + " resetting...\n", dev->name, ioread32(ioaddr + ISR)); { printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring); @@ -1282,7 +1265,7 @@ /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void init_ring(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); int i; /* initialize rx variables */ @@ -1346,7 +1329,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&np->lock, flags); @@ -1413,7 +1396,7 @@ if (np->free_tx_count < 2) netif_stop_queue(dev); ++np->really_tx_count; - writel(0, dev->base_addr + TXPDR); + iowrite32(0, np->mem + TXPDR); dev->trans_start = jiffies; spin_unlock_irqrestore(&np->lock, flags); @@ -1425,7 +1408,7 @@ /* Chip probably hosed tx ring. Clean up. */ static void reset_tx_descriptors(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); struct fealnx_desc *cur; int i; @@ -1460,7 +1443,7 @@ /* Take lock and stop rx before calling this */ static void reset_rx_descriptors(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); struct fealnx_desc *cur = np->cur_rx; int i; @@ -1472,8 +1455,8 @@ cur = cur->next_desc_logical; } - writel(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring), - dev->base_addr + RXLBA); + iowrite32(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring), + np->mem + RXLBA); } @@ -1482,21 +1465,21 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) { struct net_device *dev = (struct net_device *) dev_instance; - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->mem; long boguscnt = max_interrupt_work; unsigned int num_tx = 0; int handled = 0; spin_lock(&np->lock); - writel(0, ioaddr + IMR); + iowrite32(0, ioaddr + IMR); do { - u32 intr_status = readl(ioaddr + ISR); + u32 intr_status = ioread32(ioaddr + ISR); /* Acknowledge all of the current interrupt sources ASAP. */ - writel(intr_status, ioaddr + ISR); + iowrite32(intr_status, ioaddr + ISR); if (debug) printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", dev->name, @@ -1517,15 +1500,15 @@ // }; if (intr_status & TUNF) - writel(0, ioaddr + TXPDR); + iowrite32(0, ioaddr + TXPDR); if (intr_status & CNTOVF) { /* missed pkts */ - np->stats.rx_missed_errors += readl(ioaddr + TALLY) & 0x7fff; + np->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff; /* crc error */ np->stats.rx_crc_errors += - (readl(ioaddr + TALLY) & 0x7fff0000) >> 16; + (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16; } if (intr_status & (RI | RBU)) { @@ -1534,7 +1517,7 @@ else { stop_nic_rx(ioaddr, np->crvalue); reset_rx_descriptors(dev); - writel(np->crvalue, ioaddr + TCRRCR); + iowrite32(np->crvalue, ioaddr + TCRRCR); } } @@ -1605,7 +1588,7 @@ if (np->crvalue & CR_W_ENH) { long data; - data = readl(ioaddr + TSR); + data = ioread32(ioaddr + TSR); np->stats.tx_errors += (data & 0xff000000) >> 24; np->stats.tx_aborted_errors += (data & 0xff000000) >> 24; np->stats.tx_window_errors += (data & 0x00ff0000) >> 16; @@ -1635,16 +1618,16 @@ /* read the tally counters */ /* missed pkts */ - np->stats.rx_missed_errors += readl(ioaddr + TALLY) & 0x7fff; + np->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff; /* crc error */ - np->stats.rx_crc_errors += (readl(ioaddr + TALLY) & 0x7fff0000) >> 16; + np->stats.rx_crc_errors += (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16; if (debug) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", - dev->name, readl(ioaddr + ISR)); + dev->name, ioread32(ioaddr + ISR)); - writel(np->imrvalue, ioaddr + IMR); + iowrite32(np->imrvalue, ioaddr + IMR); spin_unlock(&np->lock); @@ -1656,8 +1639,8 @@ for clarity and better register allocation. */ static int netdev_rx(struct net_device *dev) { - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->mem; /* If EOP is set on the next entry, it's a new packet. Send it up. */ while (!(np->cur_rx->status & RXOWN) && np->cur_rx->skbuff) { @@ -1725,7 +1708,7 @@ } else { /* rx error, need to reset this chip */ stop_nic_rx(ioaddr, np->crvalue); reset_rx_descriptors(dev); - writel(np->crvalue, ioaddr + TCRRCR); + iowrite32(np->crvalue, ioaddr + TCRRCR); } break; /* exit the while loop */ } @@ -1793,13 +1776,13 @@ static struct net_device_stats *get_stats(struct net_device *dev) { - long ioaddr = dev->base_addr; - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->mem; /* The chip only need report frame silently dropped. */ if (netif_running(dev)) { - np->stats.rx_missed_errors += readl(ioaddr + TALLY) & 0x7fff; - np->stats.rx_crc_errors += (readl(ioaddr + TALLY) & 0x7fff0000) >> 16; + np->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff; + np->stats.rx_crc_errors += (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16; } return &np->stats; @@ -1809,7 +1792,7 @@ /* for dev->set_multicast_list */ static void set_rx_mode(struct net_device *dev) { - spinlock_t *lp = &((struct netdev_private *)dev->priv)->lock; + spinlock_t *lp = &((struct netdev_private *)netdev_priv(dev))->lock; unsigned long flags; spin_lock_irqsave(lp, flags); __set_rx_mode(dev); @@ -1820,8 +1803,8 @@ /* Take lock before calling */ static void __set_rx_mode(struct net_device *dev) { - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->mem; u32 mc_filter[2]; /* Multicast hash filter */ u32 rx_mode; @@ -1851,16 +1834,16 @@ stop_nic_rxtx(ioaddr, np->crvalue); - writel(mc_filter[0], ioaddr + MAR0); - writel(mc_filter[1], ioaddr + MAR1); + iowrite32(mc_filter[0], ioaddr + MAR0); + iowrite32(mc_filter[1], ioaddr + MAR1); np->crvalue &= ~CR_W_RXMODEMASK; np->crvalue |= rx_mode; - writel(np->crvalue, ioaddr + TCRRCR); + iowrite32(np->crvalue, ioaddr + TCRRCR); } static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -1869,7 +1852,7 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); int rc; spin_lock_irq(&np->lock); @@ -1881,7 +1864,7 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); int rc; spin_lock_irq(&np->lock); @@ -1893,13 +1876,13 @@ static int netdev_nway_reset(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); return mii_nway_restart(&np->mii); } static u32 netdev_get_link(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); return mii_link_ok(&np->mii); } @@ -1927,7 +1910,7 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); int rc; if (!netif_running(dev)) @@ -1943,14 +1926,14 @@ static int netdev_close(struct net_device *dev) { - long ioaddr = dev->base_addr; - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->mem; int i; netif_stop_queue(dev); /* Disable interrupts by clearing the interrupt mask. */ - writel(0x0000, ioaddr + IMR); + iowrite32(0x0000, ioaddr + IMR); /* Stop the chip's Tx and Rx processes. */ stop_nic_rxtx(ioaddr, 0); diff -Nru a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c --- a/drivers/net/hamradio/6pack.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/hamradio/6pack.c 2005-03-08 14:29:45 -05:00 @@ -756,12 +756,12 @@ switch(cmd) { case SIOCGIFNAME: - err = copy_to_user((void *) arg, dev->name, + err = copy_to_user((void __user *) arg, dev->name, strlen(dev->name) + 1) ? -EFAULT : 0; break; case SIOCGIFENCAP: - err = put_user(0, (int __user *)arg); + err = put_user(0, (int __user *) arg); break; case SIOCSIFENCAP: diff -Nru a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c --- a/drivers/net/hamradio/baycom_epp.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/hamradio/baycom_epp.c 2005-03-08 14:29:45 -05:00 @@ -68,25 +68,7 @@ /* --------------------------------------------------------------------- */ static const char paranoia_str[] = KERN_ERR -"baycom_epp: bad magic number for hdlcdrv_state struct in routine %s\n"; - -#define baycom_paranoia_check(dev,routine,retval) \ -({ \ - if (!dev || !dev->priv || ((struct baycom_state *)dev->priv)->magic != BAYCOM_MAGIC) { \ - printk(paranoia_str, routine); \ - return retval; \ - } \ -}) - -#define baycom_paranoia_check_void(dev,routine) \ -({ \ - if (!dev || !dev->priv || ((struct baycom_state *)dev->priv)->magic != BAYCOM_MAGIC) { \ - printk(paranoia_str, routine); \ - return; \ - } \ -}) - -/* --------------------------------------------------------------------- */ + "baycom_epp: bad magic number for hdlcdrv_state struct in routine %s\n"; static const char bc_drvname[] = "baycom_epp"; static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-2000 Thomas Sailer, HB9JNX/AE4WA\n" @@ -747,7 +729,6 @@ unsigned int time1 = 0, time2 = 0, time3 = 0; int cnt, cnt2; - baycom_paranoia_check_void(dev, "epp_bh"); bc = netdev_priv(dev); if (!bc->work_running) return; @@ -863,10 +844,8 @@ static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct baycom_state *bc; + struct baycom_state *bc = netdev_priv(dev); - baycom_paranoia_check(dev, "baycom_send_packet", 0); - bc = netdev_priv(dev); if (skb->data[0] != 0) { do_kiss_params(bc, skb->data, skb->len); dev_kfree_skb(skb); @@ -899,10 +878,8 @@ static struct net_device_stats *baycom_get_stats(struct net_device *dev) { - struct baycom_state *bc; + struct baycom_state *bc = netdev_priv(dev); - baycom_paranoia_check(dev, "baycom_get_stats", NULL); - bc = netdev_priv(dev); /* * Get the current statistics. This may be called with the * card open or closed. @@ -915,10 +892,8 @@ static void epp_wakeup(void *handle) { struct net_device *dev = (struct net_device *)handle; - struct baycom_state *bc; + struct baycom_state *bc = netdev_priv(dev); - baycom_paranoia_check_void(dev, "epp_wakeup"); - bc = netdev_priv(dev); printk(KERN_DEBUG "baycom_epp: %s: why am I being woken up?\n", dev->name); if (!parport_claim(bc->pdev)) printk(KERN_DEBUG "baycom_epp: %s: I'm broken.\n", dev->name); @@ -937,16 +912,13 @@ static int epp_open(struct net_device *dev) { - struct baycom_state *bc; - struct parport *pp; + struct baycom_state *bc = netdev_priv(dev); + struct parport *pp = parport_find_base(dev->base_addr); unsigned int i, j; unsigned char tmp[128]; unsigned char stat; unsigned long tstart; - baycom_paranoia_check(dev, "epp_open", -ENXIO); - bc = netdev_priv(dev); - pp = parport_find_base(dev->base_addr); if (!pp) { printk(KERN_ERR "%s: parport at 0x%lx unknown\n", bc_drvname, dev->base_addr); return -ENXIO; @@ -1055,13 +1027,10 @@ static int epp_close(struct net_device *dev) { - struct baycom_state *bc; - struct parport *pp; + struct baycom_state *bc = netdev_priv(dev); + struct parport *pp = bc->pdev->port; unsigned char tmp[1]; - baycom_paranoia_check(dev, "epp_close", -EINVAL); - bc = netdev_priv(dev); - pp = bc->pdev->port; bc->work_running = 0; flush_scheduled_work(); bc->stat = EPP_DCDBIT; @@ -1117,11 +1086,9 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct baycom_state *bc; + struct baycom_state *bc = netdev_priv(dev); struct hdlcdrv_ioctl hi; - baycom_paranoia_check(dev, "baycom_ioctl", -EINVAL); - bc = netdev_priv(dev); if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; @@ -1354,7 +1321,7 @@ free_netdev(dev); break; } - if (set_hw && baycom_setmode(dev->priv, mode[i])) + if (set_hw && baycom_setmode(netdev_priv(dev), mode[i])) set_hw = 0; baycom_device[i] = dev; found++; diff -Nru a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c --- a/drivers/net/hamradio/baycom_par.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/hamradio/baycom_par.c 2005-03-08 14:29:45 -05:00 @@ -85,6 +85,7 @@ #include #include +#include #include #include @@ -415,12 +416,11 @@ struct baycom_state *bc; struct baycom_ioctl bi; - if (!dev || !dev->priv || - ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { - printk(KERN_ERR "bc_ioctl: invalid device struct\n"); + if (!dev) return -EINVAL; - } + bc = netdev_priv(dev); + BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC); if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; diff -Nru a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c --- a/drivers/net/hamradio/baycom_ser_fdx.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/hamradio/baycom_ser_fdx.c 2005-03-08 14:29:45 -05:00 @@ -530,12 +530,11 @@ struct baycom_state *bc; struct baycom_ioctl bi; - if (!dev || !dev->priv || - ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { - printk(KERN_ERR "bc_ioctl: invalid device struct\n"); + if (!dev) return -EINVAL; - } + bc = netdev_priv(dev); + BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC); if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; diff -Nru a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c --- a/drivers/net/hamradio/baycom_ser_hdx.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/hamradio/baycom_ser_hdx.c 2005-03-08 14:29:45 -05:00 @@ -570,12 +570,11 @@ struct baycom_state *bc; struct baycom_ioctl bi; - if (!dev || !dev->priv || - ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { - printk(KERN_ERR "bc_ioctl: invalid device struct\n"); + if (!dev) return -EINVAL; - } + bc = netdev_priv(dev); + BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC); if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; diff -Nru a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c --- a/drivers/net/hamradio/bpqether.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/hamradio/bpqether.c 2005-03-08 14:29:45 -05:00 @@ -112,8 +112,6 @@ }; -#define MAXBPQDEV 100 - struct bpqdev { struct list_head bpq_list; /* list of bpq devices chain */ struct net_device *ethdev; /* link to ethernet device */ @@ -134,7 +132,7 @@ */ static inline struct net_device *bpq_get_ether_dev(struct net_device *dev) { - struct bpqdev *bpq = (struct bpqdev *) dev->priv; + struct bpqdev *bpq = netdev_priv(dev); return bpq ? bpq->ethdev : NULL; } @@ -191,7 +189,7 @@ * we check the source address of the sender. */ - bpq = (struct bpqdev *)dev->priv; + bpq = netdev_priv(dev); eth = eth_hdr(skb); @@ -281,7 +279,7 @@ *ptr++ = (size + 5) % 256; *ptr++ = (size + 5) / 256; - bpq = (struct bpqdev *)dev->priv; + bpq = netdev_priv(dev); if ((dev = bpq_get_ether_dev(dev)) == NULL) { bpq->stats.tx_dropped++; @@ -305,7 +303,7 @@ */ static struct net_device_stats *bpq_get_stats(struct net_device *dev) { - struct bpqdev *bpq = (struct bpqdev *) dev->priv; + struct bpqdev *bpq = netdev_priv(dev); return &bpq->stats; } @@ -332,15 +330,12 @@ static int bpq_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct bpq_ethaddr __user *ethaddr = ifr->ifr_data; - struct bpqdev *bpq = dev->priv; + struct bpqdev *bpq = netdev_priv(dev); struct bpq_req req; if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (bpq == NULL) /* woops! */ - return -ENODEV; - switch (cmd) { case SIOCSBPQETHOPT: if (copy_from_user(&req, ifr->ifr_data, sizeof(struct bpq_req))) @@ -525,7 +520,7 @@ return -ENOMEM; - bpq = ndev->priv; + bpq = netdev_priv(ndev); dev_hold(edev); bpq->ethdev = edev; bpq->axdev = ndev; @@ -554,7 +549,7 @@ static void bpq_free_device(struct net_device *ndev) { - struct bpqdev *bpq = ndev->priv; + struct bpqdev *bpq = netdev_priv(ndev); dev_put(bpq->ethdev); list_del_rcu(&bpq->bpq_list); diff -Nru a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c --- a/drivers/net/hamradio/dmascc.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/hamradio/dmascc.c 2005-03-08 14:29:45 -05:00 @@ -1,6 +1,4 @@ /* - * $Id: dmascc.c,v 1.27 2000/06/01 14:46:23 oe1kib Exp $ - * * Driver for high-speed SCC boards (those with DMA support) * Copyright (C) 1997-2000 Klaus Kudielka * @@ -19,7 +17,6 @@ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * */ @@ -49,9 +46,9 @@ /* Number of buffers per channel */ -#define NUM_TX_BUF 2 /* NUM_TX_BUF >= 1 (min. 2 recommended) */ -#define NUM_RX_BUF 6 /* NUM_RX_BUF >= 1 (min. 2 recommended) */ -#define BUF_SIZE 1576 /* BUF_SIZE >= mtu + hard_header_len */ +#define NUM_TX_BUF 2 /* NUM_TX_BUF >= 1 (min. 2 recommended) */ +#define NUM_RX_BUF 6 /* NUM_RX_BUF >= 1 (min. 2 recommended) */ +#define BUF_SIZE 1576 /* BUF_SIZE >= mtu + hard_header_len */ /* Cards supported */ @@ -67,7 +64,7 @@ #define HARDWARE { HW_PI, HW_PI2, HW_TWIN, HW_S5 } -#define TMR_0_HZ 25600 /* Frequency of timer 0 */ +#define TMR_0_HZ 25600 /* Frequency of timer 0 */ #define TYPE_PI 0 #define TYPE_PI2 1 @@ -164,69 +161,69 @@ /* Data types */ struct scc_param { - int pclk_hz; /* frequency of BRG input (don't change) */ - int brg_tc; /* BRG terminal count; BRG disabled if < 0 */ - int nrzi; /* 0 (nrz), 1 (nrzi) */ - int clocks; /* see dmascc_cfg documentation */ - int txdelay; /* [1/TMR_0_HZ] */ - int txtimeout; /* [1/HZ] */ - int txtail; /* [1/TMR_0_HZ] */ - int waittime; /* [1/TMR_0_HZ] */ - int slottime; /* [1/TMR_0_HZ] */ - int persist; /* 1 ... 256 */ - int dma; /* -1 (disable), 0, 1, 3 */ - int txpause; /* [1/TMR_0_HZ] */ - int rtsoff; /* [1/TMR_0_HZ] */ - int dcdon; /* [1/TMR_0_HZ] */ - int dcdoff; /* [1/TMR_0_HZ] */ + int pclk_hz; /* frequency of BRG input (don't change) */ + int brg_tc; /* BRG terminal count; BRG disabled if < 0 */ + int nrzi; /* 0 (nrz), 1 (nrzi) */ + int clocks; /* see dmascc_cfg documentation */ + int txdelay; /* [1/TMR_0_HZ] */ + int txtimeout; /* [1/HZ] */ + int txtail; /* [1/TMR_0_HZ] */ + int waittime; /* [1/TMR_0_HZ] */ + int slottime; /* [1/TMR_0_HZ] */ + int persist; /* 1 ... 256 */ + int dma; /* -1 (disable), 0, 1, 3 */ + int txpause; /* [1/TMR_0_HZ] */ + int rtsoff; /* [1/TMR_0_HZ] */ + int dcdon; /* [1/TMR_0_HZ] */ + int dcdoff; /* [1/TMR_0_HZ] */ }; struct scc_hardware { - char *name; - int io_region; - int io_delta; - int io_size; - int num_devs; - int scc_offset; - int tmr_offset; - int tmr_hz; - int pclk_hz; + char *name; + int io_region; + int io_delta; + int io_size; + int num_devs; + int scc_offset; + int tmr_offset; + int tmr_hz; + int pclk_hz; }; struct scc_priv { - int type; - int chip; - struct net_device *dev; - struct scc_info *info; - struct net_device_stats stats; - int channel; - int card_base, scc_cmd, scc_data; - int tmr_cnt, tmr_ctrl, tmr_mode; - struct scc_param param; - char rx_buf[NUM_RX_BUF][BUF_SIZE]; - int rx_len[NUM_RX_BUF]; - int rx_ptr; - struct work_struct rx_work; - int rx_head, rx_tail, rx_count; - int rx_over; - char tx_buf[NUM_TX_BUF][BUF_SIZE]; - int tx_len[NUM_TX_BUF]; - int tx_ptr; - int tx_head, tx_tail, tx_count; - int state; - unsigned long tx_start; - int rr0; - spinlock_t *register_lock; /* Per scc_info */ - spinlock_t ring_lock; + int type; + int chip; + struct net_device *dev; + struct scc_info *info; + struct net_device_stats stats; + int channel; + int card_base, scc_cmd, scc_data; + int tmr_cnt, tmr_ctrl, tmr_mode; + struct scc_param param; + char rx_buf[NUM_RX_BUF][BUF_SIZE]; + int rx_len[NUM_RX_BUF]; + int rx_ptr; + struct work_struct rx_work; + int rx_head, rx_tail, rx_count; + int rx_over; + char tx_buf[NUM_TX_BUF][BUF_SIZE]; + int tx_len[NUM_TX_BUF]; + int tx_ptr; + int tx_head, tx_tail, tx_count; + int state; + unsigned long tx_start; + int rr0; + spinlock_t *register_lock; /* Per scc_info */ + spinlock_t ring_lock; }; struct scc_info { - int irq_used; - int twin_serial_cfg; - struct net_device *dev[2]; - struct scc_priv priv[2]; - struct scc_info *next; - spinlock_t register_lock; /* Per device register lock */ + int irq_used; + int twin_serial_cfg; + struct net_device *dev[2]; + struct scc_priv priv[2]; + struct scc_info *next; + spinlock_t register_lock; /* Per device register lock */ }; @@ -252,7 +249,7 @@ static inline unsigned char random(void); static inline void z8530_isr(struct scc_info *info); -static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs * regs); +static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs); static void rx_isr(struct scc_priv *priv); static void special_condition(struct scc_priv *priv, int rc); static void rx_bh(void *arg); @@ -264,12 +261,15 @@ /* Initialization variables */ static int io[MAX_NUM_DEVS] __initdata = { 0, }; + /* Beware! hw[] is also used in cleanup_module(). */ static struct scc_hardware hw[NUM_TYPES] __initdata_or_module = HARDWARE; static char ax25_broadcast[7] __initdata = - { 'Q'<<1, 'S'<<1, 'T'<<1, ' '<<1, ' '<<1, ' '<<1, '0'<<1 }; + { 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, +'0' << 1 }; static char ax25_test[7] __initdata = - { 'L'<<1, 'I'<<1, 'N'<<1, 'U'<<1, 'X'<<1, ' '<<1, '1'<<1 }; + { 'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, +'1' << 1 }; /* Global variables */ @@ -283,143 +283,164 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i"); MODULE_LICENSE("GPL"); -static void __exit dmascc_exit(void) { - int i; - struct scc_info *info; - - while (first) { - info = first; - - /* Unregister devices */ - for (i = 0; i < 2; i++) - unregister_netdev(info->dev[i]); - - /* Reset board */ - if (info->priv[0].type == TYPE_TWIN) - outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG); - write_scc(&info->priv[0], R9, FHWRES); - release_region(info->dev[0]->base_addr, - hw[info->priv[0].type].io_size); - - for (i = 0; i < 2; i++) - free_netdev(info->dev[i]); - - /* Free memory */ - first = info->next; - kfree(info); - } +static void __exit dmascc_exit(void) +{ + int i; + struct scc_info *info; + + while (first) { + info = first; + + /* Unregister devices */ + for (i = 0; i < 2; i++) + unregister_netdev(info->dev[i]); + + /* Reset board */ + if (info->priv[0].type == TYPE_TWIN) + outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG); + write_scc(&info->priv[0], R9, FHWRES); + release_region(info->dev[0]->base_addr, + hw[info->priv[0].type].io_size); + + for (i = 0; i < 2; i++) + free_netdev(info->dev[i]); + + /* Free memory */ + first = info->next; + kfree(info); + } } #ifndef MODULE -void __init dmascc_setup(char *str, int *ints) { - int i; +void __init dmascc_setup(char *str, int *ints) +{ + int i; - for (i = 0; i < MAX_NUM_DEVS && i < ints[0]; i++) - io[i] = ints[i+1]; + for (i = 0; i < MAX_NUM_DEVS && i < ints[0]; i++) + io[i] = ints[i + 1]; } #endif -static int __init dmascc_init(void) { - int h, i, j, n; - int base[MAX_NUM_DEVS], tcmd[MAX_NUM_DEVS], t0[MAX_NUM_DEVS], - t1[MAX_NUM_DEVS]; - unsigned t_val; - unsigned long time, start[MAX_NUM_DEVS], delay[MAX_NUM_DEVS], - counting[MAX_NUM_DEVS]; - - /* Initialize random number generator */ - rand = jiffies; - /* Cards found = 0 */ - n = 0; - /* Warning message */ - if (!io[0]) printk(KERN_INFO "dmascc: autoprobing (dangerous)\n"); - - /* Run autodetection for each card type */ - for (h = 0; h < NUM_TYPES; h++) { - - if (io[0]) { - /* User-specified I/O address regions */ - for (i = 0; i < hw[h].num_devs; i++) base[i] = 0; - for (i = 0; i < MAX_NUM_DEVS && io[i]; i++) { - j = (io[i] - hw[h].io_region) / hw[h].io_delta; - if (j >= 0 && - j < hw[h].num_devs && - hw[h].io_region + j * hw[h].io_delta == io[i]) { - base[j] = io[i]; - } - } - } else { - /* Default I/O address regions */ - for (i = 0; i < hw[h].num_devs; i++) { - base[i] = hw[h].io_region + i * hw[h].io_delta; - } - } - - /* Check valid I/O address regions */ - for (i = 0; i < hw[h].num_devs; i++) - if (base[i]) { - if (!request_region(base[i], hw[h].io_size, "dmascc")) - base[i] = 0; - else { - tcmd[i] = base[i] + hw[h].tmr_offset + TMR_CTRL; - t0[i] = base[i] + hw[h].tmr_offset + TMR_CNT0; - t1[i] = base[i] + hw[h].tmr_offset + TMR_CNT1; - } - } - - /* Start timers */ - for (i = 0; i < hw[h].num_devs; i++) - if (base[i]) { - /* Timer 0: LSB+MSB, Mode 3, TMR_0_HZ */ - outb(0x36, tcmd[i]); - outb((hw[h].tmr_hz/TMR_0_HZ) & 0xFF, t0[i]); - outb((hw[h].tmr_hz/TMR_0_HZ) >> 8, t0[i]); - /* Timer 1: LSB+MSB, Mode 0, HZ/10 */ - outb(0x70, tcmd[i]); - outb((TMR_0_HZ/HZ*10) & 0xFF, t1[i]); - outb((TMR_0_HZ/HZ*10) >> 8, t1[i]); - start[i] = jiffies; - delay[i] = 0; - counting[i] = 1; - /* Timer 2: LSB+MSB, Mode 0 */ - outb(0xb0, tcmd[i]); - } - time = jiffies; - /* Wait until counter registers are loaded */ - udelay(2000000/TMR_0_HZ); - - /* Timing loop */ - while (jiffies - time < 13) { - for (i = 0; i < hw[h].num_devs; i++) - if (base[i] && counting[i]) { - /* Read back Timer 1: latch; read LSB; read MSB */ - outb(0x40, tcmd[i]); - t_val = inb(t1[i]) + (inb(t1[i]) << 8); - /* Also check whether counter did wrap */ - if (t_val == 0 || t_val > TMR_0_HZ/HZ*10) counting[i] = 0; - delay[i] = jiffies - start[i]; - } - } - - /* Evaluate measurements */ - for (i = 0; i < hw[h].num_devs; i++) - if (base[i]) { - if ((delay[i] >= 9 && delay[i] <= 11)&& - /* Ok, we have found an adapter */ - (setup_adapter(base[i], h, n) == 0)) - n++; - else - release_region(base[i], hw[h].io_size); - } - - } /* NUM_TYPES */ +static int __init dmascc_init(void) +{ + int h, i, j, n; + int base[MAX_NUM_DEVS], tcmd[MAX_NUM_DEVS], t0[MAX_NUM_DEVS], + t1[MAX_NUM_DEVS]; + unsigned t_val; + unsigned long time, start[MAX_NUM_DEVS], delay[MAX_NUM_DEVS], + counting[MAX_NUM_DEVS]; + + /* Initialize random number generator */ + rand = jiffies; + /* Cards found = 0 */ + n = 0; + /* Warning message */ + if (!io[0]) + printk(KERN_INFO "dmascc: autoprobing (dangerous)\n"); + + /* Run autodetection for each card type */ + for (h = 0; h < NUM_TYPES; h++) { + + if (io[0]) { + /* User-specified I/O address regions */ + for (i = 0; i < hw[h].num_devs; i++) + base[i] = 0; + for (i = 0; i < MAX_NUM_DEVS && io[i]; i++) { + j = (io[i] - + hw[h].io_region) / hw[h].io_delta; + if (j >= 0 && j < hw[h].num_devs + && hw[h].io_region + + j * hw[h].io_delta == io[i]) { + base[j] = io[i]; + } + } + } else { + /* Default I/O address regions */ + for (i = 0; i < hw[h].num_devs; i++) { + base[i] = + hw[h].io_region + i * hw[h].io_delta; + } + } - /* If any adapter was successfully initialized, return ok */ - if (n) return 0; + /* Check valid I/O address regions */ + for (i = 0; i < hw[h].num_devs; i++) + if (base[i]) { + if (!request_region + (base[i], hw[h].io_size, "dmascc")) + base[i] = 0; + else { + tcmd[i] = + base[i] + hw[h].tmr_offset + + TMR_CTRL; + t0[i] = + base[i] + hw[h].tmr_offset + + TMR_CNT0; + t1[i] = + base[i] + hw[h].tmr_offset + + TMR_CNT1; + } + } + + /* Start timers */ + for (i = 0; i < hw[h].num_devs; i++) + if (base[i]) { + /* Timer 0: LSB+MSB, Mode 3, TMR_0_HZ */ + outb(0x36, tcmd[i]); + outb((hw[h].tmr_hz / TMR_0_HZ) & 0xFF, + t0[i]); + outb((hw[h].tmr_hz / TMR_0_HZ) >> 8, + t0[i]); + /* Timer 1: LSB+MSB, Mode 0, HZ/10 */ + outb(0x70, tcmd[i]); + outb((TMR_0_HZ / HZ * 10) & 0xFF, t1[i]); + outb((TMR_0_HZ / HZ * 10) >> 8, t1[i]); + start[i] = jiffies; + delay[i] = 0; + counting[i] = 1; + /* Timer 2: LSB+MSB, Mode 0 */ + outb(0xb0, tcmd[i]); + } + time = jiffies; + /* Wait until counter registers are loaded */ + udelay(2000000 / TMR_0_HZ); + + /* Timing loop */ + while (jiffies - time < 13) { + for (i = 0; i < hw[h].num_devs; i++) + if (base[i] && counting[i]) { + /* Read back Timer 1: latch; read LSB; read MSB */ + outb(0x40, tcmd[i]); + t_val = + inb(t1[i]) + (inb(t1[i]) << 8); + /* Also check whether counter did wrap */ + if (t_val == 0 + || t_val > TMR_0_HZ / HZ * 10) + counting[i] = 0; + delay[i] = jiffies - start[i]; + } + } - /* If no adapter found, return error */ - printk(KERN_INFO "dmascc: no adapters found\n"); - return -EIO; + /* Evaluate measurements */ + for (i = 0; i < hw[h].num_devs; i++) + if (base[i]) { + if ((delay[i] >= 9 && delay[i] <= 11) && + /* Ok, we have found an adapter */ + (setup_adapter(base[i], h, n) == 0)) + n++; + else + release_region(base[i], + hw[h].io_size); + } + + } /* NUM_TYPES */ + + /* If any adapter was successfully initialized, return ok */ + if (n) + return 0; + + /* If no adapter found, return error */ + printk(KERN_INFO "dmascc: no adapters found\n"); + return -EIO; } module_init(dmascc_init); @@ -452,8 +473,8 @@ info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA); if (!info) { printk(KERN_ERR "dmascc: " - "could not allocate memory for %s at %#3x\n", - hw[type].name, card_base); + "could not allocate memory for %s at %#3x\n", + hw[type].name, card_base); goto out; } @@ -463,16 +484,16 @@ info->dev[0] = alloc_netdev(0, "", dev_setup); if (!info->dev[0]) { printk(KERN_ERR "dmascc: " - "could not allocate memory for %s at %#3x\n", - hw[type].name, card_base); + "could not allocate memory for %s at %#3x\n", + hw[type].name, card_base); goto out1; } info->dev[1] = alloc_netdev(0, "", dev_setup); if (!info->dev[1]) { printk(KERN_ERR "dmascc: " - "could not allocate memory for %s at %#3x\n", - hw[type].name, card_base); + "could not allocate memory for %s at %#3x\n", + hw[type].name, card_base); goto out2; } spin_lock_init(&info->register_lock); @@ -526,7 +547,8 @@ outb(0, tmr_base + TMR_CNT1); /* Wait and detect IRQ */ - time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ); + time = jiffies; + while (jiffies - time < 2 + HZ / TMR_0_HZ); irq = probe_irq_off(irqs); /* Clear pending interrupt, disable interrupts */ @@ -539,8 +561,9 @@ } if (irq <= 0) { - printk(KERN_ERR "dmascc: could not find irq of %s at %#3x (irq=%d)\n", - hw[type].name, card_base, irq); + printk(KERN_ERR + "dmascc: could not find irq of %s at %#3x (irq=%d)\n", + hw[type].name, card_base, irq); goto out3; } @@ -568,7 +591,7 @@ priv->param.dma = -1; INIT_WORK(&priv->rx_work, rx_bh, priv); dev->priv = priv; - sprintf(dev->name, "dmascc%i", 2*n+i); + sprintf(dev->name, "dmascc%i", 2 * n + i); SET_MODULE_OWNER(dev); dev->base_addr = card_base; dev->irq = irq; @@ -583,820 +606,888 @@ } if (register_netdev(info->dev[0])) { printk(KERN_ERR "dmascc: could not register %s\n", - info->dev[0]->name); + info->dev[0]->name); goto out3; } if (register_netdev(info->dev[1])) { printk(KERN_ERR "dmascc: could not register %s\n", - info->dev[1]->name); + info->dev[1]->name); goto out4; } info->next = first; first = info; - printk(KERN_INFO "dmascc: found %s (%s) at %#3x, irq %d\n", hw[type].name, - chipnames[chip], card_base, irq); + printk(KERN_INFO "dmascc: found %s (%s) at %#3x, irq %d\n", + hw[type].name, chipnames[chip], card_base, irq); return 0; -out4: + out4: unregister_netdev(info->dev[0]); -out3: + out3: if (info->priv[0].type == TYPE_TWIN) outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG); write_scc(&info->priv[0], R9, FHWRES); free_netdev(info->dev[1]); -out2: + out2: free_netdev(info->dev[0]); -out1: + out1: kfree(info); -out: + out: return -1; } /* Driver functions */ -static void write_scc(struct scc_priv *priv, int reg, int val) { - unsigned long flags; - switch (priv->type) { - case TYPE_S5: - if (reg) outb(reg, priv->scc_cmd); - outb(val, priv->scc_cmd); - return; - case TYPE_TWIN: - if (reg) outb_p(reg, priv->scc_cmd); - outb_p(val, priv->scc_cmd); - return; - default: - spin_lock_irqsave(priv->register_lock, flags); - outb_p(0, priv->card_base + PI_DREQ_MASK); - if (reg) outb_p(reg, priv->scc_cmd); - outb_p(val, priv->scc_cmd); - outb(1, priv->card_base + PI_DREQ_MASK); - spin_unlock_irqrestore(priv->register_lock, flags); - return; - } -} - - -static void write_scc_data(struct scc_priv *priv, int val, int fast) { - unsigned long flags; - switch (priv->type) { - case TYPE_S5: - outb(val, priv->scc_data); - return; - case TYPE_TWIN: - outb_p(val, priv->scc_data); - return; - default: - if (fast) outb_p(val, priv->scc_data); - else { - spin_lock_irqsave(priv->register_lock, flags); - outb_p(0, priv->card_base + PI_DREQ_MASK); - outb_p(val, priv->scc_data); - outb(1, priv->card_base + PI_DREQ_MASK); - spin_unlock_irqrestore(priv->register_lock, flags); - } - return; - } -} - - -static int read_scc(struct scc_priv *priv, int reg) { - int rc; - unsigned long flags; - switch (priv->type) { - case TYPE_S5: - if (reg) outb(reg, priv->scc_cmd); - return inb(priv->scc_cmd); - case TYPE_TWIN: - if (reg) outb_p(reg, priv->scc_cmd); - return inb_p(priv->scc_cmd); - default: - spin_lock_irqsave(priv->register_lock, flags); - outb_p(0, priv->card_base + PI_DREQ_MASK); - if (reg) outb_p(reg, priv->scc_cmd); - rc = inb_p(priv->scc_cmd); - outb(1, priv->card_base + PI_DREQ_MASK); - spin_unlock_irqrestore(priv->register_lock, flags); - return rc; - } -} - - -static int read_scc_data(struct scc_priv *priv) { - int rc; - unsigned long flags; - switch (priv->type) { - case TYPE_S5: - return inb(priv->scc_data); - case TYPE_TWIN: - return inb_p(priv->scc_data); - default: - spin_lock_irqsave(priv->register_lock, flags); - outb_p(0, priv->card_base + PI_DREQ_MASK); - rc = inb_p(priv->scc_data); - outb(1, priv->card_base + PI_DREQ_MASK); - spin_unlock_irqrestore(priv->register_lock, flags); - return rc; - } -} - - -static int scc_open(struct net_device *dev) { - struct scc_priv *priv = dev->priv; - struct scc_info *info = priv->info; - int card_base = priv->card_base; - - /* Request IRQ if not already used by other channel */ - if (!info->irq_used) { - if (request_irq(dev->irq, scc_isr, 0, "dmascc", info)) { - return -EAGAIN; - } - } - info->irq_used++; - - /* Request DMA if required */ - if (priv->param.dma >= 0) { - if (request_dma(priv->param.dma, "dmascc")) { - if (--info->irq_used == 0) free_irq(dev->irq, info); - return -EAGAIN; - } else { - unsigned long flags = claim_dma_lock(); - clear_dma_ff(priv->param.dma); - release_dma_lock(flags); - } - } - - /* Initialize local variables */ - priv->rx_ptr = 0; - priv->rx_over = 0; - priv->rx_head = priv->rx_tail = priv->rx_count = 0; - priv->state = IDLE; - priv->tx_head = priv->tx_tail = priv->tx_count = 0; - priv->tx_ptr = 0; - - /* Reset channel */ - write_scc(priv, R9, (priv->channel ? CHRB : CHRA) | MIE | NV); - /* X1 clock, SDLC mode */ - write_scc(priv, R4, SDLC | X1CLK); - /* DMA */ - write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); - /* 8 bit RX char, RX disable */ - write_scc(priv, R3, Rx8); - /* 8 bit TX char, TX disable */ - write_scc(priv, R5, Tx8); - /* SDLC address field */ - write_scc(priv, R6, 0); - /* SDLC flag */ - write_scc(priv, R7, FLAG); - switch (priv->chip) { - case Z85C30: - /* Select WR7' */ - write_scc(priv, R15, SHDLCE); - /* Auto EOM reset */ - write_scc(priv, R7, AUTOEOM); - write_scc(priv, R15, 0); - break; - case Z85230: - /* Select WR7' */ - write_scc(priv, R15, SHDLCE); - /* The following bits are set (see 2.5.2.1): - - Automatic EOM reset - - Interrupt request if RX FIFO is half full - This bit should be ignored in DMA mode (according to the - documentation), but actually isn't. The receiver doesn't work if - it is set. Thus, we have to clear it in DMA mode. - - Interrupt/DMA request if TX FIFO is completely empty - a) If set, the ESCC behaves as if it had no TX FIFO (Z85C30 - compatibility). - b) If cleared, DMA requests may follow each other very quickly, - filling up the TX FIFO. - Advantage: TX works even in case of high bus latency. - Disadvantage: Edge-triggered DMA request circuitry may miss - a request. No more data is delivered, resulting - in a TX FIFO underrun. - Both PI2 and S5SCC/DMA seem to work fine with TXFIFOE cleared. - The PackeTwin doesn't. I don't know about the PI, but let's - assume it behaves like the PI2. - */ - if (priv->param.dma >= 0) { - if (priv->type == TYPE_TWIN) write_scc(priv, R7, AUTOEOM | TXFIFOE); - else write_scc(priv, R7, AUTOEOM); - } else { - write_scc(priv, R7, AUTOEOM | RXFIFOH); - } - write_scc(priv, R15, 0); - break; - } - /* Preset CRC, NRZ(I) encoding */ - write_scc(priv, R10, CRCPS | (priv->param.nrzi ? NRZI : NRZ)); - - /* Configure baud rate generator */ - if (priv->param.brg_tc >= 0) { - /* Program BR generator */ - write_scc(priv, R12, priv->param.brg_tc & 0xFF); - write_scc(priv, R13, (priv->param.brg_tc>>8) & 0xFF); - /* BRG source = SYS CLK; enable BRG; DTR REQ function (required by - PackeTwin, not connected on the PI2); set DPLL source to BRG */ - write_scc(priv, R14, SSBR | DTRREQ | BRSRC | BRENABL); - /* Enable DPLL */ - write_scc(priv, R14, SEARCH | DTRREQ | BRSRC | BRENABL); - } else { - /* Disable BR generator */ - write_scc(priv, R14, DTRREQ | BRSRC); - } - - /* Configure clocks */ - if (priv->type == TYPE_TWIN) { - /* Disable external TX clock receiver */ - outb((info->twin_serial_cfg &= - ~(priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)), - card_base + TWIN_SERIAL_CFG); - } - write_scc(priv, R11, priv->param.clocks); - if ((priv->type == TYPE_TWIN) && !(priv->param.clocks & TRxCOI)) { - /* Enable external TX clock receiver */ - outb((info->twin_serial_cfg |= - (priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)), - card_base + TWIN_SERIAL_CFG); - } - - /* Configure PackeTwin */ - if (priv->type == TYPE_TWIN) { - /* Assert DTR, enable interrupts */ - outb((info->twin_serial_cfg |= TWIN_EI | - (priv->channel ? TWIN_DTRB_ON : TWIN_DTRA_ON)), - card_base + TWIN_SERIAL_CFG); - } - - /* Read current status */ - priv->rr0 = read_scc(priv, R0); - /* Enable DCD interrupt */ - write_scc(priv, R15, DCDIE); - - netif_start_queue(dev); - - return 0; -} - - -static int scc_close(struct net_device *dev) { - struct scc_priv *priv = dev->priv; - struct scc_info *info = priv->info; - int card_base = priv->card_base; - - netif_stop_queue(dev); - - if (priv->type == TYPE_TWIN) { - /* Drop DTR */ - outb((info->twin_serial_cfg &= - (priv->channel ? ~TWIN_DTRB_ON : ~TWIN_DTRA_ON)), - card_base + TWIN_SERIAL_CFG); - } - - /* Reset channel, free DMA and IRQ */ - write_scc(priv, R9, (priv->channel ? CHRB : CHRA) | MIE | NV); - if (priv->param.dma >= 0) { - if (priv->type == TYPE_TWIN) outb(0, card_base + TWIN_DMA_CFG); - free_dma(priv->param.dma); - } - if (--info->irq_used == 0) free_irq(dev->irq, info); - - return 0; -} - - -static int scc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct scc_priv *priv = dev->priv; - - switch (cmd) { - case SIOCGSCCPARAM: - if (copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param))) - return -EFAULT; - return 0; - case SIOCSSCCPARAM: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (netif_running(dev)) return -EAGAIN; - if (copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param))) - return -EFAULT; - return 0; - default: - return -EINVAL; - } -} - - -static int scc_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct scc_priv *priv = dev->priv; - unsigned long flags; - int i; - - /* Temporarily stop the scheduler feeding us packets */ - netif_stop_queue(dev); - - /* Transfer data to DMA buffer */ - i = priv->tx_head; - memcpy(priv->tx_buf[i], skb->data+1, skb->len-1); - priv->tx_len[i] = skb->len-1; - - /* Clear interrupts while we touch our circular buffers */ - - spin_lock_irqsave(&priv->ring_lock, flags); - /* Move the ring buffer's head */ - priv->tx_head = (i + 1) % NUM_TX_BUF; - priv->tx_count++; - - /* If we just filled up the last buffer, leave queue stopped. - The higher layers must wait until we have a DMA buffer - to accept the data. */ - if (priv->tx_count < NUM_TX_BUF) netif_wake_queue(dev); - - /* Set new TX state */ - if (priv->state == IDLE) { - /* Assert RTS, start timer */ - priv->state = TX_HEAD; - priv->tx_start = jiffies; - write_scc(priv, R5, TxCRC_ENAB | RTS | TxENAB | Tx8); - write_scc(priv, R15, 0); - start_timer(priv, priv->param.txdelay, 0); - } - - /* Turn interrupts back on and free buffer */ - spin_unlock_irqrestore(&priv->ring_lock, flags); - dev_kfree_skb(skb); - - return 0; -} - - -static struct net_device_stats *scc_get_stats(struct net_device *dev) { - struct scc_priv *priv = dev->priv; - - return &priv->stats; -} - - -static int scc_set_mac_address(struct net_device *dev, void *sa) { - memcpy(dev->dev_addr, ((struct sockaddr *)sa)->sa_data, dev->addr_len); - return 0; -} - - -static inline void tx_on(struct scc_priv *priv) { - int i, n; - unsigned long flags; - - if (priv->param.dma >= 0) { - n = (priv->chip == Z85230) ? 3 : 1; - /* Program DMA controller */ - flags = claim_dma_lock(); - set_dma_mode(priv->param.dma, DMA_MODE_WRITE); - set_dma_addr(priv->param.dma, (int) priv->tx_buf[priv->tx_tail]+n); - set_dma_count(priv->param.dma, priv->tx_len[priv->tx_tail]-n); - release_dma_lock(flags); - /* Enable TX underrun interrupt */ - write_scc(priv, R15, TxUIE); - /* Configure DREQ */ - if (priv->type == TYPE_TWIN) - outb((priv->param.dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3, - priv->card_base + TWIN_DMA_CFG); - else - write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB); - /* Write first byte(s) */ - spin_lock_irqsave(priv->register_lock, flags); - for (i = 0; i < n; i++) - write_scc_data(priv, priv->tx_buf[priv->tx_tail][i], 1); - enable_dma(priv->param.dma); - spin_unlock_irqrestore(priv->register_lock, flags); - } else { - write_scc(priv, R15, TxUIE); - write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB); - tx_isr(priv); - } - /* Reset EOM latch if we do not have the AUTOEOM feature */ - if (priv->chip == Z8530) write_scc(priv, R0, RES_EOM_L); -} - - -static inline void rx_on(struct scc_priv *priv) { - unsigned long flags; - - /* Clear RX FIFO */ - while (read_scc(priv, R0) & Rx_CH_AV) read_scc_data(priv); - priv->rx_over = 0; - if (priv->param.dma >= 0) { - /* Program DMA controller */ - flags = claim_dma_lock(); - set_dma_mode(priv->param.dma, DMA_MODE_READ); - set_dma_addr(priv->param.dma, (int) priv->rx_buf[priv->rx_head]); - set_dma_count(priv->param.dma, BUF_SIZE); - release_dma_lock(flags); - enable_dma(priv->param.dma); - /* Configure PackeTwin DMA */ - if (priv->type == TYPE_TWIN) { - outb((priv->param.dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3, - priv->card_base + TWIN_DMA_CFG); - } - /* Sp. cond. intr. only, ext int enable, RX DMA enable */ - write_scc(priv, R1, EXT_INT_ENAB | INT_ERR_Rx | - WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB); - } else { - /* Reset current frame */ - priv->rx_ptr = 0; - /* Intr. on all Rx characters and Sp. cond., ext int enable */ - write_scc(priv, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT | - WT_FN_RDYFN); - } - write_scc(priv, R0, ERR_RES); - write_scc(priv, R3, RxENABLE | Rx8 | RxCRC_ENAB); -} - - -static inline void rx_off(struct scc_priv *priv) { - /* Disable receiver */ - write_scc(priv, R3, Rx8); - /* Disable DREQ / RX interrupt */ - if (priv->param.dma >= 0 && priv->type == TYPE_TWIN) - outb(0, priv->card_base + TWIN_DMA_CFG); - else - write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); - /* Disable DMA */ - if (priv->param.dma >= 0) disable_dma(priv->param.dma); -} - - -static void start_timer(struct scc_priv *priv, int t, int r15) { - unsigned long flags; - - outb(priv->tmr_mode, priv->tmr_ctrl); - if (t == 0) { - tm_isr(priv); - } else if (t > 0) { - save_flags(flags); - cli(); - outb(t & 0xFF, priv->tmr_cnt); - outb((t >> 8) & 0xFF, priv->tmr_cnt); - if (priv->type != TYPE_TWIN) { - write_scc(priv, R15, r15 | CTSIE); - priv->rr0 |= CTS; - } - restore_flags(flags); - } -} - - -static inline unsigned char random(void) { - /* See "Numerical Recipes in C", second edition, p. 284 */ - rand = rand * 1664525L + 1013904223L; - return (unsigned char) (rand >> 24); -} - -static inline void z8530_isr(struct scc_info *info) { - int is, i = 100; - - while ((is = read_scc(&info->priv[0], R3)) && i--) { - if (is & CHARxIP) { - rx_isr(&info->priv[0]); - } else if (is & CHATxIP) { - tx_isr(&info->priv[0]); - } else if (is & CHAEXT) { - es_isr(&info->priv[0]); - } else if (is & CHBRxIP) { - rx_isr(&info->priv[1]); - } else if (is & CHBTxIP) { - tx_isr(&info->priv[1]); - } else { - es_isr(&info->priv[1]); - } - write_scc(&info->priv[0], R0, RES_H_IUS); - i++; - } - if (i < 0) { - printk(KERN_ERR "dmascc: stuck in ISR with RR3=0x%02x.\n", is); - } - /* Ok, no interrupts pending from this 8530. The INT line should - be inactive now. */ -} - - -static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs * regs) { - struct scc_info *info = dev_id; - - spin_lock(info->priv[0].register_lock); - /* At this point interrupts are enabled, and the interrupt under service - is already acknowledged, but masked off. - - Interrupt processing: We loop until we know that the IRQ line is - low. If another positive edge occurs afterwards during the ISR, - another interrupt will be triggered by the interrupt controller - as soon as the IRQ level is enabled again (see asm/irq.h). - - Bottom-half handlers will be processed after scc_isr(). This is - important, since we only have small ringbuffers and want new data - to be fetched/delivered immediately. */ - - if (info->priv[0].type == TYPE_TWIN) { - int is, card_base = info->priv[0].card_base; - while ((is = ~inb(card_base + TWIN_INT_REG)) & - TWIN_INT_MSK) { - if (is & TWIN_SCC_MSK) { - z8530_isr(info); - } else if (is & TWIN_TMR1_MSK) { - inb(card_base + TWIN_CLR_TMR1); - tm_isr(&info->priv[0]); - } else { - inb(card_base + TWIN_CLR_TMR2); - tm_isr(&info->priv[1]); - } - } - } else z8530_isr(info); - spin_unlock(info->priv[0].register_lock); - return IRQ_HANDLED; -} - - -static void rx_isr(struct scc_priv *priv) { - if (priv->param.dma >= 0) { - /* Check special condition and perform error reset. See 2.4.7.5. */ - special_condition(priv, read_scc(priv, R1)); - write_scc(priv, R0, ERR_RES); - } else { - /* Check special condition for each character. Error reset not necessary. - Same algorithm for SCC and ESCC. See 2.4.7.1 and 2.4.7.4. */ - int rc; - while (read_scc(priv, R0) & Rx_CH_AV) { - rc = read_scc(priv, R1); - if (priv->rx_ptr < BUF_SIZE) - priv->rx_buf[priv->rx_head][priv->rx_ptr++] = - read_scc_data(priv); - else { - priv->rx_over = 2; - read_scc_data(priv); - } - special_condition(priv, rc); - } - } -} - - -static void special_condition(struct scc_priv *priv, int rc) { - int cb; - unsigned long flags; - - /* See Figure 2-15. Only overrun and EOF need to be checked. */ - - if (rc & Rx_OVR) { - /* Receiver overrun */ - priv->rx_over = 1; - if (priv->param.dma < 0) write_scc(priv, R0, ERR_RES); - } else if (rc & END_FR) { - /* End of frame. Get byte count */ - if (priv->param.dma >= 0) { - flags = claim_dma_lock(); - cb = BUF_SIZE - get_dma_residue(priv->param.dma) - 2; - release_dma_lock(flags); - } else { - cb = priv->rx_ptr - 2; - } - if (priv->rx_over) { - /* We had an overrun */ - priv->stats.rx_errors++; - if (priv->rx_over == 2) priv->stats.rx_length_errors++; - else priv->stats.rx_fifo_errors++; - priv->rx_over = 0; - } else if (rc & CRC_ERR) { - /* Count invalid CRC only if packet length >= minimum */ - if (cb >= 15) { - priv->stats.rx_errors++; - priv->stats.rx_crc_errors++; - } - } else { - if (cb >= 15) { - if (priv->rx_count < NUM_RX_BUF - 1) { - /* Put good frame in FIFO */ - priv->rx_len[priv->rx_head] = cb; - priv->rx_head = (priv->rx_head + 1) % NUM_RX_BUF; - priv->rx_count++; - schedule_work(&priv->rx_work); +static void write_scc(struct scc_priv *priv, int reg, int val) +{ + unsigned long flags; + switch (priv->type) { + case TYPE_S5: + if (reg) + outb(reg, priv->scc_cmd); + outb(val, priv->scc_cmd); + return; + case TYPE_TWIN: + if (reg) + outb_p(reg, priv->scc_cmd); + outb_p(val, priv->scc_cmd); + return; + default: + spin_lock_irqsave(priv->register_lock, flags); + outb_p(0, priv->card_base + PI_DREQ_MASK); + if (reg) + outb_p(reg, priv->scc_cmd); + outb_p(val, priv->scc_cmd); + outb(1, priv->card_base + PI_DREQ_MASK); + spin_unlock_irqrestore(priv->register_lock, flags); + return; + } +} + + +static void write_scc_data(struct scc_priv *priv, int val, int fast) +{ + unsigned long flags; + switch (priv->type) { + case TYPE_S5: + outb(val, priv->scc_data); + return; + case TYPE_TWIN: + outb_p(val, priv->scc_data); + return; + default: + if (fast) + outb_p(val, priv->scc_data); + else { + spin_lock_irqsave(priv->register_lock, flags); + outb_p(0, priv->card_base + PI_DREQ_MASK); + outb_p(val, priv->scc_data); + outb(1, priv->card_base + PI_DREQ_MASK); + spin_unlock_irqrestore(priv->register_lock, flags); + } + return; + } +} + + +static int read_scc(struct scc_priv *priv, int reg) +{ + int rc; + unsigned long flags; + switch (priv->type) { + case TYPE_S5: + if (reg) + outb(reg, priv->scc_cmd); + return inb(priv->scc_cmd); + case TYPE_TWIN: + if (reg) + outb_p(reg, priv->scc_cmd); + return inb_p(priv->scc_cmd); + default: + spin_lock_irqsave(priv->register_lock, flags); + outb_p(0, priv->card_base + PI_DREQ_MASK); + if (reg) + outb_p(reg, priv->scc_cmd); + rc = inb_p(priv->scc_cmd); + outb(1, priv->card_base + PI_DREQ_MASK); + spin_unlock_irqrestore(priv->register_lock, flags); + return rc; + } +} + + +static int read_scc_data(struct scc_priv *priv) +{ + int rc; + unsigned long flags; + switch (priv->type) { + case TYPE_S5: + return inb(priv->scc_data); + case TYPE_TWIN: + return inb_p(priv->scc_data); + default: + spin_lock_irqsave(priv->register_lock, flags); + outb_p(0, priv->card_base + PI_DREQ_MASK); + rc = inb_p(priv->scc_data); + outb(1, priv->card_base + PI_DREQ_MASK); + spin_unlock_irqrestore(priv->register_lock, flags); + return rc; + } +} + + +static int scc_open(struct net_device *dev) +{ + struct scc_priv *priv = dev->priv; + struct scc_info *info = priv->info; + int card_base = priv->card_base; + + /* Request IRQ if not already used by other channel */ + if (!info->irq_used) { + if (request_irq(dev->irq, scc_isr, 0, "dmascc", info)) { + return -EAGAIN; + } + } + info->irq_used++; + + /* Request DMA if required */ + if (priv->param.dma >= 0) { + if (request_dma(priv->param.dma, "dmascc")) { + if (--info->irq_used == 0) + free_irq(dev->irq, info); + return -EAGAIN; + } else { + unsigned long flags = claim_dma_lock(); + clear_dma_ff(priv->param.dma); + release_dma_lock(flags); + } + } + + /* Initialize local variables */ + priv->rx_ptr = 0; + priv->rx_over = 0; + priv->rx_head = priv->rx_tail = priv->rx_count = 0; + priv->state = IDLE; + priv->tx_head = priv->tx_tail = priv->tx_count = 0; + priv->tx_ptr = 0; + + /* Reset channel */ + write_scc(priv, R9, (priv->channel ? CHRB : CHRA) | MIE | NV); + /* X1 clock, SDLC mode */ + write_scc(priv, R4, SDLC | X1CLK); + /* DMA */ + write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); + /* 8 bit RX char, RX disable */ + write_scc(priv, R3, Rx8); + /* 8 bit TX char, TX disable */ + write_scc(priv, R5, Tx8); + /* SDLC address field */ + write_scc(priv, R6, 0); + /* SDLC flag */ + write_scc(priv, R7, FLAG); + switch (priv->chip) { + case Z85C30: + /* Select WR7' */ + write_scc(priv, R15, SHDLCE); + /* Auto EOM reset */ + write_scc(priv, R7, AUTOEOM); + write_scc(priv, R15, 0); + break; + case Z85230: + /* Select WR7' */ + write_scc(priv, R15, SHDLCE); + /* The following bits are set (see 2.5.2.1): + - Automatic EOM reset + - Interrupt request if RX FIFO is half full + This bit should be ignored in DMA mode (according to the + documentation), but actually isn't. The receiver doesn't work if + it is set. Thus, we have to clear it in DMA mode. + - Interrupt/DMA request if TX FIFO is completely empty + a) If set, the ESCC behaves as if it had no TX FIFO (Z85C30 + compatibility). + b) If cleared, DMA requests may follow each other very quickly, + filling up the TX FIFO. + Advantage: TX works even in case of high bus latency. + Disadvantage: Edge-triggered DMA request circuitry may miss + a request. No more data is delivered, resulting + in a TX FIFO underrun. + Both PI2 and S5SCC/DMA seem to work fine with TXFIFOE cleared. + The PackeTwin doesn't. I don't know about the PI, but let's + assume it behaves like the PI2. + */ + if (priv->param.dma >= 0) { + if (priv->type == TYPE_TWIN) + write_scc(priv, R7, AUTOEOM | TXFIFOE); + else + write_scc(priv, R7, AUTOEOM); + } else { + write_scc(priv, R7, AUTOEOM | RXFIFOH); + } + write_scc(priv, R15, 0); + break; + } + /* Preset CRC, NRZ(I) encoding */ + write_scc(priv, R10, CRCPS | (priv->param.nrzi ? NRZI : NRZ)); + + /* Configure baud rate generator */ + if (priv->param.brg_tc >= 0) { + /* Program BR generator */ + write_scc(priv, R12, priv->param.brg_tc & 0xFF); + write_scc(priv, R13, (priv->param.brg_tc >> 8) & 0xFF); + /* BRG source = SYS CLK; enable BRG; DTR REQ function (required by + PackeTwin, not connected on the PI2); set DPLL source to BRG */ + write_scc(priv, R14, SSBR | DTRREQ | BRSRC | BRENABL); + /* Enable DPLL */ + write_scc(priv, R14, SEARCH | DTRREQ | BRSRC | BRENABL); } else { - priv->stats.rx_errors++; - priv->stats.rx_over_errors++; + /* Disable BR generator */ + write_scc(priv, R14, DTRREQ | BRSRC); + } + + /* Configure clocks */ + if (priv->type == TYPE_TWIN) { + /* Disable external TX clock receiver */ + outb((info->twin_serial_cfg &= + ~(priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)), + card_base + TWIN_SERIAL_CFG); + } + write_scc(priv, R11, priv->param.clocks); + if ((priv->type == TYPE_TWIN) && !(priv->param.clocks & TRxCOI)) { + /* Enable external TX clock receiver */ + outb((info->twin_serial_cfg |= + (priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)), + card_base + TWIN_SERIAL_CFG); + } + + /* Configure PackeTwin */ + if (priv->type == TYPE_TWIN) { + /* Assert DTR, enable interrupts */ + outb((info->twin_serial_cfg |= TWIN_EI | + (priv->channel ? TWIN_DTRB_ON : TWIN_DTRA_ON)), + card_base + TWIN_SERIAL_CFG); + } + + /* Read current status */ + priv->rr0 = read_scc(priv, R0); + /* Enable DCD interrupt */ + write_scc(priv, R15, DCDIE); + + netif_start_queue(dev); + + return 0; +} + + +static int scc_close(struct net_device *dev) +{ + struct scc_priv *priv = dev->priv; + struct scc_info *info = priv->info; + int card_base = priv->card_base; + + netif_stop_queue(dev); + + if (priv->type == TYPE_TWIN) { + /* Drop DTR */ + outb((info->twin_serial_cfg &= + (priv->channel ? ~TWIN_DTRB_ON : ~TWIN_DTRA_ON)), + card_base + TWIN_SERIAL_CFG); + } + + /* Reset channel, free DMA and IRQ */ + write_scc(priv, R9, (priv->channel ? CHRB : CHRA) | MIE | NV); + if (priv->param.dma >= 0) { + if (priv->type == TYPE_TWIN) + outb(0, card_base + TWIN_DMA_CFG); + free_dma(priv->param.dma); + } + if (--info->irq_used == 0) + free_irq(dev->irq, info); + + return 0; +} + + +static int scc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct scc_priv *priv = dev->priv; + + switch (cmd) { + case SIOCGSCCPARAM: + if (copy_to_user + (ifr->ifr_data, &priv->param, + sizeof(struct scc_param))) + return -EFAULT; + return 0; + case SIOCSSCCPARAM: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (netif_running(dev)) + return -EAGAIN; + if (copy_from_user + (&priv->param, ifr->ifr_data, + sizeof(struct scc_param))) + return -EFAULT; + return 0; + default: + return -EINVAL; + } +} + + +static int scc_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct scc_priv *priv = dev->priv; + unsigned long flags; + int i; + + /* Temporarily stop the scheduler feeding us packets */ + netif_stop_queue(dev); + + /* Transfer data to DMA buffer */ + i = priv->tx_head; + memcpy(priv->tx_buf[i], skb->data + 1, skb->len - 1); + priv->tx_len[i] = skb->len - 1; + + /* Clear interrupts while we touch our circular buffers */ + + spin_lock_irqsave(&priv->ring_lock, flags); + /* Move the ring buffer's head */ + priv->tx_head = (i + 1) % NUM_TX_BUF; + priv->tx_count++; + + /* If we just filled up the last buffer, leave queue stopped. + The higher layers must wait until we have a DMA buffer + to accept the data. */ + if (priv->tx_count < NUM_TX_BUF) + netif_wake_queue(dev); + + /* Set new TX state */ + if (priv->state == IDLE) { + /* Assert RTS, start timer */ + priv->state = TX_HEAD; + priv->tx_start = jiffies; + write_scc(priv, R5, TxCRC_ENAB | RTS | TxENAB | Tx8); + write_scc(priv, R15, 0); + start_timer(priv, priv->param.txdelay, 0); + } + + /* Turn interrupts back on and free buffer */ + spin_unlock_irqrestore(&priv->ring_lock, flags); + dev_kfree_skb(skb); + + return 0; +} + + +static struct net_device_stats *scc_get_stats(struct net_device *dev) +{ + struct scc_priv *priv = dev->priv; + + return &priv->stats; +} + + +static int scc_set_mac_address(struct net_device *dev, void *sa) +{ + memcpy(dev->dev_addr, ((struct sockaddr *) sa)->sa_data, + dev->addr_len); + return 0; +} + + +static inline void tx_on(struct scc_priv *priv) +{ + int i, n; + unsigned long flags; + + if (priv->param.dma >= 0) { + n = (priv->chip == Z85230) ? 3 : 1; + /* Program DMA controller */ + flags = claim_dma_lock(); + set_dma_mode(priv->param.dma, DMA_MODE_WRITE); + set_dma_addr(priv->param.dma, + (int) priv->tx_buf[priv->tx_tail] + n); + set_dma_count(priv->param.dma, + priv->tx_len[priv->tx_tail] - n); + release_dma_lock(flags); + /* Enable TX underrun interrupt */ + write_scc(priv, R15, TxUIE); + /* Configure DREQ */ + if (priv->type == TYPE_TWIN) + outb((priv->param.dma == + 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3, + priv->card_base + TWIN_DMA_CFG); + else + write_scc(priv, R1, + EXT_INT_ENAB | WT_FN_RDYFN | + WT_RDY_ENAB); + /* Write first byte(s) */ + spin_lock_irqsave(priv->register_lock, flags); + for (i = 0; i < n; i++) + write_scc_data(priv, + priv->tx_buf[priv->tx_tail][i], 1); + enable_dma(priv->param.dma); + spin_unlock_irqrestore(priv->register_lock, flags); + } else { + write_scc(priv, R15, TxUIE); + write_scc(priv, R1, + EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB); + tx_isr(priv); + } + /* Reset EOM latch if we do not have the AUTOEOM feature */ + if (priv->chip == Z8530) + write_scc(priv, R0, RES_EOM_L); +} + + +static inline void rx_on(struct scc_priv *priv) +{ + unsigned long flags; + + /* Clear RX FIFO */ + while (read_scc(priv, R0) & Rx_CH_AV) + read_scc_data(priv); + priv->rx_over = 0; + if (priv->param.dma >= 0) { + /* Program DMA controller */ + flags = claim_dma_lock(); + set_dma_mode(priv->param.dma, DMA_MODE_READ); + set_dma_addr(priv->param.dma, + (int) priv->rx_buf[priv->rx_head]); + set_dma_count(priv->param.dma, BUF_SIZE); + release_dma_lock(flags); + enable_dma(priv->param.dma); + /* Configure PackeTwin DMA */ + if (priv->type == TYPE_TWIN) { + outb((priv->param.dma == + 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3, + priv->card_base + TWIN_DMA_CFG); + } + /* Sp. cond. intr. only, ext int enable, RX DMA enable */ + write_scc(priv, R1, EXT_INT_ENAB | INT_ERR_Rx | + WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB); + } else { + /* Reset current frame */ + priv->rx_ptr = 0; + /* Intr. on all Rx characters and Sp. cond., ext int enable */ + write_scc(priv, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT | + WT_FN_RDYFN); + } + write_scc(priv, R0, ERR_RES); + write_scc(priv, R3, RxENABLE | Rx8 | RxCRC_ENAB); +} + + +static inline void rx_off(struct scc_priv *priv) +{ + /* Disable receiver */ + write_scc(priv, R3, Rx8); + /* Disable DREQ / RX interrupt */ + if (priv->param.dma >= 0 && priv->type == TYPE_TWIN) + outb(0, priv->card_base + TWIN_DMA_CFG); + else + write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); + /* Disable DMA */ + if (priv->param.dma >= 0) + disable_dma(priv->param.dma); +} + + +static void start_timer(struct scc_priv *priv, int t, int r15) +{ + unsigned long flags; + + outb(priv->tmr_mode, priv->tmr_ctrl); + if (t == 0) { + tm_isr(priv); + } else if (t > 0) { + save_flags(flags); + cli(); + outb(t & 0xFF, priv->tmr_cnt); + outb((t >> 8) & 0xFF, priv->tmr_cnt); + if (priv->type != TYPE_TWIN) { + write_scc(priv, R15, r15 | CTSIE); + priv->rr0 |= CTS; + } + restore_flags(flags); + } +} + + +static inline unsigned char random(void) +{ + /* See "Numerical Recipes in C", second edition, p. 284 */ + rand = rand * 1664525L + 1013904223L; + return (unsigned char) (rand >> 24); +} + +static inline void z8530_isr(struct scc_info *info) +{ + int is, i = 100; + + while ((is = read_scc(&info->priv[0], R3)) && i--) { + if (is & CHARxIP) { + rx_isr(&info->priv[0]); + } else if (is & CHATxIP) { + tx_isr(&info->priv[0]); + } else if (is & CHAEXT) { + es_isr(&info->priv[0]); + } else if (is & CHBRxIP) { + rx_isr(&info->priv[1]); + } else if (is & CHBTxIP) { + tx_isr(&info->priv[1]); + } else { + es_isr(&info->priv[1]); + } + write_scc(&info->priv[0], R0, RES_H_IUS); + i++; + } + if (i < 0) { + printk(KERN_ERR "dmascc: stuck in ISR with RR3=0x%02x.\n", + is); + } + /* Ok, no interrupts pending from this 8530. The INT line should + be inactive now. */ +} + + +static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct scc_info *info = dev_id; + + spin_lock(info->priv[0].register_lock); + /* At this point interrupts are enabled, and the interrupt under service + is already acknowledged, but masked off. + + Interrupt processing: We loop until we know that the IRQ line is + low. If another positive edge occurs afterwards during the ISR, + another interrupt will be triggered by the interrupt controller + as soon as the IRQ level is enabled again (see asm/irq.h). + + Bottom-half handlers will be processed after scc_isr(). This is + important, since we only have small ringbuffers and want new data + to be fetched/delivered immediately. */ + + if (info->priv[0].type == TYPE_TWIN) { + int is, card_base = info->priv[0].card_base; + while ((is = ~inb(card_base + TWIN_INT_REG)) & + TWIN_INT_MSK) { + if (is & TWIN_SCC_MSK) { + z8530_isr(info); + } else if (is & TWIN_TMR1_MSK) { + inb(card_base + TWIN_CLR_TMR1); + tm_isr(&info->priv[0]); + } else { + inb(card_base + TWIN_CLR_TMR2); + tm_isr(&info->priv[1]); + } + } + } else + z8530_isr(info); + spin_unlock(info->priv[0].register_lock); + return IRQ_HANDLED; +} + + +static void rx_isr(struct scc_priv *priv) +{ + if (priv->param.dma >= 0) { + /* Check special condition and perform error reset. See 2.4.7.5. */ + special_condition(priv, read_scc(priv, R1)); + write_scc(priv, R0, ERR_RES); + } else { + /* Check special condition for each character. Error reset not necessary. + Same algorithm for SCC and ESCC. See 2.4.7.1 and 2.4.7.4. */ + int rc; + while (read_scc(priv, R0) & Rx_CH_AV) { + rc = read_scc(priv, R1); + if (priv->rx_ptr < BUF_SIZE) + priv->rx_buf[priv->rx_head][priv-> + rx_ptr++] = + read_scc_data(priv); + else { + priv->rx_over = 2; + read_scc_data(priv); + } + special_condition(priv, rc); + } + } +} + + +static void special_condition(struct scc_priv *priv, int rc) +{ + int cb; + unsigned long flags; + + /* See Figure 2-15. Only overrun and EOF need to be checked. */ + + if (rc & Rx_OVR) { + /* Receiver overrun */ + priv->rx_over = 1; + if (priv->param.dma < 0) + write_scc(priv, R0, ERR_RES); + } else if (rc & END_FR) { + /* End of frame. Get byte count */ + if (priv->param.dma >= 0) { + flags = claim_dma_lock(); + cb = BUF_SIZE - get_dma_residue(priv->param.dma) - + 2; + release_dma_lock(flags); + } else { + cb = priv->rx_ptr - 2; + } + if (priv->rx_over) { + /* We had an overrun */ + priv->stats.rx_errors++; + if (priv->rx_over == 2) + priv->stats.rx_length_errors++; + else + priv->stats.rx_fifo_errors++; + priv->rx_over = 0; + } else if (rc & CRC_ERR) { + /* Count invalid CRC only if packet length >= minimum */ + if (cb >= 15) { + priv->stats.rx_errors++; + priv->stats.rx_crc_errors++; + } + } else { + if (cb >= 15) { + if (priv->rx_count < NUM_RX_BUF - 1) { + /* Put good frame in FIFO */ + priv->rx_len[priv->rx_head] = cb; + priv->rx_head = + (priv->rx_head + + 1) % NUM_RX_BUF; + priv->rx_count++; + schedule_work(&priv->rx_work); + } else { + priv->stats.rx_errors++; + priv->stats.rx_over_errors++; + } + } + } + /* Get ready for new frame */ + if (priv->param.dma >= 0) { + flags = claim_dma_lock(); + set_dma_addr(priv->param.dma, + (int) priv->rx_buf[priv->rx_head]); + set_dma_count(priv->param.dma, BUF_SIZE); + release_dma_lock(flags); + } else { + priv->rx_ptr = 0; + } + } +} + + +static void rx_bh(void *arg) +{ + struct scc_priv *priv = arg; + int i = priv->rx_tail; + int cb; + unsigned long flags; + struct sk_buff *skb; + unsigned char *data; + + spin_lock_irqsave(&priv->ring_lock, flags); + while (priv->rx_count) { + spin_unlock_irqrestore(&priv->ring_lock, flags); + cb = priv->rx_len[i]; + /* Allocate buffer */ + skb = dev_alloc_skb(cb + 1); + if (skb == NULL) { + /* Drop packet */ + priv->stats.rx_dropped++; + } else { + /* Fill buffer */ + data = skb_put(skb, cb + 1); + data[0] = 0; + memcpy(&data[1], priv->rx_buf[i], cb); + skb->dev = priv->dev; + skb->protocol = ntohs(ETH_P_AX25); + skb->mac.raw = skb->data; + netif_rx(skb); + priv->dev->last_rx = jiffies; + priv->stats.rx_packets++; + priv->stats.rx_bytes += cb; + } + spin_lock_irqsave(&priv->ring_lock, flags); + /* Move tail */ + priv->rx_tail = i = (i + 1) % NUM_RX_BUF; + priv->rx_count--; + } + spin_unlock_irqrestore(&priv->ring_lock, flags); +} + + +static void tx_isr(struct scc_priv *priv) +{ + int i = priv->tx_tail, p = priv->tx_ptr; + + /* Suspend TX interrupts if we don't want to send anything. + See Figure 2-22. */ + if (p == priv->tx_len[i]) { + write_scc(priv, R0, RES_Tx_P); + return; + } + + /* Write characters */ + while ((read_scc(priv, R0) & Tx_BUF_EMP) && p < priv->tx_len[i]) { + write_scc_data(priv, priv->tx_buf[i][p++], 0); + } + + /* Reset EOM latch of Z8530 */ + if (!priv->tx_ptr && p && priv->chip == Z8530) + write_scc(priv, R0, RES_EOM_L); + + priv->tx_ptr = p; +} + + +static void es_isr(struct scc_priv *priv) +{ + int i, rr0, drr0, res; + unsigned long flags; + + /* Read status, reset interrupt bit (open latches) */ + rr0 = read_scc(priv, R0); + write_scc(priv, R0, RES_EXT_INT); + drr0 = priv->rr0 ^ rr0; + priv->rr0 = rr0; + + /* Transmit underrun (2.4.9.6). We can't check the TxEOM flag, since + it might have already been cleared again by AUTOEOM. */ + if (priv->state == TX_DATA) { + /* Get remaining bytes */ + i = priv->tx_tail; + if (priv->param.dma >= 0) { + disable_dma(priv->param.dma); + flags = claim_dma_lock(); + res = get_dma_residue(priv->param.dma); + release_dma_lock(flags); + } else { + res = priv->tx_len[i] - priv->tx_ptr; + priv->tx_ptr = 0; + } + /* Disable DREQ / TX interrupt */ + if (priv->param.dma >= 0 && priv->type == TYPE_TWIN) + outb(0, priv->card_base + TWIN_DMA_CFG); + else + write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); + if (res) { + /* Update packet statistics */ + priv->stats.tx_errors++; + priv->stats.tx_fifo_errors++; + /* Other underrun interrupts may already be waiting */ + write_scc(priv, R0, RES_EXT_INT); + write_scc(priv, R0, RES_EXT_INT); + } else { + /* Update packet statistics */ + priv->stats.tx_packets++; + priv->stats.tx_bytes += priv->tx_len[i]; + /* Remove frame from FIFO */ + priv->tx_tail = (i + 1) % NUM_TX_BUF; + priv->tx_count--; + /* Inform upper layers */ + netif_wake_queue(priv->dev); + } + /* Switch state */ + write_scc(priv, R15, 0); + if (priv->tx_count && + (jiffies - priv->tx_start) < priv->param.txtimeout) { + priv->state = TX_PAUSE; + start_timer(priv, priv->param.txpause, 0); + } else { + priv->state = TX_TAIL; + start_timer(priv, priv->param.txtail, 0); + } + } + + /* DCD transition */ + if (drr0 & DCD) { + if (rr0 & DCD) { + switch (priv->state) { + case IDLE: + case WAIT: + priv->state = DCD_ON; + write_scc(priv, R15, 0); + start_timer(priv, priv->param.dcdon, 0); + } + } else { + switch (priv->state) { + case RX_ON: + rx_off(priv); + priv->state = DCD_OFF; + write_scc(priv, R15, 0); + start_timer(priv, priv->param.dcdoff, 0); + } + } + } + + /* CTS transition */ + if ((drr0 & CTS) && (~rr0 & CTS) && priv->type != TYPE_TWIN) + tm_isr(priv); + +} + + +static void tm_isr(struct scc_priv *priv) +{ + switch (priv->state) { + case TX_HEAD: + case TX_PAUSE: + tx_on(priv); + priv->state = TX_DATA; + break; + case TX_TAIL: + write_scc(priv, R5, TxCRC_ENAB | Tx8); + priv->state = RTS_OFF; + if (priv->type != TYPE_TWIN) + write_scc(priv, R15, 0); + start_timer(priv, priv->param.rtsoff, 0); + break; + case RTS_OFF: + write_scc(priv, R15, DCDIE); + priv->rr0 = read_scc(priv, R0); + if (priv->rr0 & DCD) { + priv->stats.collisions++; + rx_on(priv); + priv->state = RX_ON; + } else { + priv->state = WAIT; + start_timer(priv, priv->param.waittime, DCDIE); + } + break; + case WAIT: + if (priv->tx_count) { + priv->state = TX_HEAD; + priv->tx_start = jiffies; + write_scc(priv, R5, + TxCRC_ENAB | RTS | TxENAB | Tx8); + write_scc(priv, R15, 0); + start_timer(priv, priv->param.txdelay, 0); + } else { + priv->state = IDLE; + if (priv->type != TYPE_TWIN) + write_scc(priv, R15, DCDIE); + } + break; + case DCD_ON: + case DCD_OFF: + write_scc(priv, R15, DCDIE); + priv->rr0 = read_scc(priv, R0); + if (priv->rr0 & DCD) { + rx_on(priv); + priv->state = RX_ON; + } else { + priv->state = WAIT; + start_timer(priv, + random() / priv->param.persist * + priv->param.slottime, DCDIE); + } + break; } - } - } - /* Get ready for new frame */ - if (priv->param.dma >= 0) { - flags = claim_dma_lock(); - set_dma_addr(priv->param.dma, (int) priv->rx_buf[priv->rx_head]); - set_dma_count(priv->param.dma, BUF_SIZE); - release_dma_lock(flags); - } else { - priv->rx_ptr = 0; - } - } -} - - -static void rx_bh(void *arg) { - struct scc_priv *priv = arg; - int i = priv->rx_tail; - int cb; - unsigned long flags; - struct sk_buff *skb; - unsigned char *data; - - spin_lock_irqsave(&priv->ring_lock, flags); - while (priv->rx_count) { - spin_unlock_irqrestore(&priv->ring_lock, flags); - cb = priv->rx_len[i]; - /* Allocate buffer */ - skb = dev_alloc_skb(cb+1); - if (skb == NULL) { - /* Drop packet */ - priv->stats.rx_dropped++; - } else { - /* Fill buffer */ - data = skb_put(skb, cb+1); - data[0] = 0; - memcpy(&data[1], priv->rx_buf[i], cb); - skb->dev = priv->dev; - skb->protocol = ntohs(ETH_P_AX25); - skb->mac.raw = skb->data; - netif_rx(skb); - priv->dev->last_rx = jiffies; - priv->stats.rx_packets++; - priv->stats.rx_bytes += cb; - } - spin_lock_irqsave(&priv->ring_lock, flags); - /* Move tail */ - priv->rx_tail = i = (i + 1) % NUM_RX_BUF; - priv->rx_count--; - } - spin_unlock_irqrestore(&priv->ring_lock, flags); -} - - -static void tx_isr(struct scc_priv *priv) { - int i = priv->tx_tail, p = priv->tx_ptr; - - /* Suspend TX interrupts if we don't want to send anything. - See Figure 2-22. */ - if (p == priv->tx_len[i]) { - write_scc(priv, R0, RES_Tx_P); - return; - } - - /* Write characters */ - while ((read_scc(priv, R0) & Tx_BUF_EMP) && p < priv->tx_len[i]) { - write_scc_data(priv, priv->tx_buf[i][p++], 0); - } - - /* Reset EOM latch of Z8530 */ - if (!priv->tx_ptr && p && priv->chip == Z8530) - write_scc(priv, R0, RES_EOM_L); - - priv->tx_ptr = p; -} - - -static void es_isr(struct scc_priv *priv) { - int i, rr0, drr0, res; - unsigned long flags; - - /* Read status, reset interrupt bit (open latches) */ - rr0 = read_scc(priv, R0); - write_scc(priv, R0, RES_EXT_INT); - drr0 = priv->rr0 ^ rr0; - priv->rr0 = rr0; - - /* Transmit underrun (2.4.9.6). We can't check the TxEOM flag, since - it might have already been cleared again by AUTOEOM. */ - if (priv->state == TX_DATA) { - /* Get remaining bytes */ - i = priv->tx_tail; - if (priv->param.dma >= 0) { - disable_dma(priv->param.dma); - flags = claim_dma_lock(); - res = get_dma_residue(priv->param.dma); - release_dma_lock(flags); - } else { - res = priv->tx_len[i] - priv->tx_ptr; - priv->tx_ptr = 0; - } - /* Disable DREQ / TX interrupt */ - if (priv->param.dma >= 0 && priv->type == TYPE_TWIN) - outb(0, priv->card_base + TWIN_DMA_CFG); - else - write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); - if (res) { - /* Update packet statistics */ - priv->stats.tx_errors++; - priv->stats.tx_fifo_errors++; - /* Other underrun interrupts may already be waiting */ - write_scc(priv, R0, RES_EXT_INT); - write_scc(priv, R0, RES_EXT_INT); - } else { - /* Update packet statistics */ - priv->stats.tx_packets++; - priv->stats.tx_bytes += priv->tx_len[i]; - /* Remove frame from FIFO */ - priv->tx_tail = (i + 1) % NUM_TX_BUF; - priv->tx_count--; - /* Inform upper layers */ - netif_wake_queue(priv->dev); - } - /* Switch state */ - write_scc(priv, R15, 0); - if (priv->tx_count && - (jiffies - priv->tx_start) < priv->param.txtimeout) { - priv->state = TX_PAUSE; - start_timer(priv, priv->param.txpause, 0); - } else { - priv->state = TX_TAIL; - start_timer(priv, priv->param.txtail, 0); - } - } - - /* DCD transition */ - if (drr0 & DCD) { - if (rr0 & DCD) { - switch (priv->state) { - case IDLE: - case WAIT: - priv->state = DCD_ON; - write_scc(priv, R15, 0); - start_timer(priv, priv->param.dcdon, 0); - } - } else { - switch (priv->state) { - case RX_ON: - rx_off(priv); - priv->state = DCD_OFF; - write_scc(priv, R15, 0); - start_timer(priv, priv->param.dcdoff, 0); - } - } - } - - /* CTS transition */ - if ((drr0 & CTS) && (~rr0 & CTS) && priv->type != TYPE_TWIN) - tm_isr(priv); - -} - - -static void tm_isr(struct scc_priv *priv) { - switch (priv->state) { - case TX_HEAD: - case TX_PAUSE: - tx_on(priv); - priv->state = TX_DATA; - break; - case TX_TAIL: - write_scc(priv, R5, TxCRC_ENAB | Tx8); - priv->state = RTS_OFF; - if (priv->type != TYPE_TWIN) write_scc(priv, R15, 0); - start_timer(priv, priv->param.rtsoff, 0); - break; - case RTS_OFF: - write_scc(priv, R15, DCDIE); - priv->rr0 = read_scc(priv, R0); - if (priv->rr0 & DCD) { - priv->stats.collisions++; - rx_on(priv); - priv->state = RX_ON; - } else { - priv->state = WAIT; - start_timer(priv, priv->param.waittime, DCDIE); - } - break; - case WAIT: - if (priv->tx_count) { - priv->state = TX_HEAD; - priv->tx_start = jiffies; - write_scc(priv, R5, TxCRC_ENAB | RTS | TxENAB | Tx8); - write_scc(priv, R15, 0); - start_timer(priv, priv->param.txdelay, 0); - } else { - priv->state = IDLE; - if (priv->type != TYPE_TWIN) write_scc(priv, R15, DCDIE); - } - break; - case DCD_ON: - case DCD_OFF: - write_scc(priv, R15, DCDIE); - priv->rr0 = read_scc(priv, R0); - if (priv->rr0 & DCD) { - rx_on(priv); - priv->state = RX_ON; - } else { - priv->state = WAIT; - start_timer(priv, - random()/priv->param.persist*priv->param.slottime, - DCDIE); - } - break; - } } diff -Nru a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c --- a/drivers/net/hamradio/hdlcdrv.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/hamradio/hdlcdrv.c 2005-03-08 14:29:45 -05:00 @@ -427,27 +427,10 @@ * ===================== network driver interface ========================= */ -static inline int hdlcdrv_paranoia_check(struct net_device *dev, - const char *routine) -{ - if (!dev || !dev->priv || - ((struct hdlcdrv_state *)dev->priv)->magic != HDLCDRV_MAGIC) { - printk(KERN_ERR "hdlcdrv: bad magic number for hdlcdrv_state " - "struct in routine %s\n", routine); - return 1; - } - return 0; -} - -/* --------------------------------------------------------------------- */ - static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct hdlcdrv_state *sm; + struct hdlcdrv_state *sm = netdev_priv(dev); - if (hdlcdrv_paranoia_check(dev, "hdlcdrv_send_packet")) - return 0; - sm = (struct hdlcdrv_state *)dev->priv; if (skb->data[0] != 0) { do_kiss_params(sm, skb->data, skb->len); dev_kfree_skb(skb); @@ -475,11 +458,8 @@ static struct net_device_stats *hdlcdrv_get_stats(struct net_device *dev) { - struct hdlcdrv_state *sm; + struct hdlcdrv_state *sm = netdev_priv(dev); - if (hdlcdrv_paranoia_check(dev, "hdlcdrv_get_stats")) - return NULL; - sm = (struct hdlcdrv_state *)dev->priv; /* * Get the current statistics. This may be called with the * card open or closed. @@ -499,13 +479,9 @@ static int hdlcdrv_open(struct net_device *dev) { - struct hdlcdrv_state *s; + struct hdlcdrv_state *s = netdev_priv(dev); int i; - if (hdlcdrv_paranoia_check(dev, "hdlcdrv_open")) - return -EINVAL; - s = (struct hdlcdrv_state *)dev->priv; - if (!s->ops || !s->ops->open) return -ENODEV; @@ -540,13 +516,9 @@ static int hdlcdrv_close(struct net_device *dev) { - struct hdlcdrv_state *s; + struct hdlcdrv_state *s = netdev_priv(dev); int i = 0; - if (hdlcdrv_paranoia_check(dev, "hdlcdrv_close")) - return -EINVAL; - s = (struct hdlcdrv_state *)dev->priv; - netif_stop_queue(dev); if (s->ops && s->ops->close) @@ -562,12 +534,8 @@ static int hdlcdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct hdlcdrv_state *s; + struct hdlcdrv_state *s = netdev_priv(dev); struct hdlcdrv_ioctl bi; - - if (hdlcdrv_paranoia_check(dev, "hdlcdrv_ioctl")) - return -EINVAL; - s = (struct hdlcdrv_state *)dev->priv; if (cmd != SIOCDEVPRIVATE) { if (s->ops && s->ops->ioctl) @@ -698,7 +666,7 @@ static const struct hdlcdrv_channel_params dflt_ch_params = { 20, 2, 10, 40, 0 }; - struct hdlcdrv_state *s = dev->priv; + struct hdlcdrv_state *s = netdev_priv(dev); /* * initialize the hdlcdrv_state struct @@ -782,7 +750,7 @@ /* * initialize part of the hdlcdrv_state struct */ - s = dev->priv; + s = netdev_priv(dev); s->magic = HDLCDRV_MAGIC; s->ops = ops; dev->base_addr = baseaddr; @@ -803,7 +771,7 @@ void hdlcdrv_unregister(struct net_device *dev) { - struct hdlcdrv_state *s = dev->priv; + struct hdlcdrv_state *s = netdev_priv(dev); BUG_ON(s->magic != HDLCDRV_MAGIC); diff -Nru a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c --- a/drivers/net/hamradio/mkiss.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/hamradio/mkiss.c 2005-03-08 14:29:45 -05:00 @@ -419,7 +419,7 @@ /* Encapsulate an AX.25 packet and kick it into a TTY queue. */ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ax_disp *ax = (struct ax_disp *) dev->priv; + struct ax_disp *ax = netdev_priv(dev); if (!netif_running(dev)) { printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name); @@ -483,7 +483,7 @@ /* Open the low-level part of the AX25 channel. Easy! */ static int ax_open(struct net_device *dev) { - struct ax_disp *ax = (struct ax_disp *) dev->priv; + struct ax_disp *ax = netdev_priv(dev); unsigned long len; if (ax->tty == NULL) @@ -534,7 +534,7 @@ /* Close the low-level part of the AX25 channel. Easy! */ static int ax_close(struct net_device *dev) { - struct ax_disp *ax = (struct ax_disp *) dev->priv; + struct ax_disp *ax = netdev_priv(dev); if (ax->tty == NULL) return -EBUSY; @@ -634,7 +634,7 @@ static struct net_device_stats *ax_get_stats(struct net_device *dev) { static struct net_device_stats stats; - struct ax_disp *ax = (struct ax_disp *) dev->priv; + struct ax_disp *ax = netdev_priv(dev); memset(&stats, 0, sizeof(struct net_device_stats)); @@ -827,7 +827,7 @@ static int ax_open_dev(struct net_device *dev) { - struct ax_disp *ax = (struct ax_disp *) dev->priv; + struct ax_disp *ax = netdev_priv(dev); if (ax->tty == NULL) return -ENODEV; @@ -839,7 +839,7 @@ /* Initialize the driver. Called by network startup. */ static int ax25_init(struct net_device *dev) { - struct ax_disp *ax = (struct ax_disp *) dev->priv; + struct ax_disp *ax = netdev_priv(dev); static char ax25_bcast[AX25_ADDR_LEN] = {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; diff -Nru a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c --- a/drivers/net/hamradio/yam.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/hamradio/yam.c 2005-03-08 14:29:45 -05:00 @@ -442,7 +442,7 @@ static void yam_set_uart(struct net_device *dev) { - struct yam_port *yp = (struct yam_port *) dev->priv; + struct yam_port *yp = netdev_priv(dev); int divisor = 115200 / yp->baudrate; outb(0, IER(dev->base_addr)); @@ -565,7 +565,7 @@ static int yam_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct yam_port *yp = dev->priv; + struct yam_port *yp = netdev_priv(dev); skb_queue_tail(&yp->send_queue, skb); dev->trans_start = jiffies; @@ -592,12 +592,11 @@ static void yam_arbitrate(struct net_device *dev) { - struct yam_port *yp = dev->priv; + struct yam_port *yp = netdev_priv(dev); - if (!yp || yp->magic != YAM_MAGIC - || yp->tx_state != TX_OFF || skb_queue_empty(&yp->send_queue)) { + if (yp->magic != YAM_MAGIC || yp->tx_state != TX_OFF || + skb_queue_empty(&yp->send_queue)) return; - } /* tx_state is TX_OFF and there is data to send */ if (yp->dupmode) { @@ -725,7 +724,7 @@ for (i = 0; i < NR_PORTS; i++) { dev = yam_devs[i]; - yp = dev->priv; + yp = netdev_priv(dev); if (!netif_running(dev)) continue; @@ -784,8 +783,8 @@ static int yam_seq_show(struct seq_file *seq, void *v) { - const struct net_device *dev = v; - const struct yam_port *yp = dev->priv; + struct net_device *dev = v; + const struct yam_port *yp = netdev_priv(dev); seq_printf(seq, "Device %s\n", dev->name); seq_printf(seq, " Up %d\n", netif_running(dev)); @@ -838,10 +837,10 @@ { struct yam_port *yp; - if (!dev || !dev->priv) + if (!dev) return NULL; - yp = (struct yam_port *) dev->priv; + yp = netdev_priv(dev); if (yp->magic != YAM_MAGIC) return NULL; @@ -856,14 +855,14 @@ static int yam_open(struct net_device *dev) { - struct yam_port *yp = (struct yam_port *) dev->priv; + struct yam_port *yp = netdev_priv(dev); enum uart u; int i; int ret=0; printk(KERN_INFO "Trying %s at iobase 0x%lx irq %u\n", dev->name, dev->base_addr, dev->irq); - if (!dev || !yp || !yp->bitrate) + if (!dev || !yp->bitrate) return -ENXIO; if (!dev->base_addr || dev->base_addr > 0x1000 - YAM_EXTENT || dev->irq < 2 || dev->irq > 15) { @@ -900,7 +899,7 @@ /* Reset overruns for all ports - FPGA programming makes overruns */ for (i = 0; i < NR_PORTS; i++) { struct net_device *dev = yam_devs[i]; - struct yam_port *yp = dev->priv; + struct yam_port *yp = netdev_priv(dev); inb(LSR(dev->base_addr)); yp->stats.rx_fifo_errors = 0; } @@ -919,10 +918,11 @@ static int yam_close(struct net_device *dev) { struct sk_buff *skb; - struct yam_port *yp = (struct yam_port *) dev->priv; + struct yam_port *yp = netdev_priv(dev); - if (!dev || !yp) + if (!dev) return -EINVAL; + /* * disable interrupts */ @@ -944,7 +944,7 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct yam_port *yp = (struct yam_port *) dev->priv; + struct yam_port *yp = netdev_priv(dev); struct yamdrv_ioctl_cfg yi; struct yamdrv_ioctl_mcs *ym; int ioctl_cmd; @@ -952,7 +952,7 @@ if (copy_from_user(&ioctl_cmd, ifr->ifr_data, sizeof(int))) return -EFAULT; - if (yp == NULL || yp->magic != YAM_MAGIC) + if (yp->magic != YAM_MAGIC) return -EINVAL; if (!capable(CAP_NET_ADMIN)) @@ -1091,7 +1091,7 @@ static void yam_setup(struct net_device *dev) { - struct yam_port *yp = dev->priv; + struct yam_port *yp = netdev_priv(dev); yp->magic = YAM_MAGIC; yp->bitrate = DEFAULT_BITRATE; diff -Nru a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c --- a/drivers/net/mv643xx_eth.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/mv643xx_eth.c 2005-03-08 14:29:45 -05:00 @@ -1,5 +1,5 @@ /* - * drivers/net/mv64340_eth.c - Driver for MV64340X ethernet ports + * drivers/net/mv643xx_eth.c - Driver for MV643XX ethernet ports * Copyright (C) 2002 Matthew Dharm * * Based on the 64360 driver from: @@ -10,6 +10,12 @@ * * Copyright (C) 2003 Ralf Baechle * + * Copyright (C) 2004-2005 MontaVista Software, Inc. + * Dale Farnsworth + * + * Copyright (C) 2004 Steven J. Hill + * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -24,80 +30,100 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include +#include #include -#include +#include #include -#include #include +#include +#include #include #include #include #include +#include #include "mv643xx_eth.h" /* - * The first part is the high level driver of the gigE ethernet ports. + * The first part is the high level driver of the gigE ethernet ports. */ -/* Definition for configuring driver */ -#undef MV64340_RX_QUEUE_FILL_ON_TASK - /* Constants */ -#define EXTRA_BYTES 32 -#define WRAP ETH_HLEN + 2 + 4 + 16 -#define BUFFER_MTU dev->mtu + WRAP +#define VLAN_HLEN 4 +#define FCS_LEN 4 +#define WRAP NET_IP_ALIGN + ETH_HLEN + VLAN_HLEN + FCS_LEN +#define RX_SKB_SIZE ((dev->mtu + WRAP + 7) & ~0x7) + #define INT_CAUSE_UNMASK_ALL 0x0007ffff #define INT_CAUSE_UNMASK_ALL_EXT 0x0011ffff -#ifdef MV64340_RX_FILL_ON_TASK +#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK #define INT_CAUSE_MASK_ALL 0x00000000 #define INT_CAUSE_CHECK_BITS INT_CAUSE_UNMASK_ALL #define INT_CAUSE_CHECK_BITS_EXT INT_CAUSE_UNMASK_ALL_EXT #endif +#ifdef MV643XX_CHECKSUM_OFFLOAD_TX +#define MAX_DESCS_PER_SKB (MAX_SKB_FRAGS + 1) +#else +#define MAX_DESCS_PER_SKB 1 +#endif + +#define PHY_WAIT_ITERATIONS 1000 /* 1000 iterations * 10uS = 10mS max */ +#define PHY_WAIT_MICRO_SECONDS 10 + /* Static function declarations */ -static int mv64340_eth_real_open(struct net_device *); -static int mv64340_eth_real_stop(struct net_device *); -static int mv64340_eth_change_mtu(struct net_device *, int); -static struct net_device_stats *mv64340_eth_get_stats(struct net_device *); +static int eth_port_link_is_up(unsigned int eth_port_num); +static void eth_port_uc_addr_get(struct net_device *dev, + unsigned char *MacAddr); +static int mv643xx_eth_real_open(struct net_device *); +static int mv643xx_eth_real_stop(struct net_device *); +static int mv643xx_eth_change_mtu(struct net_device *, int); +static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *); static void eth_port_init_mac_tables(unsigned int eth_port_num); -#ifdef MV64340_NAPI -static int mv64340_poll(struct net_device *dev, int *budget); +#ifdef MV643XX_NAPI +static int mv643xx_poll(struct net_device *dev, int *budget); #endif +static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr); +static int ethernet_phy_detect(unsigned int eth_port_num); +static struct ethtool_ops mv643xx_ethtool_ops; + +static char mv643xx_driver_name[] = "mv643xx_eth"; +static char mv643xx_driver_version[] = "1.0"; + +static void __iomem *mv643xx_eth_shared_base; + +/* used to protect MV643XX_ETH_SMI_REG, which is shared across ports */ +static spinlock_t mv643xx_eth_phy_lock = SPIN_LOCK_UNLOCKED; + +static inline u32 mv_read(int offset) +{ + void *__iomem reg_base; + + reg_base = mv643xx_eth_shared_base - MV643XX_ETH_SHARED_REGS; + + return readl(reg_base + offset); +} + +static inline void mv_write(int offset, u32 data) +{ + void * __iomem reg_base; -unsigned char prom_mac_addr_base[6]; -unsigned long mv64340_sram_base; + reg_base = mv643xx_eth_shared_base - MV643XX_ETH_SHARED_REGS; + writel(data, reg_base + offset); +} /* * Changes MTU (maximum transfer unit) of the gigabit ethenret port * - * Input : pointer to ethernet interface network device structure - * new mtu size - * Output : 0 upon success, -EINVAL upon failure + * Input : pointer to ethernet interface network device structure + * new mtu size + * Output : 0 upon success, -EINVAL upon failure */ -static int mv64340_eth_change_mtu(struct net_device *dev, int new_mtu) +static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&mp->lock, flags); @@ -108,21 +134,21 @@ } dev->mtu = new_mtu; - /* + /* * Stop then re-open the interface. This will allocate RX skb's with * the new MTU. * There is a possible danger that the open will not successed, due * to memory is full, which might fail the open function. */ if (netif_running(dev)) { - if (mv64340_eth_real_stop(dev)) + if (mv643xx_eth_real_stop(dev)) printk(KERN_ERR - "%s: Fatal error on stopping device\n", - dev->name); - if (mv64340_eth_real_open(dev)) + "%s: Fatal error on stopping device\n", + dev->name); + if (mv643xx_eth_real_open(dev)) printk(KERN_ERR - "%s: Fatal error on opening device\n", - dev->name); + "%s: Fatal error on opening device\n", + dev->name); } spin_unlock_irqrestore(&mp->lock, flags); @@ -130,17 +156,17 @@ } /* - * mv64340_eth_rx_task - * + * mv643xx_eth_rx_task + * * Fills / refills RX queue on a certain gigabit ethernet port * - * Input : pointer to ethernet interface network device structure - * Output : N/A + * Input : pointer to ethernet interface network device structure + * Output : N/A */ -static void mv64340_eth_rx_task(void *data) +static void mv643xx_eth_rx_task(void *data) { - struct net_device *dev = (struct net_device *) data; - struct mv64340_private *mp = netdev_priv(dev); + struct net_device *dev = (struct net_device *)data; + struct mv643xx_private *mp = netdev_priv(dev); struct pkt_info pkt_info; struct sk_buff *skb; @@ -148,28 +174,18 @@ panic("%s: Error in test_set_bit / clear_bit", dev->name); while (mp->rx_ring_skbs < (mp->rx_ring_size - 5)) { - /* The +8 for buffer allignment and another 32 byte extra */ - - skb = dev_alloc_skb(BUFFER_MTU + 8 + EXTRA_BYTES); + skb = dev_alloc_skb(RX_SKB_SIZE); if (!skb) - /* Better luck next time */ break; mp->rx_ring_skbs++; pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT; - pkt_info.byte_cnt = dev->mtu + ETH_HLEN + 4 + 2 + EXTRA_BYTES; - /* Allign buffer to 8 bytes */ - if (pkt_info.byte_cnt & ~0x7) { - pkt_info.byte_cnt &= ~0x7; - pkt_info.byte_cnt += 8; - } - pkt_info.buf_ptr = - pci_map_single(0, skb->data, - dev->mtu + ETH_HLEN + 4 + 2 + EXTRA_BYTES, - PCI_DMA_FROMDEVICE); + pkt_info.byte_cnt = RX_SKB_SIZE; + pkt_info.buf_ptr = dma_map_single(NULL, skb->data, RX_SKB_SIZE, + DMA_FROM_DEVICE); pkt_info.return_info = skb; if (eth_rx_return_buff(mp, &pkt_info) != ETH_OK) { printk(KERN_ERR - "%s: Error allocating RX Ring\n", dev->name); + "%s: Error allocating RX Ring\n", dev->name); break; } skb_reserve(skb, 2); @@ -186,46 +202,45 @@ add_timer(&mp->timeout); mp->rx_timer_flag = 1; } -#if MV64340_RX_QUEUE_FILL_ON_TASK +#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK else { /* Return interrupts */ - MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(mp->port_num), - INT_CAUSE_UNMASK_ALL); + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(mp->port_num), + INT_CAUSE_UNMASK_ALL); } #endif } /* - * mv64340_eth_rx_task_timer_wrapper - * + * mv643xx_eth_rx_task_timer_wrapper + * * Timer routine to wake up RX queue filling task. This function is * used only in case the RX queue is empty, and all alloc_skb has * failed (due to out of memory event). * - * Input : pointer to ethernet interface network device structure - * Output : N/A + * Input : pointer to ethernet interface network device structure + * Output : N/A */ -static void mv64340_eth_rx_task_timer_wrapper(unsigned long data) +static void mv643xx_eth_rx_task_timer_wrapper(unsigned long data) { - struct net_device *dev = (struct net_device *) data; - struct mv64340_private *mp = netdev_priv(dev); + struct net_device *dev = (struct net_device *)data; + struct mv643xx_private *mp = netdev_priv(dev); mp->rx_timer_flag = 0; - mv64340_eth_rx_task((void *) data); + mv643xx_eth_rx_task((void *)data); } - /* - * mv64340_eth_update_mac_address - * + * mv643xx_eth_update_mac_address + * * Update the MAC address of the port in the address table * - * Input : pointer to ethernet interface network device structure - * Output : N/A + * Input : pointer to ethernet interface network device structure + * Output : N/A */ -static void mv64340_eth_update_mac_address(struct net_device *dev) +static void mv643xx_eth_update_mac_address(struct net_device *dev) { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); unsigned int port_num = mp->port_num; eth_port_init_mac_tables(port_num); @@ -234,64 +249,59 @@ } /* - * mv64340_eth_set_rx_mode - * + * mv643xx_eth_set_rx_mode + * * Change from promiscuos to regular rx mode * - * Input : pointer to ethernet interface network device structure - * Output : N/A + * Input : pointer to ethernet interface network device structure + * Output : N/A */ -static void mv64340_eth_set_rx_mode(struct net_device *dev) +static void mv643xx_eth_set_rx_mode(struct net_device *dev) { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); + u32 config_reg; - if (dev->flags & IFF_PROMISC) { - ethernet_set_config_reg - (mp->port_num, - ethernet_get_config_reg(mp->port_num) | - ETH_UNICAST_PROMISCUOUS_MODE); - } else { - ethernet_set_config_reg - (mp->port_num, - ethernet_get_config_reg(mp->port_num) & - ~(unsigned int) ETH_UNICAST_PROMISCUOUS_MODE); - } + config_reg = ethernet_get_config_reg(mp->port_num); + if (dev->flags & IFF_PROMISC) + config_reg |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE; + else + config_reg &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE; + ethernet_set_config_reg(mp->port_num, config_reg); } - /* - * mv64340_eth_set_mac_address - * + * mv643xx_eth_set_mac_address + * * Change the interface's mac address. * No special hardware thing should be done because interface is always * put in promiscuous mode. * - * Input : pointer to ethernet interface network device structure and - * a pointer to the designated entry to be added to the cache. - * Output : zero upon success, negative upon failure + * Input : pointer to ethernet interface network device structure and + * a pointer to the designated entry to be added to the cache. + * Output : zero upon success, negative upon failure */ -static int mv64340_eth_set_mac_address(struct net_device *dev, void *addr) +static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr) { int i; for (i = 0; i < 6; i++) /* +2 is for the offset of the HW addr type */ - dev->dev_addr[i] = ((unsigned char *) addr)[i + 2]; - mv64340_eth_update_mac_address(dev); + dev->dev_addr[i] = ((unsigned char *)addr)[i + 2]; + mv643xx_eth_update_mac_address(dev); return 0; } /* - * mv64340_eth_tx_timeout - * + * mv643xx_eth_tx_timeout + * * Called upon a timeout on transmitting a packet * - * Input : pointer to ethernet interface network device structure. - * Output : N/A + * Input : pointer to ethernet interface network device structure. + * Output : N/A */ -static void mv64340_eth_tx_timeout(struct net_device *dev) +static void mv643xx_eth_tx_timeout(struct net_device *dev) { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); printk(KERN_INFO "%s: TX timeout ", dev->name); @@ -300,31 +310,31 @@ } /* - * mv64340_eth_tx_timeout_task + * mv643xx_eth_tx_timeout_task * * Actual routine to reset the adapter when a timeout on Tx has occurred */ -static void mv64340_eth_tx_timeout_task(struct net_device *dev) +static void mv643xx_eth_tx_timeout_task(struct net_device *dev) { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); - netif_device_detach(dev); - eth_port_reset(mp->port_num); - eth_port_start(mp); - netif_device_attach(dev); + netif_device_detach(dev); + eth_port_reset(mp->port_num); + eth_port_start(mp); + netif_device_attach(dev); } /* - * mv64340_eth_free_tx_queue + * mv643xx_eth_free_tx_queue * - * Input : dev - a pointer to the required interface + * Input : dev - a pointer to the required interface * - * Output : 0 if was able to release skb , nonzero otherwise + * Output : 0 if was able to release skb , nonzero otherwise */ -static int mv64340_eth_free_tx_queue(struct net_device *dev, - unsigned int eth_int_cause_ext) +static int mv643xx_eth_free_tx_queue(struct net_device *dev, + unsigned int eth_int_cause_ext) { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); struct net_device_stats *stats = &mp->stats; struct pkt_info pkt_info; int released = 1; @@ -341,33 +351,36 @@ stats->tx_errors++; } - /* + /* * If return_info is different than 0, release the skb. * The case where return_info is not 0 is only in case * when transmitted a scatter/gather packet, where only * last skb releases the whole chain. */ if (pkt_info.return_info) { - dev_kfree_skb_irq((struct sk_buff *) - pkt_info.return_info); - released = 0; if (skb_shinfo(pkt_info.return_info)->nr_frags) - pci_unmap_page(NULL, pkt_info.buf_ptr, - pkt_info.byte_cnt, PCI_DMA_TODEVICE); + dma_unmap_page(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, + DMA_TO_DEVICE); + else + dma_unmap_single(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, + DMA_TO_DEVICE); - if (mp->tx_ring_skbs != 1) - mp->tx_ring_skbs--; - } else - pci_unmap_page(NULL, pkt_info.buf_ptr, - pkt_info.byte_cnt, PCI_DMA_TODEVICE); - - /* - * Decrement the number of outstanding skbs counter on - * the TX queue. - */ - if (mp->tx_ring_skbs == 0) - panic("ERROR - TX outstanding SKBs counter is corrupted"); + dev_kfree_skb_irq(pkt_info.return_info); + released = 0; + /* + * Decrement the number of outstanding skbs counter on + * the TX queue. + */ + if (mp->tx_ring_skbs == 0) + panic("ERROR - TX outstanding SKBs" + " counter is corrupted"); + mp->tx_ring_skbs--; + } else + dma_unmap_page(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, DMA_TO_DEVICE); } spin_unlock(&mp->lock); @@ -376,60 +389,59 @@ } /* - * mv64340_eth_receive + * mv643xx_eth_receive * * This function is forward packets that are received from the port's * queues toward kernel core or FastRoute them to another interface. * - * Input : dev - a pointer to the required interface - * max - maximum number to receive (0 means unlimted) + * Input : dev - a pointer to the required interface + * max - maximum number to receive (0 means unlimted) * - * Output : number of served packets + * Output : number of served packets */ -#ifdef MV64340_NAPI -static int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max, - int budget) +#ifdef MV643XX_NAPI +static int mv643xx_eth_receive_queue(struct net_device *dev, int budget) #else -static int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max) +static int mv643xx_eth_receive_queue(struct net_device *dev) #endif { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); struct net_device_stats *stats = &mp->stats; unsigned int received_packets = 0; struct sk_buff *skb; struct pkt_info pkt_info; -#ifdef MV64340_NAPI +#ifdef MV643XX_NAPI while (eth_port_receive(mp, &pkt_info) == ETH_OK && budget > 0) { #else - while ((--max) && eth_port_receive(mp, &pkt_info) == ETH_OK) { + while (eth_port_receive(mp, &pkt_info) == ETH_OK) { #endif mp->rx_ring_skbs--; received_packets++; -#ifdef MV64340_NAPI +#ifdef MV643XX_NAPI budget--; #endif /* Update statistics. Note byte count includes 4 byte CRC count */ stats->rx_packets++; stats->rx_bytes += pkt_info.byte_cnt; - skb = (struct sk_buff *) pkt_info.return_info; + skb = pkt_info.return_info; /* * In case received a packet without first / last bits on OR * the error summary bit is on, the packets needs to be dropeed. */ if (((pkt_info.cmd_sts - & (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) != - (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) - || (pkt_info.cmd_sts & ETH_ERROR_SUMMARY)) { + & (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) != + (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) + || (pkt_info.cmd_sts & ETH_ERROR_SUMMARY)) { stats->rx_dropped++; if ((pkt_info.cmd_sts & (ETH_RX_FIRST_DESC | - ETH_RX_LAST_DESC)) != - (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) { + ETH_RX_LAST_DESC)) != + (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) { if (net_ratelimit()) printk(KERN_ERR - "%s: Received packet spread on multiple" - " descriptors\n", - dev->name); + "%s: Received packet spread " + "on multiple descriptors\n", + dev->name); } if (pkt_info.cmd_sts & ETH_ERROR_SUMMARY) stats->rx_errors++; @@ -445,11 +457,11 @@ if (pkt_info.cmd_sts & ETH_LAYER_4_CHECKSUM_OK) { skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->csum = htons((pkt_info.cmd_sts - & 0x0007fff8) >> 3); + skb->csum = htons( + (pkt_info.cmd_sts & 0x0007fff8) >> 3); } skb->protocol = eth_type_trans(skb, dev); -#ifdef MV64340_NAPI +#ifdef MV643XX_NAPI netif_receive_skb(skb); #else netif_rx(skb); @@ -461,74 +473,74 @@ } /* - * mv64340_eth_int_handler + * mv643xx_eth_int_handler * * Main interrupt handler for the gigbit ethernet ports * - * Input : irq - irq number (not used) - * dev_id - a pointer to the required interface's data structure - * regs - not used - * Output : N/A + * Input : irq - irq number (not used) + * dev_id - a pointer to the required interface's data structure + * regs - not used + * Output : N/A */ -static irqreturn_t mv64340_eth_int_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, + struct pt_regs *regs) { - struct net_device *dev = (struct net_device *) dev_id; - struct mv64340_private *mp = netdev_priv(dev); + struct net_device *dev = (struct net_device *)dev_id; + struct mv643xx_private *mp = netdev_priv(dev); u32 eth_int_cause, eth_int_cause_ext = 0; unsigned int port_num = mp->port_num; /* Read interrupt cause registers */ - eth_int_cause = MV_READ(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num)) & - INT_CAUSE_UNMASK_ALL; + eth_int_cause = mv_read(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num)) & + INT_CAUSE_UNMASK_ALL; if (eth_int_cause & BIT1) - eth_int_cause_ext = - MV_READ(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) & - INT_CAUSE_UNMASK_ALL_EXT; + eth_int_cause_ext = mv_read( + MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) & + INT_CAUSE_UNMASK_ALL_EXT; -#ifdef MV64340_NAPI +#ifdef MV643XX_NAPI if (!(eth_int_cause & 0x0007fffd)) { - /* Dont ack the Rx interrupt */ + /* Dont ack the Rx interrupt */ #endif /* - * Clear specific ethernet port intrerrupt registers by + * Clear specific ethernet port intrerrupt registers by * acknowleding relevant bits. */ - MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), - ~eth_int_cause); + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), + ~eth_int_cause); if (eth_int_cause_ext != 0x0) - MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), - ~eth_int_cause_ext); + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG + (port_num), ~eth_int_cause_ext); /* UDP change : We may need this */ if ((eth_int_cause_ext & 0x0000ffff) && - (mv64340_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) && - (MV64340_TX_QUEUE_SIZE > mp->tx_ring_skbs + 1)) - netif_wake_queue(dev); -#ifdef MV64340_NAPI + (mv643xx_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) && + (mp->tx_ring_size > mp->tx_ring_skbs + MAX_DESCS_PER_SKB)) + netif_wake_queue(dev); +#ifdef MV643XX_NAPI } else { if (netif_rx_schedule_prep(dev)) { /* Mask all the interrupts */ - MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num),0); - MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0); + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), 0); + mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG + (port_num), 0); __netif_rx_schedule(dev); } #else - { if (eth_int_cause & (BIT2 | BIT11)) - mv64340_eth_receive_queue(dev, 0); + mv643xx_eth_receive_queue(dev, 0); /* - * After forwarded received packets to upper layer, add a task + * After forwarded received packets to upper layer, add a task * in an interrupts enabled context that refills the RX ring * with skb's. */ -#if MV64340_RX_QUEUE_FILL_ON_TASK +#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK /* Unmask all interrupts on ethernet port */ - MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), - INT_CAUSE_MASK_ALL); + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), + INT_CAUSE_MASK_ALL); queue_task(&mp->rx_task, &tq_immediate); mark_bh(IMMEDIATE_BH); #else @@ -538,25 +550,15 @@ } /* PHY status changed */ if (eth_int_cause_ext & (BIT16 | BIT20)) { - unsigned int phy_reg_data; - - /* Check Link status on ethernet port */ - eth_port_read_smi_reg(port_num, 1, &phy_reg_data); - if (!(phy_reg_data & 0x20)) { - netif_stop_queue(dev); - } else { + if (eth_port_link_is_up(port_num)) { + netif_carrier_on(dev); netif_wake_queue(dev); - - /* - * Start all TX queues on ethernet port. This is good in - * case of previous packets where not transmitted, due - * to link down and this command re-enables all TX - * queues. - * Note that it is possible to get a TX resource error - * interrupt after issuing this, since not all TX queues - * are enabled, or has anything to send. - */ - MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), 1); + /* Start TX queue */ + mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG + (port_num), 1); + } else { + netif_carrier_off(dev); + netif_stop_queue(dev); } } @@ -570,7 +572,7 @@ return IRQ_HANDLED; } -#ifdef MV64340_COAL +#ifdef MV643XX_COAL /* * eth_port_set_rx_coal - Sets coalescing interrupt mechanism on RX path @@ -584,9 +586,9 @@ * , and the required delay of the interrupt in usec. * * INPUT: - * unsigned int eth_port_num Ethernet port number - * unsigned int t_clk t_clk of the MV-643xx chip in HZ units - * unsigned int delay Delay in usec + * unsigned int eth_port_num Ethernet port number + * unsigned int t_clk t_clk of the MV-643xx chip in HZ units + * unsigned int delay Delay in usec * * OUTPUT: * Interrupt coalescing mechanism value is set in MV-643xx chip. @@ -596,15 +598,15 @@ * */ static unsigned int eth_port_set_rx_coal(unsigned int eth_port_num, - unsigned int t_clk, unsigned int delay) + unsigned int t_clk, unsigned int delay) { unsigned int coal = ((t_clk / 1000000) * delay) / 64; /* Set RX Coalescing mechanism */ - MV_WRITE(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num), - ((coal & 0x3fff) << 8) | - (MV_READ(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num)) - & 0xffc000ff)); + mv_write(MV643XX_ETH_SDMA_CONFIG_REG(eth_port_num), + ((coal & 0x3fff) << 8) | + (mv_read(MV643XX_ETH_SDMA_CONFIG_REG(eth_port_num)) + & 0xffc000ff)); return coal; } @@ -618,13 +620,13 @@ * This parameter is a timeout counter, that counts in 64 t_clk * chunks ; that when timeout event occurs a maskable interrupt * occurs. - * The parameter is calculated using the t_cLK frequency of the + * The parameter is calculated using the t_cLK frequency of the * MV-643xx chip and the required delay in the interrupt in uSec * * INPUT: - * unsigned int eth_port_num Ethernet port number - * unsigned int t_clk t_clk of the MV-643xx chip in HZ units - * unsigned int delay Delay in uSeconds + * unsigned int eth_port_num Ethernet port number + * unsigned int t_clk t_clk of the MV-643xx chip in HZ units + * unsigned int delay Delay in uSeconds * * OUTPUT: * Interrupt coalescing mechanism value is set in MV-643xx chip. @@ -634,48 +636,48 @@ * */ static unsigned int eth_port_set_tx_coal(unsigned int eth_port_num, - unsigned int t_clk, unsigned int delay) + unsigned int t_clk, unsigned int delay) { unsigned int coal; coal = ((t_clk / 1000000) * delay) / 64; /* Set TX Coalescing mechanism */ - MV_WRITE(MV64340_ETH_TX_FIFO_URGENT_THRESHOLD_REG(eth_port_num), - coal << 4); + mv_write(MV643XX_ETH_TX_FIFO_URGENT_THRESHOLD_REG(eth_port_num), + coal << 4); return coal; } /* - * mv64340_eth_open + * mv643xx_eth_open * * This function is called when openning the network device. The function * should initialize all the hardware, initialize cyclic Rx/Tx * descriptors chain and buffers and allocate an IRQ to the network * device. * - * Input : a pointer to the network device structure + * Input : a pointer to the network device structure * - * Output : zero of success , nonzero if fails. + * Output : zero of success , nonzero if fails. */ -static int mv64340_eth_open(struct net_device *dev) +static int mv643xx_eth_open(struct net_device *dev) { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); unsigned int port_num = mp->port_num; - int err = err; + int err; spin_lock_irq(&mp->lock); - err = request_irq(dev->irq, mv64340_eth_int_handler, - SA_INTERRUPT | SA_SAMPLE_RANDOM, dev->name, dev); + err = request_irq(dev->irq, mv643xx_eth_int_handler, + SA_INTERRUPT | SA_SAMPLE_RANDOM, dev->name, dev); if (err) { - printk(KERN_ERR "Can not assign IRQ number to MV64340_eth%d\n", - port_num); + printk(KERN_ERR "Can not assign IRQ number to MV643XX_eth%d\n", + port_num); err = -EAGAIN; goto out; } - if (mv64340_eth_real_open(dev)) { + if (mv643xx_eth_real_open(dev)) { printk("%s: Error opening interface\n", dev->name); err = -EBUSY; goto out_free; @@ -698,66 +700,35 @@ * ether_init_rx_desc_ring - Curve a Rx chain desc list and buffer in memory. * * DESCRIPTION: - * This function prepares a Rx chained list of descriptors and packet - * buffers in a form of a ring. The routine must be called after port - * initialization routine and before port start routine. - * The Ethernet SDMA engine uses CPU bus addresses to access the various - * devices in the system (i.e. DRAM). This function uses the ethernet - * struct 'virtual to physical' routine (set by the user) to set the ring - * with physical addresses. + * This function prepares a Rx chained list of descriptors and packet + * buffers in a form of a ring. The routine must be called after port + * initialization routine and before port start routine. + * The Ethernet SDMA engine uses CPU bus addresses to access the various + * devices in the system (i.e. DRAM). This function uses the ethernet + * struct 'virtual to physical' routine (set by the user) to set the ring + * with physical addresses. * * INPUT: - * struct mv64340_private *mp Ethernet Port Control srtuct. - * int rx_desc_num Number of Rx descriptors - * int rx_buff_size Size of Rx buffer - * unsigned int rx_desc_base_addr Rx descriptors memory area base addr. - * unsigned int rx_buff_base_addr Rx buffer memory area base addr. + * struct mv643xx_private *mp Ethernet Port Control srtuct. * * OUTPUT: - * The routine updates the Ethernet port control struct with information - * regarding the Rx descriptors and buffers. + * The routine updates the Ethernet port control struct with information + * regarding the Rx descriptors and buffers. * * RETURN: - * false if the given descriptors memory area is not aligned according to - * Ethernet SDMA specifications. - * true otherwise. + * None. */ -static int ether_init_rx_desc_ring(struct mv64340_private * mp, - unsigned long rx_buff_base_addr) +static void ether_init_rx_desc_ring(struct mv643xx_private *mp) { - unsigned long buffer_addr = rx_buff_base_addr; volatile struct eth_rx_desc *p_rx_desc; int rx_desc_num = mp->rx_ring_size; - unsigned long rx_desc_base_addr = (unsigned long) mp->p_rx_desc_area; - int rx_buff_size = 1536; /* Dummy, will be replaced later */ int i; - p_rx_desc = (struct eth_rx_desc *) rx_desc_base_addr; - - /* Rx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */ - if (rx_buff_base_addr & 0xf) - return 0; - - /* Rx buffers are limited to 64K bytes and Minimum size is 8 bytes */ - if ((rx_buff_size < 8) || (rx_buff_size > RX_BUFFER_MAX_SIZE)) - return 0; - - /* Rx buffers must be 64-bit aligned. */ - if ((rx_buff_base_addr + rx_buff_size) & 0x7) - return 0; - - /* initialize the Rx descriptors ring */ + /* initialize the next_desc_ptr links in the Rx descriptors ring */ + p_rx_desc = (struct eth_rx_desc *)mp->p_rx_desc_area; for (i = 0; i < rx_desc_num; i++) { - p_rx_desc[i].buf_size = rx_buff_size; - p_rx_desc[i].byte_cnt = 0x0000; - p_rx_desc[i].cmd_sts = - ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT; p_rx_desc[i].next_desc_ptr = mp->rx_desc_dma + ((i + 1) % rx_desc_num) * sizeof(struct eth_rx_desc); - p_rx_desc[i].buf_ptr = buffer_addr; - - mp->rx_skb[i] = NULL; - buffer_addr += rx_buff_size; } /* Save Rx desc pointer to driver struct. */ @@ -766,293 +737,288 @@ mp->rx_desc_area_size = rx_desc_num * sizeof(struct eth_rx_desc); + /* Add the queue to the list of RX queues of this port */ mp->port_rx_queue_command |= 1; - - return 1; } /* * ether_init_tx_desc_ring - Curve a Tx chain desc list and buffer in memory. * * DESCRIPTION: - * This function prepares a Tx chained list of descriptors and packet - * buffers in a form of a ring. The routine must be called after port - * initialization routine and before port start routine. - * The Ethernet SDMA engine uses CPU bus addresses to access the various - * devices in the system (i.e. DRAM). This function uses the ethernet - * struct 'virtual to physical' routine (set by the user) to set the ring - * with physical addresses. + * This function prepares a Tx chained list of descriptors and packet + * buffers in a form of a ring. The routine must be called after port + * initialization routine and before port start routine. + * The Ethernet SDMA engine uses CPU bus addresses to access the various + * devices in the system (i.e. DRAM). This function uses the ethernet + * struct 'virtual to physical' routine (set by the user) to set the ring + * with physical addresses. * * INPUT: - * struct mv64340_private *mp Ethernet Port Control srtuct. - * int tx_desc_num Number of Tx descriptors - * int tx_buff_size Size of Tx buffer - * unsigned int tx_desc_base_addr Tx descriptors memory area base addr. + * struct mv643xx_private *mp Ethernet Port Control srtuct. * * OUTPUT: - * The routine updates the Ethernet port control struct with information - * regarding the Tx descriptors and buffers. + * The routine updates the Ethernet port control struct with information + * regarding the Tx descriptors and buffers. * * RETURN: - * false if the given descriptors memory area is not aligned according to - * Ethernet SDMA specifications. - * true otherwise. + * None. */ -static int ether_init_tx_desc_ring(struct mv64340_private *mp) +static void ether_init_tx_desc_ring(struct mv643xx_private *mp) { - unsigned long tx_desc_base_addr = (unsigned long) mp->p_tx_desc_area; int tx_desc_num = mp->tx_ring_size; struct eth_tx_desc *p_tx_desc; int i; - /* Tx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */ - if (tx_desc_base_addr & 0xf) - return 0; - - /* save the first desc pointer to link with the last descriptor */ - p_tx_desc = (struct eth_tx_desc *) tx_desc_base_addr; - - /* Initialize the Tx descriptors ring */ + /* Initialize the next_desc_ptr links in the Tx descriptors ring */ + p_tx_desc = (struct eth_tx_desc *)mp->p_tx_desc_area; for (i = 0; i < tx_desc_num; i++) { - p_tx_desc[i].byte_cnt = 0x0000; - p_tx_desc[i].l4i_chk = 0x0000; - p_tx_desc[i].cmd_sts = 0x00000000; p_tx_desc[i].next_desc_ptr = mp->tx_desc_dma + ((i + 1) % tx_desc_num) * sizeof(struct eth_tx_desc); - p_tx_desc[i].buf_ptr = 0x00000000; - mp->tx_skb[i] = NULL; } - /* Set Tx desc pointer in driver struct. */ mp->tx_curr_desc_q = 0; mp->tx_used_desc_q = 0; -#ifdef MV64340_CHECKSUM_OFFLOAD_TX - mp->tx_first_desc_q = 0; +#ifdef MV643XX_CHECKSUM_OFFLOAD_TX + mp->tx_first_desc_q = 0; #endif - /* Init Tx ring base and size parameters */ - mp->tx_desc_area_size = tx_desc_num * sizeof(struct eth_tx_desc); + + mp->tx_desc_area_size = tx_desc_num * sizeof(struct eth_tx_desc); /* Add the queue to the list of Tx queues of this port */ mp->port_tx_queue_command |= 1; - - return 1; } -/* Helper function for mv64340_eth_open */ -static int mv64340_eth_real_open(struct net_device *dev) +/* Helper function for mv643xx_eth_open */ +static int mv643xx_eth_real_open(struct net_device *dev) { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); unsigned int port_num = mp->port_num; - u32 phy_reg_data; unsigned int size; /* Stop RX Queues */ - MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), - 0x0000ff00); + mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), 0x0000ff00); /* Clear the ethernet port interrupts */ - MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), 0); - MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); /* Unmask RX buffer and TX end interrupt */ - MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), - INT_CAUSE_UNMASK_ALL); + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL); /* Unmask phy and link status changes interrupts */ - MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), - INT_CAUSE_UNMASK_ALL_EXT); + mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL_EXT); /* Set the MAC Address */ memcpy(mp->port_mac_addr, dev->dev_addr, 6); eth_port_init(mp); - INIT_WORK(&mp->rx_task, (void (*)(void *)) mv64340_eth_rx_task, dev); + INIT_WORK(&mp->rx_task, (void (*)(void *))mv643xx_eth_rx_task, dev); memset(&mp->timeout, 0, sizeof(struct timer_list)); - mp->timeout.function = mv64340_eth_rx_task_timer_wrapper; - mp->timeout.data = (unsigned long) dev; + mp->timeout.function = mv643xx_eth_rx_task_timer_wrapper; + mp->timeout.data = (unsigned long)dev; mp->rx_task_busy = 0; mp->rx_timer_flag = 0; + /* Allocate RX and TX skb rings */ + mp->rx_skb = kmalloc(sizeof(*mp->rx_skb) * mp->rx_ring_size, + GFP_KERNEL); + if (!mp->rx_skb) { + printk(KERN_ERR "%s: Cannot allocate Rx skb ring\n", dev->name); + return -ENOMEM; + } + mp->tx_skb = kmalloc(sizeof(*mp->tx_skb) * mp->tx_ring_size, + GFP_KERNEL); + if (!mp->tx_skb) { + printk(KERN_ERR "%s: Cannot allocate Tx skb ring\n", dev->name); + kfree(mp->rx_skb); + return -ENOMEM; + } + /* Allocate TX ring */ mp->tx_ring_skbs = 0; - mp->tx_ring_size = MV64340_TX_QUEUE_SIZE; size = mp->tx_ring_size * sizeof(struct eth_tx_desc); mp->tx_desc_area_size = size; - /* Assumes allocated ring is 16 bytes alligned */ - mp->p_tx_desc_area = pci_alloc_consistent(NULL, size, &mp->tx_desc_dma); + if (mp->tx_sram_size) { + mp->p_tx_desc_area = ioremap(mp->tx_sram_addr, + mp->tx_sram_size); + mp->tx_desc_dma = mp->tx_sram_addr; + } else + mp->p_tx_desc_area = dma_alloc_coherent(NULL, size, + &mp->tx_desc_dma, + GFP_KERNEL); + if (!mp->p_tx_desc_area) { printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n", - dev->name, size); + dev->name, size); + kfree(mp->rx_skb); + kfree(mp->tx_skb); return -ENOMEM; } - memset((void *) mp->p_tx_desc_area, 0, mp->tx_desc_area_size); + BUG_ON((u32) mp->p_tx_desc_area & 0xf); /* check 16-byte alignment */ + memset((void *)mp->p_tx_desc_area, 0, mp->tx_desc_area_size); - /* Dummy will be replaced upon real tx */ ether_init_tx_desc_ring(mp); /* Allocate RX ring */ - /* Meantime RX Ring are fixed - but must be configurable by user */ - mp->rx_ring_size = MV64340_RX_QUEUE_SIZE; mp->rx_ring_skbs = 0; size = mp->rx_ring_size * sizeof(struct eth_rx_desc); mp->rx_desc_area_size = size; - /* Assumes allocated ring is 16 bytes aligned */ - - mp->p_rx_desc_area = pci_alloc_consistent(NULL, size, &mp->rx_desc_dma); + if (mp->rx_sram_size) { + mp->p_rx_desc_area = ioremap(mp->rx_sram_addr, + mp->rx_sram_size); + mp->rx_desc_dma = mp->rx_sram_addr; + } else + mp->p_rx_desc_area = dma_alloc_coherent(NULL, size, + &mp->rx_desc_dma, + GFP_KERNEL); if (!mp->p_rx_desc_area) { printk(KERN_ERR "%s: Cannot allocate Rx ring (size %d bytes)\n", - dev->name, size); + dev->name, size); printk(KERN_ERR "%s: Freeing previously allocated TX queues...", - dev->name); - pci_free_consistent(0, mp->tx_desc_area_size, - (void *) mp->p_tx_desc_area, - mp->tx_desc_dma); + dev->name); + if (mp->rx_sram_size) + iounmap(mp->p_rx_desc_area); + else + dma_free_coherent(NULL, mp->tx_desc_area_size, + mp->p_tx_desc_area, mp->tx_desc_dma); + kfree(mp->rx_skb); + kfree(mp->tx_skb); return -ENOMEM; } - memset(mp->p_rx_desc_area, 0, size); + memset((void *)mp->p_rx_desc_area, 0, size); - if (!(ether_init_rx_desc_ring(mp, 0))) - panic("%s: Error initializing RX Ring", dev->name); + ether_init_rx_desc_ring(mp); - mv64340_eth_rx_task(dev); /* Fill RX ring with skb's */ + mv643xx_eth_rx_task(dev); /* Fill RX ring with skb's */ eth_port_start(mp); /* Interrupt Coalescing */ -#ifdef MV64340_COAL +#ifdef MV643XX_COAL mp->rx_int_coal = - eth_port_set_rx_coal(port_num, 133000000, MV64340_RX_COAL); + eth_port_set_rx_coal(port_num, 133000000, MV643XX_RX_COAL); #endif mp->tx_int_coal = - eth_port_set_tx_coal (port_num, 133000000, MV64340_TX_COAL); + eth_port_set_tx_coal(port_num, 133000000, MV643XX_TX_COAL); - /* Increase the Rx side buffer size */ - - MV_WRITE (MV64340_ETH_PORT_SERIAL_CONTROL_REG(port_num), (0x5 << 17) | - (MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(port_num)) - & 0xfff1ffff)); - - /* Check Link status on phy */ - eth_port_read_smi_reg(port_num, 1, &phy_reg_data); - if (!(phy_reg_data & 0x20)) - netif_stop_queue(dev); - else - netif_start_queue(dev); + netif_start_queue(dev); return 0; } -static void mv64340_eth_free_tx_rings(struct net_device *dev) +static void mv643xx_eth_free_tx_rings(struct net_device *dev) { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); unsigned int port_num = mp->port_num; unsigned int curr; /* Stop Tx Queues */ - MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), - 0x0000ff00); + mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), 0x0000ff00); - /* Free TX rings */ /* Free outstanding skb's on TX rings */ - for (curr = 0; - (mp->tx_ring_skbs) && (curr < MV64340_TX_QUEUE_SIZE); - curr++) { + for (curr = 0; mp->tx_ring_skbs && curr < mp->tx_ring_size; curr++) { if (mp->tx_skb[curr]) { dev_kfree_skb(mp->tx_skb[curr]); mp->tx_ring_skbs--; } } - if (mp->tx_ring_skbs != 0) + if (mp->tx_ring_skbs) printk("%s: Error on Tx descriptor free - could not free %d" - " descriptors\n", dev->name, - mp->tx_ring_skbs); - pci_free_consistent(0, mp->tx_desc_area_size, - (void *) mp->p_tx_desc_area, mp->tx_desc_dma); + " descriptors\n", dev->name, mp->tx_ring_skbs); + + /* Free TX ring */ + if (mp->tx_sram_size) + iounmap(mp->p_tx_desc_area); + else + dma_free_coherent(NULL, mp->tx_desc_area_size, + mp->p_tx_desc_area, mp->tx_desc_dma); } -static void mv64340_eth_free_rx_rings(struct net_device *dev) +static void mv643xx_eth_free_rx_rings(struct net_device *dev) { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); unsigned int port_num = mp->port_num; int curr; /* Stop RX Queues */ - MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), - 0x0000ff00); + mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), 0x0000ff00); - /* Free RX rings */ /* Free preallocated skb's on RX rings */ - for (curr = 0; - mp->rx_ring_skbs && (curr < MV64340_RX_QUEUE_SIZE); - curr++) { + for (curr = 0; mp->rx_ring_skbs && curr < mp->rx_ring_size; curr++) { if (mp->rx_skb[curr]) { dev_kfree_skb(mp->rx_skb[curr]); mp->rx_ring_skbs--; } } - if (mp->rx_ring_skbs != 0) + if (mp->rx_ring_skbs) printk(KERN_ERR - "%s: Error in freeing Rx Ring. %d skb's still" - " stuck in RX Ring - ignoring them\n", dev->name, - mp->rx_ring_skbs); - pci_free_consistent(0, mp->rx_desc_area_size, - (void *) mp->p_rx_desc_area, - mp->rx_desc_dma); + "%s: Error in freeing Rx Ring. %d skb's still" + " stuck in RX Ring - ignoring them\n", dev->name, + mp->rx_ring_skbs); + /* Free RX ring */ + if (mp->rx_sram_size) + iounmap(mp->p_rx_desc_area); + else + dma_free_coherent(NULL, mp->rx_desc_area_size, + mp->p_rx_desc_area, mp->rx_desc_dma); } /* - * mv64340_eth_stop + * mv643xx_eth_stop * - * This function is used when closing the network device. - * It updates the hardware, + * This function is used when closing the network device. + * It updates the hardware, * release all memory that holds buffers and descriptors and release the IRQ. - * Input : a pointer to the device structure - * Output : zero if success , nonzero if fails + * Input : a pointer to the device structure + * Output : zero if success , nonzero if fails */ -/* Helper function for mv64340_eth_stop */ +/* Helper function for mv643xx_eth_stop */ -static int mv64340_eth_real_stop(struct net_device *dev) +static int mv643xx_eth_real_stop(struct net_device *dev) { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); unsigned int port_num = mp->port_num; + netif_carrier_off(dev); netif_stop_queue(dev); - mv64340_eth_free_tx_rings(dev); - mv64340_eth_free_rx_rings(dev); + mv643xx_eth_free_tx_rings(dev); + mv643xx_eth_free_rx_rings(dev); eth_port_reset(mp->port_num); /* Disable ethernet port interrupts */ - MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), 0); - MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); /* Mask RX buffer and TX end interrupt */ - MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), 0); + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), 0); /* Mask phy and link status changes interrupts */ - MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0); + mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0); return 0; } -static int mv64340_eth_stop(struct net_device *dev) +static int mv643xx_eth_stop(struct net_device *dev) { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); spin_lock_irq(&mp->lock); - mv64340_eth_real_stop(dev); + mv643xx_eth_real_stop(dev); free_irq(dev->irq, dev); spin_unlock_irq(&mp->lock); @@ -1060,59 +1026,64 @@ return 0; } -#ifdef MV64340_NAPI -static void mv64340_tx(struct net_device *dev) +#ifdef MV643XX_NAPI +static void mv643xx_tx(struct net_device *dev) { - struct mv64340_private *mp = netdev_priv(dev); - struct pkt_info pkt_info; + struct mv643xx_private *mp = netdev_priv(dev); + struct pkt_info pkt_info; while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) { if (pkt_info.return_info) { - dev_kfree_skb_irq((struct sk_buff *) - pkt_info.return_info); - if (skb_shinfo(pkt_info.return_info)->nr_frags) - pci_unmap_page(NULL, pkt_info.buf_ptr, - pkt_info.byte_cnt, - PCI_DMA_TODEVICE); - - if (mp->tx_ring_skbs != 1) - mp->tx_ring_skbs--; - } else - pci_unmap_page(NULL, pkt_info.buf_ptr, pkt_info.byte_cnt, - PCI_DMA_TODEVICE); + if (skb_shinfo(pkt_info.return_info)->nr_frags) + dma_unmap_page(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, + DMA_TO_DEVICE); + else + dma_unmap_single(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, + DMA_TO_DEVICE); + + dev_kfree_skb_irq(pkt_info.return_info); + + if (mp->tx_ring_skbs) + mp->tx_ring_skbs--; + } else + dma_unmap_page(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, DMA_TO_DEVICE); } if (netif_queue_stopped(dev) && - MV64340_TX_QUEUE_SIZE > mp->tx_ring_skbs + 1) - netif_wake_queue(dev); + mp->tx_ring_size > mp->tx_ring_skbs + MAX_DESCS_PER_SKB) + netif_wake_queue(dev); } /* - * mv64340_poll + * mv643xx_poll * * This function is used in case of NAPI */ -static int mv64340_poll(struct net_device *dev, int *budget) +static int mv643xx_poll(struct net_device *dev, int *budget) { - struct mv64340_private *mp = netdev_priv(dev); - int done = 1, orig_budget, work_done; + struct mv643xx_private *mp = netdev_priv(dev); + int done = 1, orig_budget, work_done; unsigned int port_num = mp->port_num; unsigned long flags; -#ifdef MV64340_TX_FAST_REFILL +#ifdef MV643XX_TX_FAST_REFILL if (++mp->tx_clean_threshold > 5) { spin_lock_irqsave(&mp->lock, flags); - mv64340_tx(dev); + mv643xx_tx(dev); mp->tx_clean_threshold = 0; spin_unlock_irqrestore(&mp->lock, flags); } #endif - if ((u32)(MV_READ(MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num))) != (u32)mp->rx_used_desc_q) { + if ((mv_read(MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num))) + != (u32) mp->rx_used_desc_q) { orig_budget = *budget; if (orig_budget > dev->quota) orig_budget = dev->quota; - work_done = mv64340_eth_receive_queue(dev, 0, orig_budget); + work_done = mv643xx_eth_receive_queue(dev, orig_budget); mp->rx_task.func(dev); *budget -= work_done; dev->quota -= work_done; @@ -1123,12 +1094,12 @@ if (done) { spin_lock_irqsave(&mp->lock, flags); __netif_rx_complete(dev); - MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num),0); - MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num),0); - MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_CAUSE_UNMASK_ALL); - MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), - INT_CAUSE_UNMASK_ALL_EXT); + mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL_EXT); spin_unlock_irqrestore(&mp->lock, flags); } @@ -1137,19 +1108,19 @@ #endif /* - * mv64340_eth_start_xmit + * mv643xx_eth_start_xmit * - * This function is queues a packet in the Tx descriptor for + * This function is queues a packet in the Tx descriptor for * required port. * - * Input : skb - a pointer to socket buffer - * dev - a pointer to the required port + * Input : skb - a pointer to socket buffer + * dev - a pointer to the required port * - * Output : zero upon success + * Output : zero upon success */ -static int mv64340_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); struct net_device_stats *stats = &mp->stats; ETH_FUNC_RET_STATUS status; unsigned long flags; @@ -1157,119 +1128,195 @@ if (netif_queue_stopped(dev)) { printk(KERN_ERR - "%s: Tried sending packet when interface is stopped\n", - dev->name); + "%s: Tried sending packet when interface is stopped\n", + dev->name); return 1; } /* This is a hard error, log it. */ - if ((MV64340_TX_QUEUE_SIZE - mp->tx_ring_skbs) <= - (skb_shinfo(skb)->nr_frags + 1)) { + if ((mp->tx_ring_size - mp->tx_ring_skbs) <= + (skb_shinfo(skb)->nr_frags + 1)) { netif_stop_queue(dev); printk(KERN_ERR - "%s: Bug in mv64340_eth - Trying to transmit when" - " queue full !\n", dev->name); + "%s: Bug in mv643xx_eth - Trying to transmit when" + " queue full !\n", dev->name); return 1; } /* Paranoid check - this shouldn't happen */ if (skb == NULL) { stats->tx_dropped++; + printk(KERN_ERR "mv64320_eth paranoid check failed\n"); return 1; } spin_lock_irqsave(&mp->lock, flags); /* Update packet info data structure -- DMA owned, first last */ -#ifdef MV64340_CHECKSUM_OFFLOAD_TX - if (!skb_shinfo(skb)->nr_frags || (skb_shinfo(skb)->nr_frags > 3)) { -#endif - pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | - ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC; +#ifdef MV643XX_CHECKSUM_OFFLOAD_TX + if (!skb_shinfo(skb)->nr_frags) { +linear: + if (skb->ip_summed != CHECKSUM_HW) { + pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | + ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC; + pkt_info.l4i_chk = 0; + } else { + u32 ipheader = skb->nh.iph->ihl << 11; + pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | + ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC | + ETH_GEN_TCP_UDP_CHECKSUM | + ETH_GEN_IP_V_4_CHECKSUM | ipheader; + /* CPU already calculated pseudo header checksum. */ + if (skb->nh.iph->protocol == IPPROTO_UDP) { + pkt_info.cmd_sts |= ETH_UDP_FRAME; + pkt_info.l4i_chk = skb->h.uh->check; + } else if (skb->nh.iph->protocol == IPPROTO_TCP) + pkt_info.l4i_chk = skb->h.th->check; + else { + printk(KERN_ERR + "%s: chksum proto != TCP or UDP\n", + dev->name); + spin_unlock_irqrestore(&mp->lock, flags); + return 1; + } + } pkt_info.byte_cnt = skb->len; - pkt_info.buf_ptr = pci_map_single(0, skb->data, skb->len, - PCI_DMA_TODEVICE); - - + pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len, + DMA_TO_DEVICE); pkt_info.return_info = skb; + mp->tx_ring_skbs++; status = eth_port_send(mp, &pkt_info); if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL)) printk(KERN_ERR "%s: Error on transmitting packet\n", - dev->name); - mp->tx_ring_skbs++; -#ifdef MV64340_CHECKSUM_OFFLOAD_TX + dev->name); + stats->tx_bytes += pkt_info.byte_cnt; } else { - unsigned int frag; - u32 ipheader; + unsigned int frag; + u32 ipheader; - /* first frag which is skb header */ - pkt_info.byte_cnt = skb_headlen(skb); - pkt_info.buf_ptr = pci_map_single(0, skb->data, - skb_headlen(skb), PCI_DMA_TODEVICE); - pkt_info.return_info = 0; - ipheader = skb->nh.iph->ihl << 11; - pkt_info.cmd_sts = ETH_TX_FIRST_DESC | - ETH_GEN_TCP_UDP_CHECKSUM | - ETH_GEN_IP_V_4_CHECKSUM | - ipheader; - /* CPU already calculated pseudo header checksum. So, use it */ - pkt_info.l4i_chk = skb->h.th->check; - status = eth_port_send(mp, &pkt_info); + /* Since hardware can't handle unaligned fragments smaller + * than 9 bytes, if we find any, we linearize the skb + * and start again. When I've seen it, it's always been + * the first frag (probably near the end of the page), + * but we check all frags to be safe. + */ + for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { + skb_frag_t *fragp; + + fragp = &skb_shinfo(skb)->frags[frag]; + if (fragp->size <= 8 && fragp->page_offset & 0x7) { + skb_linearize(skb, GFP_ATOMIC); + printk(KERN_DEBUG "%s: unaligned tiny fragment" + "%d of %d, fixed\n", + dev->name, frag, + skb_shinfo(skb)->nr_frags); + goto linear; + } + } + + /* first frag which is skb header */ + pkt_info.byte_cnt = skb_headlen(skb); + pkt_info.buf_ptr = dma_map_single(NULL, skb->data, + skb_headlen(skb), + DMA_TO_DEVICE); + pkt_info.l4i_chk = 0; + pkt_info.return_info = 0; + pkt_info.cmd_sts = ETH_TX_FIRST_DESC; + + if (skb->ip_summed == CHECKSUM_HW) { + ipheader = skb->nh.iph->ihl << 11; + pkt_info.cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM | + ETH_GEN_IP_V_4_CHECKSUM | ipheader; + /* CPU already calculated pseudo header checksum. */ + if (skb->nh.iph->protocol == IPPROTO_UDP) { + pkt_info.cmd_sts |= ETH_UDP_FRAME; + pkt_info.l4i_chk = skb->h.uh->check; + } else if (skb->nh.iph->protocol == IPPROTO_TCP) + pkt_info.l4i_chk = skb->h.th->check; + else { + printk(KERN_ERR + "%s: chksum proto != TCP or UDP\n", + dev->name); + spin_unlock_irqrestore(&mp->lock, flags); + return 1; + } + } + + status = eth_port_send(mp, &pkt_info); if (status != ETH_OK) { - if ((status == ETH_ERROR)) - printk(KERN_ERR "%s: Error on transmitting packet\n", dev->name); - if (status == ETH_QUEUE_FULL) - printk("Error on Queue Full \n"); - if (status == ETH_QUEUE_LAST_RESOURCE) - printk("Tx resource error \n"); + if ((status == ETH_ERROR)) + printk(KERN_ERR + "%s: Error on transmitting packet\n", + dev->name); + if (status == ETH_QUEUE_FULL) + printk("Error on Queue Full \n"); + if (status == ETH_QUEUE_LAST_RESOURCE) + printk("Tx resource error \n"); } + stats->tx_bytes += pkt_info.byte_cnt; + + /* Check for the remaining frags */ + for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { + skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; + pkt_info.l4i_chk = 0x0000; + pkt_info.cmd_sts = 0x00000000; + + /* Last Frag enables interrupt and frees the skb */ + if (frag == (skb_shinfo(skb)->nr_frags - 1)) { + pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT | + ETH_TX_LAST_DESC; + pkt_info.return_info = skb; + mp->tx_ring_skbs++; + } else { + pkt_info.return_info = 0; + } + pkt_info.l4i_chk = 0; + pkt_info.byte_cnt = this_frag->size; - /* Check for the remaining frags */ - for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { - skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; - pkt_info.l4i_chk = 0x0000; - pkt_info.cmd_sts = 0x00000000; - - /* Last Frag enables interrupt and frees the skb */ - if (frag == (skb_shinfo(skb)->nr_frags - 1)) { - pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT | - ETH_TX_LAST_DESC; - pkt_info.return_info = skb; - mp->tx_ring_skbs++; - } - else { - pkt_info.return_info = 0; - } - pkt_info.byte_cnt = this_frag->size; - if (this_frag->size < 8) - printk("%d : \n", skb_shinfo(skb)->nr_frags); - - pkt_info.buf_ptr = pci_map_page(NULL, this_frag->page, - this_frag->page_offset, - this_frag->size, PCI_DMA_TODEVICE); + pkt_info.buf_ptr = dma_map_page(NULL, this_frag->page, + this_frag->page_offset, + this_frag->size, + DMA_TO_DEVICE); - status = eth_port_send(mp, &pkt_info); + status = eth_port_send(mp, &pkt_info); if (status != ETH_OK) { - if ((status == ETH_ERROR)) - printk(KERN_ERR "%s: Error on transmitting packet\n", dev->name); + if ((status == ETH_ERROR)) + printk(KERN_ERR "%s: Error on " + "transmitting packet\n", + dev->name); - if (status == ETH_QUEUE_LAST_RESOURCE) - printk("Tx resource error \n"); + if (status == ETH_QUEUE_LAST_RESOURCE) + printk("Tx resource error \n"); - if (status == ETH_QUEUE_FULL) - printk("Queue is full \n"); + if (status == ETH_QUEUE_FULL) + printk("Queue is full \n"); } - } - } + stats->tx_bytes += pkt_info.byte_cnt; + } + } +#else + pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | ETH_TX_FIRST_DESC | + ETH_TX_LAST_DESC; + pkt_info.l4i_chk = 0; + pkt_info.byte_cnt = skb->len; + pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len, + DMA_TO_DEVICE); + pkt_info.return_info = skb; + mp->tx_ring_skbs++; + status = eth_port_send(mp, &pkt_info); + if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL)) + printk(KERN_ERR "%s: Error on transmitting packet\n", + dev->name); + stats->tx_bytes += pkt_info.byte_cnt; #endif /* Check if TX queue can handle another skb. If not, then * signal higher layers to stop requesting TX */ - if (MV64340_TX_QUEUE_SIZE <= (mp->tx_ring_skbs + 1)) - /* + if (mp->tx_ring_size <= (mp->tx_ring_skbs + MAX_DESCS_PER_SKB)) + /* * Stop getting skb's from upper layers. * Getting skb's from upper layers will be enabled again after * packets are released. @@ -1277,7 +1324,6 @@ netif_stop_queue(dev); /* Update statistics and start of transmittion time */ - stats->tx_bytes += skb->len; stats->tx_packets++; dev->trans_start = jiffies; @@ -1287,212 +1333,302 @@ } /* - * mv64340_eth_get_stats + * mv643xx_eth_get_stats * * Returns a pointer to the interface statistics. * - * Input : dev - a pointer to the required interface + * Input : dev - a pointer to the required interface * - * Output : a pointer to the interface's statistics + * Output : a pointer to the interface's statistics */ -static struct net_device_stats *mv64340_eth_get_stats(struct net_device *dev) +static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev) { - struct mv64340_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = netdev_priv(dev); return &mp->stats; } /*/ - * mv64340_eth_init - * - * First function called after registering the network device. - * It's purpose is to initialize the device as an ethernet device, - * fill the structure that was given in registration with pointers - * to functions, and setting the MAC address of the interface + * mv643xx_eth_probe * - * Input : number of port to initialize - * Output : -ENONMEM if failed , 0 if success - */ -static struct net_device *mv64340_eth_init(int port_num) -{ - struct mv64340_private *mp; + * First function called after registering the network device. + * It's purpose is to initialize the device as an ethernet device, + * fill the ethernet device structure with pointers * to functions, + * and set the MAC address of the interface + * + * Input : struct device * + * Output : -ENOMEM if failed , 0 if success + */ +static int mv643xx_eth_probe(struct device *ddev) +{ + struct platform_device *pdev = to_platform_device(ddev); + struct mv643xx_eth_platform_data *pd; + int port_num = pdev->id; + struct mv643xx_private *mp; struct net_device *dev; + u8 *p; + struct resource *res; int err; - dev = alloc_etherdev(sizeof(struct mv64340_private)); + dev = alloc_etherdev(sizeof(struct mv643xx_private)); if (!dev) - return NULL; + return -ENOMEM; + + dev_set_drvdata(ddev, dev); mp = netdev_priv(dev); - dev->irq = ETH_PORT0_IRQ_NUM + port_num; + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + BUG_ON(!res); + dev->irq = res->start; - dev->open = mv64340_eth_open; - dev->stop = mv64340_eth_stop; - dev->hard_start_xmit = mv64340_eth_start_xmit; - dev->get_stats = mv64340_eth_get_stats; - dev->set_mac_address = mv64340_eth_set_mac_address; - dev->set_multicast_list = mv64340_eth_set_rx_mode; + mp->port_num = port_num; + + dev->open = mv643xx_eth_open; + dev->stop = mv643xx_eth_stop; + dev->hard_start_xmit = mv643xx_eth_start_xmit; + dev->get_stats = mv643xx_eth_get_stats; + dev->set_mac_address = mv643xx_eth_set_mac_address; + dev->set_multicast_list = mv643xx_eth_set_rx_mode; /* No need to Tx Timeout */ - dev->tx_timeout = mv64340_eth_tx_timeout; -#ifdef MV64340_NAPI - dev->poll = mv64340_poll; - dev->weight = 64; + dev->tx_timeout = mv643xx_eth_tx_timeout; +#ifdef MV643XX_NAPI + dev->poll = mv643xx_poll; + dev->weight = 64; #endif dev->watchdog_timeo = 2 * HZ; - dev->tx_queue_len = MV64340_TX_QUEUE_SIZE; + dev->tx_queue_len = mp->tx_ring_size; dev->base_addr = 0; - dev->change_mtu = mv64340_eth_change_mtu; + dev->change_mtu = mv643xx_eth_change_mtu; + SET_ETHTOOL_OPS(dev, &mv643xx_ethtool_ops); -#ifdef MV64340_CHECKSUM_OFFLOAD_TX +#ifdef MV643XX_CHECKSUM_OFFLOAD_TX #ifdef MAX_SKB_FRAGS - /* - * Zero copy can only work if we use Discovery II memory. Else, we will - * have to map the buffers to ISA memory which is only 16 MB - */ - dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HW_CSUM; + /* + * Zero copy can only work if we use Discovery II memory. Else, we will + * have to map the buffers to ISA memory which is only 16 MB + */ + dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HW_CSUM; #endif #endif - mp->port_num = port_num; - /* Configure the timeout task */ - INIT_WORK(&mp->tx_timeout_task, - (void (*)(void *))mv64340_eth_tx_timeout_task, dev); + INIT_WORK(&mp->tx_timeout_task, + (void (*)(void *))mv643xx_eth_tx_timeout_task, dev); spin_lock_init(&mp->lock); - /* set MAC addresses */ - memcpy(dev->dev_addr, prom_mac_addr_base, 6); - dev->dev_addr[5] += port_num; + /* set default config values */ + eth_port_uc_addr_get(dev, dev->dev_addr); + mp->port_config = MV643XX_ETH_PORT_CONFIG_DEFAULT_VALUE; + mp->port_config_extend = MV643XX_ETH_PORT_CONFIG_EXTEND_DEFAULT_VALUE; + mp->port_sdma_config = MV643XX_ETH_PORT_SDMA_CONFIG_DEFAULT_VALUE; + mp->port_serial_control = MV643XX_ETH_PORT_SERIAL_CONTROL_DEFAULT_VALUE; + mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE; + mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE; + + pd = pdev->dev.platform_data; + if (pd) { + if (pd->mac_addr != NULL) + memcpy(dev->dev_addr, pd->mac_addr, 6); + + if (pd->phy_addr || pd->force_phy_addr) + ethernet_phy_set(port_num, pd->phy_addr); + + if (pd->port_config || pd->force_port_config) + mp->port_config = pd->port_config; + + if (pd->port_config_extend || pd->force_port_config_extend) + mp->port_config_extend = pd->port_config_extend; + + if (pd->port_sdma_config || pd->force_port_sdma_config) + mp->port_sdma_config = pd->port_sdma_config; + + if (pd->port_serial_control || pd->force_port_serial_control) + mp->port_serial_control = pd->port_serial_control; + + if (pd->rx_queue_size) + mp->rx_ring_size = pd->rx_queue_size; + + if (pd->tx_queue_size) + mp->tx_ring_size = pd->tx_queue_size; + + if (pd->tx_sram_size) { + mp->tx_sram_size = pd->tx_sram_size; + mp->tx_sram_addr = pd->tx_sram_addr; + } + + if (pd->rx_sram_size) { + mp->rx_sram_size = pd->rx_sram_size; + mp->rx_sram_addr = pd->rx_sram_addr; + } + } + + err = ethernet_phy_detect(port_num); + if (err) { + pr_debug("MV643xx ethernet port %d: " + "No PHY detected at addr %d\n", + port_num, ethernet_phy_get(port_num)); + return err; + } err = register_netdev(dev); if (err) - goto out_free_dev; + goto out; - printk(KERN_NOTICE "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, port_num, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + p = dev->dev_addr; + printk(KERN_NOTICE + "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, port_num, p[0], p[1], p[2], p[3], p[4], p[5]); if (dev->features & NETIF_F_SG) - printk("Scatter Gather Enabled "); + printk(KERN_NOTICE "%s: Scatter Gather Enabled\n", dev->name); if (dev->features & NETIF_F_IP_CSUM) - printk("TX TCP/IP Checksumming Supported \n"); + printk(KERN_NOTICE "%s: TX TCP/IP Checksumming Supported\n", + dev->name); + +#ifdef MV643XX_CHECKSUM_OFFLOAD_TX + printk(KERN_NOTICE "%s: RX TCP/UDP Checksum Offload ON \n", dev->name); +#endif - printk("RX TCP/UDP Checksum Offload ON, \n"); - printk("TX and RX Interrupt Coalescing ON \n"); +#ifdef MV643XX_COAL + printk(KERN_NOTICE "%s: TX and RX Interrupt Coalescing ON \n", + dev->name); +#endif -#ifdef MV64340_NAPI - printk("RX NAPI Enabled \n"); +#ifdef MV643XX_NAPI + printk(KERN_NOTICE "%s: RX NAPI Enabled \n", dev->name); #endif - return dev; + return 0; -out_free_dev: +out: free_netdev(dev); - return NULL; + return err; } -static void mv64340_eth_remove(struct net_device *dev) +static int mv643xx_eth_remove(struct device *ddev) { - struct mv64340_private *mp = netdev_priv(dev); + struct net_device *dev = dev_get_drvdata(ddev); unregister_netdev(dev); flush_scheduled_work(); + free_netdev(dev); + dev_set_drvdata(ddev, NULL); + return 0; +} + +static int mv643xx_eth_shared_probe(struct device *ddev) +{ + struct platform_device *pdev = to_platform_device(ddev); + struct resource *res; + + printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n"); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + return -ENODEV; + + mv643xx_eth_shared_base = ioremap(res->start, + MV643XX_ETH_SHARED_REGS_SIZE); + if (mv643xx_eth_shared_base == NULL) + return -ENOMEM; + + return 0; + +} + +static int mv643xx_eth_shared_remove(struct device *ddev) +{ + iounmap(mv643xx_eth_shared_base); + mv643xx_eth_shared_base = NULL; + + return 0; } -static struct net_device *mv64340_dev0; -static struct net_device *mv64340_dev1; -static struct net_device *mv64340_dev2; +static struct device_driver mv643xx_eth_driver = { + .name = MV643XX_ETH_NAME, + .bus = &platform_bus_type, + .probe = mv643xx_eth_probe, + .remove = mv643xx_eth_remove, +}; + +static struct device_driver mv643xx_eth_shared_driver = { + .name = MV643XX_ETH_SHARED_NAME, + .bus = &platform_bus_type, + .probe = mv643xx_eth_shared_probe, + .remove = mv643xx_eth_shared_remove, +}; /* - * mv64340_init_module + * mv643xx_init_module * * Registers the network drivers into the Linux kernel * - * Input : N/A + * Input : N/A * - * Output : N/A + * Output : N/A */ -static int __init mv64340_init_module(void) +static int __init mv643xx_init_module(void) { - printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n"); + int rc; -#ifdef CONFIG_MV643XX_ETH_0 - mv64340_dev0 = mv64340_eth_init(0); - if (!mv64340_dev0) { - printk(KERN_ERR - "Error registering MV-64360 ethernet port 0\n"); - } -#endif -#ifdef CONFIG_MV643XX_ETH_1 - mv64340_dev1 = mv64340_eth_init(1); - if (!mv64340_dev1) { - printk(KERN_ERR - "Error registering MV-64360 ethernet port 1\n"); - } -#endif -#ifdef CONFIG_MV643XX_ETH_2 - mv64340_dev2 = mv64340_eth_init(2); - if (!mv64340_dev2) { - printk(KERN_ERR - "Error registering MV-64360 ethernet port 2\n"); + rc = driver_register(&mv643xx_eth_shared_driver); + if (!rc) { + rc = driver_register(&mv643xx_eth_driver); + if (rc) + driver_unregister(&mv643xx_eth_shared_driver); } -#endif - return 0; + return rc; } /* - * mv64340_cleanup_module + * mv643xx_cleanup_module * * Registers the network drivers into the Linux kernel * - * Input : N/A + * Input : N/A * - * Output : N/A + * Output : N/A */ -static void __exit mv64340_cleanup_module(void) +static void __exit mv643xx_cleanup_module(void) { - if (mv64340_dev2) - mv64340_eth_remove(mv64340_dev2); - if (mv64340_dev1) - mv64340_eth_remove(mv64340_dev1); - if (mv64340_dev0) - mv64340_eth_remove(mv64340_dev0); + driver_unregister(&mv643xx_eth_driver); + driver_unregister(&mv643xx_eth_shared_driver); } -module_init(mv64340_init_module); -module_exit(mv64340_cleanup_module); +module_init(mv643xx_init_module); +module_exit(mv643xx_cleanup_module); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Rabeeh Khoury, Assaf Hoffman, Matthew Dharm and Manish Lachwani"); -MODULE_DESCRIPTION("Ethernet driver for Marvell MV64340"); +MODULE_AUTHOR( "Rabeeh Khoury, Assaf Hoffman, Matthew Dharm, Manish Lachwani" + " and Dale Farnsworth"); +MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX"); /* - * The second part is the low level driver of the gigE ethernet ports. + * The second part is the low level driver of the gigE ethernet ports. */ /* * Marvell's Gigabit Ethernet controller low level driver * * DESCRIPTION: - * This file introduce low level API to Marvell's Gigabit Ethernet + * This file introduce low level API to Marvell's Gigabit Ethernet * controller. This Gigabit Ethernet Controller driver API controls * 1) Operations (i.e. port init, start, reset etc'). * 2) Data flow (i.e. port send, receive etc'). * Each Gigabit Ethernet port is controlled via - * struct mv64340_private. + * struct mv643xx_private. * This struct includes user configuration information as well as * driver internal data needed for its operations. * - * Supported Features: + * Supported Features: * - This low level driver is OS independent. Allocating memory for * the descriptor rings and buffers are not within the scope of * this driver. @@ -1509,12 +1645,12 @@ * - PHY access and control API. * - Port control register configuration API. * - Full control over Unicast and Multicast MAC configurations. - * + * * Operation flow: * * Initialization phase - * This phase complete the initialization of the the mv64340_private - * struct. + * This phase complete the initialization of the the + * mv643xx_private struct. * User information regarding port configuration has to be set * prior to calling the port initialization routine. * @@ -1523,7 +1659,7 @@ * access to DRAM and internal SRAM memory spaces. * * Driver ring initialization - * Allocating memory for the descriptor rings and buffers is not + * Allocating memory for the descriptor rings and buffers is not * within the scope of this driver. Thus, the user is required to * allocate memory for the descriptors ring and buffers. Those * memory parameters are used by the Rx and Tx ring initialization @@ -1531,49 +1667,50 @@ * of a ring. * Note: Pay special attention to alignment issues when using * cached descriptors/buffers. In this phase the driver store - * information in the mv64340_private struct regarding each queue + * information in the mv643xx_private struct regarding each queue * ring. * - * Driver start + * Driver start * This phase prepares the Ethernet port for Rx and Tx activity. - * It uses the information stored in the mv64340_private struct to + * It uses the information stored in the mv643xx_private struct to * initialize the various port registers. * * Data flow: * All packet references to/from the driver are done using - * struct pkt_info. - * This struct is a unified struct used with Rx and Tx operations. + * struct pkt_info. + * This struct is a unified struct used with Rx and Tx operations. * This way the user is not required to be familiar with neither * Tx nor Rx descriptors structures. * The driver's descriptors rings are management by indexes. * Those indexes controls the ring resources and used to indicate * a SW resource error: - * 'current' - * This index points to the current available resource for use. For - * example in Rx process this index will point to the descriptor - * that will be passed to the user upon calling the receive routine. - * In Tx process, this index will point to the descriptor + * 'current' + * This index points to the current available resource for use. For + * example in Rx process this index will point to the descriptor + * that will be passed to the user upon calling the receive + * routine. In Tx process, this index will point to the descriptor * that will be assigned with the user packet info and transmitted. - * 'used' - * This index points to the descriptor that need to restore its + * 'used' + * This index points to the descriptor that need to restore its * resources. For example in Rx process, using the Rx buffer return * API will attach the buffer returned in packet info to the * descriptor pointed by 'used'. In Tx process, using the Tx * descriptor return will merely return the user packet info with - * the command status of the transmitted buffer pointed by the + * the command status of the transmitted buffer pointed by the * 'used' index. Nevertheless, it is essential to use this routine * to update the 'used' index. * 'first' - * This index supports Tx Scatter-Gather. It points to the first - * descriptor of a packet assembled of multiple buffers. For example - * when in middle of Such packet we have a Tx resource error the - * 'curr' index get the value of 'first' to indicate that the ring - * returned to its state before trying to transmit this packet. + * This index supports Tx Scatter-Gather. It points to the first + * descriptor of a packet assembled of multiple buffers. For + * example when in middle of Such packet we have a Tx resource + * error the 'curr' index get the value of 'first' to indicate + * that the ring returned to its state before trying to transmit + * this packet. * * Receive operation: * The eth_port_receive API set the packet information struct, - * passed by the caller, with received information from the - * 'current' SDMA descriptor. + * passed by the caller, with received information from the + * 'current' SDMA descriptor. * It is the user responsibility to return this resource back * to the Rx descriptor ring to enable the reuse of this source. * Return Rx resource is done using the eth_rx_return_buff API. @@ -1594,27 +1731,21 @@ * * EXTERNAL INTERFACE * - * Prior to calling the initialization routine eth_port_init() the user - * must set the following fields under mv64340_private struct: - * port_num User Ethernet port number. - * port_mac_addr[6] User defined port MAC address. - * port_config User port configuration value. - * port_config_extend User port config extend value. - * port_sdma_config User port SDMA config value. - * port_serial_control User port serial control value. - * - * This driver introduce a set of default values: - * PORT_CONFIG_VALUE Default port configuration value - * PORT_CONFIG_EXTEND_VALUE Default port extend configuration value - * PORT_SDMA_CONFIG_VALUE Default sdma control value - * PORT_SERIAL_CONTROL_VALUE Default port serial control value + * Prior to calling the initialization routine eth_port_init() the user + * must set the following fields under mv643xx_private struct: + * port_num User Ethernet port number. + * port_mac_addr[6] User defined port MAC address. + * port_config User port configuration value. + * port_config_extend User port config extend value. + * port_sdma_config User port SDMA config value. + * port_serial_control User port serial control value. * * This driver data flow is done using the struct pkt_info which - * is a unified struct for Rx and Tx operations: + * is a unified struct for Rx and Tx operations: * * byte_cnt Tx/Rx descriptor buffer byte count. * l4i_chk CPU provided TCP Checksum. For Tx operation - * only. + * only. * cmd_sts Tx/Rx descriptor command status. * buf_ptr Tx/Rx descriptor buffer pointer. * return_info Tx/Rx user resource return information. @@ -1623,70 +1754,44 @@ /* defines */ /* SDMA command macros */ #define ETH_ENABLE_TX_QUEUE(eth_port) \ - MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), 1) - -#define ETH_DISABLE_TX_QUEUE(eth_port) \ - MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), \ - (1 << 8)) - -#define ETH_ENABLE_RX_QUEUE(rx_queue, eth_port) \ - MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port), \ - (1 << rx_queue)) - -#define ETH_DISABLE_RX_QUEUE(rx_queue, eth_port) \ - MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port), \ - (1 << (8 + rx_queue))) - -#define LINK_UP_TIMEOUT 100000 -#define PHY_BUSY_TIMEOUT 10000000 + mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), 1) /* locals */ /* PHY routines */ static int ethernet_phy_get(unsigned int eth_port_num); +static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr); /* Ethernet Port routines */ static int eth_port_uc_addr(unsigned int eth_port_num, unsigned char uc_nibble, - int option); + int option); /* * eth_port_init - Initialize the Ethernet port driver * * DESCRIPTION: - * This function prepares the ethernet port to start its activity: - * 1) Completes the ethernet port driver struct initialization toward port - * start routine. - * 2) Resets the device to a quiescent state in case of warm reboot. - * 3) Enable SDMA access to all four DRAM banks as well as internal SRAM. - * 4) Clean MAC tables. The reset status of those tables is unknown. - * 5) Set PHY address. - * Note: Call this routine prior to eth_port_start routine and after - * setting user values in the user fields of Ethernet port control - * struct. + * This function prepares the ethernet port to start its activity: + * 1) Completes the ethernet port driver struct initialization toward port + * start routine. + * 2) Resets the device to a quiescent state in case of warm reboot. + * 3) Enable SDMA access to all four DRAM banks as well as internal SRAM. + * 4) Clean MAC tables. The reset status of those tables is unknown. + * 5) Set PHY address. + * Note: Call this routine prior to eth_port_start routine and after + * setting user values in the user fields of Ethernet port control + * struct. * * INPUT: - * struct mv64340_private *mp Ethernet port control struct + * struct mv643xx_private *mp Ethernet port control struct * * OUTPUT: - * See description. + * See description. * * RETURN: - * None. + * None. */ -static void eth_port_init(struct mv64340_private * mp) +static void eth_port_init(struct mv643xx_private *mp) { - mp->port_config = PORT_CONFIG_VALUE; - mp->port_config_extend = PORT_CONFIG_EXTEND_VALUE; -#if defined(__BIG_ENDIAN) - mp->port_sdma_config = PORT_SDMA_CONFIG_VALUE; -#elif defined(__LITTLE_ENDIAN) - mp->port_sdma_config = PORT_SDMA_CONFIG_VALUE | - ETH_BLM_RX_NO_SWAP | ETH_BLM_TX_NO_SWAP; -#else -#error One of __LITTLE_ENDIAN or __BIG_ENDIAN must be defined! -#endif - mp->port_serial_control = PORT_SERIAL_CONTROL_VALUE; - mp->port_rx_queue_command = 0; mp->port_tx_queue_command = 0; @@ -1704,77 +1809,73 @@ * eth_port_start - Start the Ethernet port activity. * * DESCRIPTION: - * This routine prepares the Ethernet port for Rx and Tx activity: - * 1. Initialize Tx and Rx Current Descriptor Pointer for each queue that - * has been initialized a descriptor's ring (using - * ether_init_tx_desc_ring for Tx and ether_init_rx_desc_ring for Rx) - * 2. Initialize and enable the Ethernet configuration port by writing to - * the port's configuration and command registers. - * 3. Initialize and enable the SDMA by writing to the SDMA's - * configuration and command registers. After completing these steps, - * the ethernet port SDMA can starts to perform Rx and Tx activities. + * This routine prepares the Ethernet port for Rx and Tx activity: + * 1. Initialize Tx and Rx Current Descriptor Pointer for each queue that + * has been initialized a descriptor's ring (using + * ether_init_tx_desc_ring for Tx and ether_init_rx_desc_ring for Rx) + * 2. Initialize and enable the Ethernet configuration port by writing to + * the port's configuration and command registers. + * 3. Initialize and enable the SDMA by writing to the SDMA's + * configuration and command registers. After completing these steps, + * the ethernet port SDMA can starts to perform Rx and Tx activities. * - * Note: Each Rx and Tx queue descriptor's list must be initialized prior - * to calling this function (use ether_init_tx_desc_ring for Tx queues - * and ether_init_rx_desc_ring for Rx queues). + * Note: Each Rx and Tx queue descriptor's list must be initialized prior + * to calling this function (use ether_init_tx_desc_ring for Tx queues + * and ether_init_rx_desc_ring for Rx queues). * * INPUT: - * struct mv64340_private *mp Ethernet port control struct + * struct mv643xx_private *mp Ethernet port control struct * * OUTPUT: - * Ethernet port is ready to receive and transmit. + * Ethernet port is ready to receive and transmit. * * RETURN: - * false if the port PHY is not up. - * true otherwise. + * None. */ -static int eth_port_start(struct mv64340_private *mp) +static void eth_port_start(struct mv643xx_private *mp) { - unsigned int eth_port_num = mp->port_num; + unsigned int port_num = mp->port_num; int tx_curr_desc, rx_curr_desc; - unsigned int phy_reg_data; /* Assignment of Tx CTRP of given queue */ tx_curr_desc = mp->tx_curr_desc_q; - MV_WRITE(MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(eth_port_num), - (struct eth_tx_desc *) mp->tx_desc_dma + tx_curr_desc); + mv_write(MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(port_num), + (u32)((struct eth_tx_desc *)mp->tx_desc_dma + tx_curr_desc)); /* Assignment of Rx CRDP of given queue */ rx_curr_desc = mp->rx_curr_desc_q; - MV_WRITE(MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(eth_port_num), - (struct eth_rx_desc *) mp->rx_desc_dma + rx_curr_desc); + mv_write(MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num), + (u32)((struct eth_rx_desc *)mp->rx_desc_dma + rx_curr_desc)); /* Add the assigned Ethernet address to the port's address table */ - eth_port_uc_addr_set(mp->port_num, mp->port_mac_addr); + eth_port_uc_addr_set(port_num, mp->port_mac_addr); /* Assign port configuration and command. */ - MV_WRITE(MV64340_ETH_PORT_CONFIG_REG(eth_port_num), - mp->port_config); + mv_write(MV643XX_ETH_PORT_CONFIG_REG(port_num), mp->port_config); - MV_WRITE(MV64340_ETH_PORT_CONFIG_EXTEND_REG(eth_port_num), - mp->port_config_extend); + mv_write(MV643XX_ETH_PORT_CONFIG_EXTEND_REG(port_num), + mp->port_config_extend); - MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num), - mp->port_serial_control); - MV_SET_REG_BITS(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num), - ETH_SERIAL_PORT_ENABLE); + /* Increase the Rx side buffer size if supporting GigE */ + if (mp->port_serial_control & MV643XX_ETH_SET_GMII_SPEED_TO_1000) + mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), + (mp->port_serial_control & 0xfff1ffff) | (0x5 << 17)); + else + mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), + mp->port_serial_control); + + mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), + mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)) | + MV643XX_ETH_SERIAL_PORT_ENABLE); /* Assign port SDMA configuration */ - MV_WRITE(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num), - mp->port_sdma_config); + mv_write(MV643XX_ETH_SDMA_CONFIG_REG(port_num), + mp->port_sdma_config); /* Enable port Rx. */ - MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port_num), - mp->port_rx_queue_command); - - /* Check if link is up */ - eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data); - - if (!(phy_reg_data & 0x20)) - return 0; - - return 1; + mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), + mp->port_rx_queue_command); } /* @@ -1784,29 +1885,29 @@ * This function Set the port Ethernet MAC address. * * INPUT: - * unsigned int eth_port_num Port number. - * char * p_addr Address to be set + * unsigned int eth_port_num Port number. + * char * p_addr Address to be set * * OUTPUT: - * Set MAC address low and high registers. also calls eth_port_uc_addr() - * To set the unicast table with the proper information. + * Set MAC address low and high registers. also calls eth_port_uc_addr() + * To set the unicast table with the proper information. * * RETURN: * N/A. * */ static void eth_port_uc_addr_set(unsigned int eth_port_num, - unsigned char *p_addr) + unsigned char *p_addr) { unsigned int mac_h; unsigned int mac_l; mac_l = (p_addr[4] << 8) | (p_addr[5]); - mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | - (p_addr[2] << 8) | (p_addr[3] << 0); + mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) | + (p_addr[3] << 0); - MV_WRITE(MV64340_ETH_MAC_ADDR_LOW(eth_port_num), mac_l); - MV_WRITE(MV64340_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h); + mv_write(MV643XX_ETH_MAC_ADDR_LOW(eth_port_num), mac_l); + mv_write(MV643XX_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h); /* Accept frames of this address */ eth_port_uc_addr(eth_port_num, p_addr[5], ACCEPT_MAC_ADDR); @@ -1815,29 +1916,64 @@ } /* + * eth_port_uc_addr_get - This function retrieves the port Unicast address + * (MAC address) from the ethernet hw registers. + * + * DESCRIPTION: + * This function retrieves the port Ethernet MAC address. + * + * INPUT: + * unsigned int eth_port_num Port number. + * char *MacAddr pointer where the MAC address is stored + * + * OUTPUT: + * Copy the MAC address to the location pointed to by MacAddr + * + * RETURN: + * N/A. + * + */ +static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *p_addr) +{ + struct mv643xx_private *mp = netdev_priv(dev); + unsigned int mac_h; + unsigned int mac_l; + + mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(mp->port_num)); + mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(mp->port_num)); + + p_addr[0] = (mac_h >> 24) & 0xff; + p_addr[1] = (mac_h >> 16) & 0xff; + p_addr[2] = (mac_h >> 8) & 0xff; + p_addr[3] = mac_h & 0xff; + p_addr[4] = (mac_l >> 8) & 0xff; + p_addr[5] = mac_l & 0xff; +} + +/* * eth_port_uc_addr - This function Set the port unicast address table * * DESCRIPTION: - * This function locates the proper entry in the Unicast table for the - * specified MAC nibble and sets its properties according to function + * This function locates the proper entry in the Unicast table for the + * specified MAC nibble and sets its properties according to function * parameters. * * INPUT: - * unsigned int eth_port_num Port number. - * unsigned char uc_nibble Unicast MAC Address last nibble. - * int option 0 = Add, 1 = remove address. + * unsigned int eth_port_num Port number. + * unsigned char uc_nibble Unicast MAC Address last nibble. + * int option 0 = Add, 1 = remove address. * * OUTPUT: * This function add/removes MAC addresses from the port unicast address - * table. + * table. * * RETURN: * true is output succeeded. * false if option parameter is invalid. * */ -static int eth_port_uc_addr(unsigned int eth_port_num, - unsigned char uc_nibble, int option) +static int eth_port_uc_addr(unsigned int eth_port_num, unsigned char uc_nibble, + int option) { unsigned int unicast_reg; unsigned int tbl_offset; @@ -1850,29 +1986,26 @@ switch (option) { case REJECT_MAC_ADDR: - /* Clear accepts frame bit at specified unicast DA table entry */ - unicast_reg = MV_READ((MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE - (eth_port_num) + tbl_offset)); + /* Clear accepts frame bit at given unicast DA table entry */ + unicast_reg = mv_read((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset)); unicast_reg &= (0x0E << (8 * reg_offset)); - MV_WRITE( - (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE - (eth_port_num) + tbl_offset), unicast_reg); + mv_write((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset), unicast_reg); break; case ACCEPT_MAC_ADDR: /* Set accepts frame bit at unicast DA filter table entry */ unicast_reg = - MV_READ( - (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE - (eth_port_num) + tbl_offset)); + mv_read((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset)); unicast_reg |= (0x01 << (8 * reg_offset)); - MV_WRITE( - (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE - (eth_port_num) + tbl_offset), unicast_reg); + mv_write((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset), unicast_reg); break; @@ -1887,17 +2020,17 @@ * eth_port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables * * DESCRIPTION: - * Go through all the DA filter tables (Unicast, Special Multicast & - * Other Multicast) and set each entry to 0. + * Go through all the DA filter tables (Unicast, Special Multicast & + * Other Multicast) and set each entry to 0. * * INPUT: - * unsigned int eth_port_num Ethernet Port number. + * unsigned int eth_port_num Ethernet Port number. * * OUTPUT: - * Multicast and Unicast packets are rejected. + * Multicast and Unicast packets are rejected. * * RETURN: - * None. + * None. */ static void eth_port_init_mac_tables(unsigned int eth_port_num) { @@ -1905,18 +2038,16 @@ /* Clear DA filter unicast table (Ex_dFUT) */ for (table_index = 0; table_index <= 0xC; table_index += 4) - MV_WRITE( - (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE - (eth_port_num) + table_index), 0); + mv_write((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + table_index), 0); for (table_index = 0; table_index <= 0xFC; table_index += 4) { /* Clear DA filter special multicast table (Ex_dFSMT) */ - MV_WRITE( - (MV64340_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE - (eth_port_num) + table_index), 0); + mv_write((MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE + (eth_port_num) + table_index), 0); /* Clear DA filter other multicast table (Ex_dFOMT) */ - MV_WRITE((MV64340_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE - (eth_port_num) + table_index), 0); + mv_write((MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE + (eth_port_num) + table_index), 0); } } @@ -1924,17 +2055,17 @@ * eth_clear_mib_counters - Clear all MIB counters * * DESCRIPTION: - * This function clears all MIB counters of a specific ethernet port. - * A read from the MIB counter will reset the counter. + * This function clears all MIB counters of a specific ethernet port. + * A read from the MIB counter will reset the counter. * * INPUT: - * unsigned int eth_port_num Ethernet Port number. + * unsigned int eth_port_num Ethernet Port number. * * OUTPUT: - * After reading all MIB counters, the counters resets. + * After reading all MIB counters, the counters resets. * * RETURN: - * MIB counter value. + * MIB counter value. * */ static void eth_clear_mib_counters(unsigned int eth_port_num) @@ -1942,72 +2073,155 @@ int i; /* Perform dummy reads from MIB counters */ - for (i = ETH_MIB_GOOD_OCTETS_RECEIVED_LOW; i < ETH_MIB_LATE_COLLISION; i += 4) - MV_READ(MV64340_ETH_MIB_COUNTERS_BASE(eth_port_num) + i); + for (i = ETH_MIB_GOOD_OCTETS_RECEIVED_LOW; i < ETH_MIB_LATE_COLLISION; + i += 4) + mv_read(MV643XX_ETH_MIB_COUNTERS_BASE(eth_port_num) + i); +} + +static inline u32 read_mib(struct mv643xx_private *mp, int offset) +{ + return mv_read(MV643XX_ETH_MIB_COUNTERS_BASE(mp->port_num) + offset); } +static void eth_update_mib_counters(struct mv643xx_private *mp) +{ + struct mv643xx_mib_counters *p = &mp->mib_counters; + int offset; + + p->good_octets_received += + read_mib(mp, ETH_MIB_GOOD_OCTETS_RECEIVED_LOW); + p->good_octets_received += + (u64)read_mib(mp, ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH) << 32; + + for (offset = ETH_MIB_BAD_OCTETS_RECEIVED; + offset <= ETH_MIB_FRAMES_1024_TO_MAX_OCTETS; + offset += 4) + *(u32 *)((char *)p + offset) = read_mib(mp, offset); + + p->good_octets_sent += read_mib(mp, ETH_MIB_GOOD_OCTETS_SENT_LOW); + p->good_octets_sent += + (u64)read_mib(mp, ETH_MIB_GOOD_OCTETS_SENT_HIGH) << 32; + + for (offset = ETH_MIB_GOOD_FRAMES_SENT; + offset <= ETH_MIB_LATE_COLLISION; + offset += 4) + *(u32 *)((char *)p + offset) = read_mib(mp, offset); +} + +/* + * ethernet_phy_detect - Detect whether a phy is present + * + * DESCRIPTION: + * This function tests whether there is a PHY present on + * the specified port. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * None + * + * RETURN: + * 0 on success + * -ENODEV on failure + * + */ +static int ethernet_phy_detect(unsigned int port_num) +{ + unsigned int phy_reg_data0; + int auto_neg; + + eth_port_read_smi_reg(port_num, 0, &phy_reg_data0); + auto_neg = phy_reg_data0 & 0x1000; + phy_reg_data0 ^= 0x1000; /* invert auto_neg */ + eth_port_write_smi_reg(port_num, 0, phy_reg_data0); + + eth_port_read_smi_reg(port_num, 0, &phy_reg_data0); + if ((phy_reg_data0 & 0x1000) == auto_neg) + return -ENODEV; /* change didn't take */ + + phy_reg_data0 ^= 0x1000; + eth_port_write_smi_reg(port_num, 0, phy_reg_data0); + return 0; +} /* * ethernet_phy_get - Get the ethernet port PHY address. * * DESCRIPTION: - * This routine returns the given ethernet port PHY address. + * This routine returns the given ethernet port PHY address. * * INPUT: - * unsigned int eth_port_num Ethernet Port number. + * unsigned int eth_port_num Ethernet Port number. * * OUTPUT: - * None. + * None. * * RETURN: - * PHY address. + * PHY address. * */ static int ethernet_phy_get(unsigned int eth_port_num) { unsigned int reg_data; - reg_data = MV_READ(MV64340_ETH_PHY_ADDR_REG); + reg_data = mv_read(MV643XX_ETH_PHY_ADDR_REG); return ((reg_data >> (5 * eth_port_num)) & 0x1f); } /* + * ethernet_phy_set - Set the ethernet port PHY address. + * + * DESCRIPTION: + * This routine sets the given ethernet port PHY address. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * int phy_addr PHY address. + * + * OUTPUT: + * None. + * + * RETURN: + * None. + * + */ +static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr) +{ + u32 reg_data; + int addr_shift = 5 * eth_port_num; + + reg_data = mv_read(MV643XX_ETH_PHY_ADDR_REG); + reg_data &= ~(0x1f << addr_shift); + reg_data |= (phy_addr & 0x1f) << addr_shift; + mv_write(MV643XX_ETH_PHY_ADDR_REG, reg_data); +} + +/* * ethernet_phy_reset - Reset Ethernet port PHY. * * DESCRIPTION: - * This routine utilize the SMI interface to reset the ethernet port PHY. - * The routine waits until the link is up again or link up is timeout. + * This routine utilizes the SMI interface to reset the ethernet port PHY. * * INPUT: - * unsigned int eth_port_num Ethernet Port number. + * unsigned int eth_port_num Ethernet Port number. * * OUTPUT: - * The ethernet port PHY renew its link. + * The PHY is reset. * * RETURN: - * None. + * None. * */ -static int ethernet_phy_reset(unsigned int eth_port_num) +static void ethernet_phy_reset(unsigned int eth_port_num) { - unsigned int time_out = 50; unsigned int phy_reg_data; /* Reset the PHY */ eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data); phy_reg_data |= 0x8000; /* Set bit 15 to reset the PHY */ eth_port_write_smi_reg(eth_port_num, 0, phy_reg_data); - - /* Poll on the PHY LINK */ - do { - eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data); - - if (time_out-- == 0) - return 0; - } while (!(phy_reg_data & 0x20)); - - return 1; } /* @@ -2015,381 +2229,358 @@ * * DESCRIPTION: * This routine resets the chip by aborting any SDMA engine activity and - * clearing the MIB counters. The Receiver and the Transmit unit are in - * idle state after this command is performed and the port is disabled. + * clearing the MIB counters. The Receiver and the Transmit unit are in + * idle state after this command is performed and the port is disabled. * * INPUT: - * unsigned int eth_port_num Ethernet Port number. + * unsigned int eth_port_num Ethernet Port number. * * OUTPUT: - * Channel activity is halted. + * Channel activity is halted. * * RETURN: - * None. + * None. * */ -static void eth_port_reset(unsigned int eth_port_num) +static void eth_port_reset(unsigned int port_num) { unsigned int reg_data; /* Stop Tx port activity. Check port Tx activity. */ - reg_data = - MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port_num)); + reg_data = mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num)); if (reg_data & 0xFF) { /* Issue stop command for active channels only */ - MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG - (eth_port_num), (reg_data << 8)); + mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), + (reg_data << 8)); /* Wait for all Tx activity to terminate. */ - do { - /* Check port cause register that all Tx queues are stopped */ - reg_data = - MV_READ - (MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG - (eth_port_num)); - } - while (reg_data & 0xFF); + /* Check port cause register that all Tx queues are stopped */ + while (mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num)) + & 0xFF) + udelay(10); } /* Stop Rx port activity. Check port Rx activity. */ - reg_data = - MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG - (eth_port_num)); + reg_data = mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num)); if (reg_data & 0xFF) { /* Issue stop command for active channels only */ - MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG - (eth_port_num), (reg_data << 8)); + mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), + (reg_data << 8)); /* Wait for all Rx activity to terminate. */ - do { - /* Check port cause register that all Rx queues are stopped */ - reg_data = - MV_READ - (MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG - (eth_port_num)); - } - while (reg_data & 0xFF); + /* Check port cause register that all Rx queues are stopped */ + while (mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num)) + & 0xFF) + udelay(10); } - /* Clear all MIB counters */ - eth_clear_mib_counters(eth_port_num); + eth_clear_mib_counters(port_num); /* Reset the Enable bit in the Configuration Register */ - reg_data = - MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG (eth_port_num)); - reg_data &= ~ETH_SERIAL_PORT_ENABLE; - MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num), reg_data); - - return; + reg_data = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); + reg_data &= ~MV643XX_ETH_SERIAL_PORT_ENABLE; + mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), reg_data); } /* * ethernet_set_config_reg - Set specified bits in configuration register. * * DESCRIPTION: - * This function sets specified bits in the given ethernet - * configuration register. + * This function sets specified bits in the given ethernet + * configuration register. * * INPUT: - * unsigned int eth_port_num Ethernet Port number. - * unsigned int value 32 bit value. + * unsigned int eth_port_num Ethernet Port number. + * unsigned int value 32 bit value. * * OUTPUT: - * The set bits in the value parameter are set in the configuration - * register. + * The set bits in the value parameter are set in the configuration + * register. * * RETURN: - * None. + * None. * */ static void ethernet_set_config_reg(unsigned int eth_port_num, - unsigned int value) + unsigned int value) { unsigned int eth_config_reg; - eth_config_reg = - MV_READ(MV64340_ETH_PORT_CONFIG_REG(eth_port_num)); + eth_config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_REG(eth_port_num)); eth_config_reg |= value; - MV_WRITE(MV64340_ETH_PORT_CONFIG_REG(eth_port_num), - eth_config_reg); + mv_write(MV643XX_ETH_PORT_CONFIG_REG(eth_port_num), eth_config_reg); +} + +static int eth_port_autoneg_supported(unsigned int eth_port_num) +{ + unsigned int phy_reg_data0; + + eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data0); + + return phy_reg_data0 & 0x1000; +} + +static int eth_port_link_is_up(unsigned int eth_port_num) +{ + unsigned int phy_reg_data1; + + eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data1); + + if (eth_port_autoneg_supported(eth_port_num)) { + if (phy_reg_data1 & 0x20) /* auto-neg complete */ + return 1; + } else if (phy_reg_data1 & 0x4) /* link up */ + return 1; + + return 0; } /* * ethernet_get_config_reg - Get the port configuration register * * DESCRIPTION: - * This function returns the configuration register value of the given - * ethernet port. + * This function returns the configuration register value of the given + * ethernet port. * * INPUT: - * unsigned int eth_port_num Ethernet Port number. + * unsigned int eth_port_num Ethernet Port number. * * OUTPUT: - * None. + * None. * * RETURN: - * Port configuration register value. + * Port configuration register value. */ static unsigned int ethernet_get_config_reg(unsigned int eth_port_num) { unsigned int eth_config_reg; - eth_config_reg = MV_READ(MV64340_ETH_PORT_CONFIG_EXTEND_REG - (eth_port_num)); + eth_config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_EXTEND_REG + (eth_port_num)); return eth_config_reg; } - /* * eth_port_read_smi_reg - Read PHY registers * * DESCRIPTION: - * This routine utilize the SMI interface to interact with the PHY in - * order to perform PHY register read. + * This routine utilize the SMI interface to interact with the PHY in + * order to perform PHY register read. * * INPUT: - * unsigned int eth_port_num Ethernet Port number. - * unsigned int phy_reg PHY register address offset. - * unsigned int *value Register value buffer. + * unsigned int port_num Ethernet Port number. + * unsigned int phy_reg PHY register address offset. + * unsigned int *value Register value buffer. * * OUTPUT: - * Write the value of a specified PHY register into given buffer. + * Write the value of a specified PHY register into given buffer. * * RETURN: - * false if the PHY is busy or read data is not in valid state. - * true otherwise. + * false if the PHY is busy or read data is not in valid state. + * true otherwise. * */ -static int eth_port_read_smi_reg(unsigned int eth_port_num, - unsigned int phy_reg, unsigned int *value) +static void eth_port_read_smi_reg(unsigned int port_num, + unsigned int phy_reg, unsigned int *value) { - int phy_addr = ethernet_phy_get(eth_port_num); - unsigned int time_out = PHY_BUSY_TIMEOUT; - unsigned int reg_value; - - /* first check that it is not busy */ - do { - reg_value = MV_READ(MV64340_ETH_SMI_REG); - if (time_out-- == 0) - return 0; - } while (reg_value & ETH_SMI_BUSY); - - /* not busy */ - - MV_WRITE(MV64340_ETH_SMI_REG, - (phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ); - - time_out = PHY_BUSY_TIMEOUT; /* initialize the time out var again */ + int phy_addr = ethernet_phy_get(port_num); + unsigned long flags; + int i; - do { - reg_value = MV_READ(MV64340_ETH_SMI_REG); - if (time_out-- == 0) - return 0; - } while (reg_value & ETH_SMI_READ_VALID); + /* the SMI register is a shared resource */ + spin_lock_irqsave(&mv643xx_eth_phy_lock, flags); - /* Wait for the data to update in the SMI register */ - for (time_out = 0; time_out < PHY_BUSY_TIMEOUT; time_out++); + /* wait for the SMI register to become available */ + for (i = 0; mv_read(MV643XX_ETH_SMI_REG) & ETH_SMI_BUSY; i++) { + if (i == PHY_WAIT_ITERATIONS) { + printk("mv643xx PHY busy timeout, port %d\n", port_num); + goto out; + } + udelay(PHY_WAIT_MICRO_SECONDS); + } - reg_value = MV_READ(MV64340_ETH_SMI_REG); + mv_write(MV643XX_ETH_SMI_REG, + (phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ); - *value = reg_value & 0xffff; + /* now wait for the data to be valid */ + for (i = 0; !(mv_read(MV643XX_ETH_SMI_REG) & ETH_SMI_READ_VALID); i++) { + if (i == PHY_WAIT_ITERATIONS) { + printk("mv643xx PHY read timeout, port %d\n", port_num); + goto out; + } + udelay(PHY_WAIT_MICRO_SECONDS); + } - return 1; + *value = mv_read(MV643XX_ETH_SMI_REG) & 0xffff; +out: + spin_unlock_irqrestore(&mv643xx_eth_phy_lock, flags); } /* * eth_port_write_smi_reg - Write to PHY registers * * DESCRIPTION: - * This routine utilize the SMI interface to interact with the PHY in - * order to perform writes to PHY registers. + * This routine utilize the SMI interface to interact with the PHY in + * order to perform writes to PHY registers. * * INPUT: - * unsigned int eth_port_num Ethernet Port number. - * unsigned int phy_reg PHY register address offset. - * unsigned int value Register value. + * unsigned int eth_port_num Ethernet Port number. + * unsigned int phy_reg PHY register address offset. + * unsigned int value Register value. * * OUTPUT: - * Write the given value to the specified PHY register. + * Write the given value to the specified PHY register. * * RETURN: - * false if the PHY is busy. - * true otherwise. + * false if the PHY is busy. + * true otherwise. * */ -static int eth_port_write_smi_reg(unsigned int eth_port_num, - unsigned int phy_reg, unsigned int value) +static void eth_port_write_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, unsigned int value) { - unsigned int time_out = PHY_BUSY_TIMEOUT; - unsigned int reg_value; int phy_addr; + int i; + unsigned long flags; phy_addr = ethernet_phy_get(eth_port_num); - /* first check that it is not busy */ - do { - reg_value = MV_READ(MV64340_ETH_SMI_REG); - if (time_out-- == 0) - return 0; - } while (reg_value & ETH_SMI_BUSY); - - /* not busy */ - MV_WRITE(MV64340_ETH_SMI_REG, (phy_addr << 16) | (phy_reg << 21) | - ETH_SMI_OPCODE_WRITE | (value & 0xffff)); + /* the SMI register is a shared resource */ + spin_lock_irqsave(&mv643xx_eth_phy_lock, flags); - return 1; + /* wait for the SMI register to become available */ + for (i = 0; mv_read(MV643XX_ETH_SMI_REG) & ETH_SMI_BUSY; i++) { + if (i == PHY_WAIT_ITERATIONS) { + printk("mv643xx PHY busy timeout, port %d\n", + eth_port_num); + goto out; + } + udelay(PHY_WAIT_MICRO_SECONDS); + } + + mv_write(MV643XX_ETH_SMI_REG, (phy_addr << 16) | (phy_reg << 21) | + ETH_SMI_OPCODE_WRITE | (value & 0xffff)); +out: + spin_unlock_irqrestore(&mv643xx_eth_phy_lock, flags); } /* * eth_port_send - Send an Ethernet packet * * DESCRIPTION: - * This routine send a given packet described by p_pktinfo parameter. It - * supports transmitting of a packet spaned over multiple buffers. The - * routine updates 'curr' and 'first' indexes according to the packet - * segment passed to the routine. In case the packet segment is first, - * the 'first' index is update. In any case, the 'curr' index is updated. - * If the routine get into Tx resource error it assigns 'curr' index as - * 'first'. This way the function can abort Tx process of multiple - * descriptors per packet. + * This routine send a given packet described by p_pktinfo parameter. It + * supports transmitting of a packet spaned over multiple buffers. The + * routine updates 'curr' and 'first' indexes according to the packet + * segment passed to the routine. In case the packet segment is first, + * the 'first' index is update. In any case, the 'curr' index is updated. + * If the routine get into Tx resource error it assigns 'curr' index as + * 'first'. This way the function can abort Tx process of multiple + * descriptors per packet. * * INPUT: - * struct mv64340_private *mp Ethernet Port Control srtuct. - * struct pkt_info *p_pkt_info User packet buffer. + * struct mv643xx_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info User packet buffer. * * OUTPUT: - * Tx ring 'curr' and 'first' indexes are updated. + * Tx ring 'curr' and 'first' indexes are updated. * * RETURN: - * ETH_QUEUE_FULL in case of Tx resource error. + * ETH_QUEUE_FULL in case of Tx resource error. * ETH_ERROR in case the routine can not access Tx desc ring. * ETH_QUEUE_LAST_RESOURCE if the routine uses the last Tx resource. - * ETH_OK otherwise. + * ETH_OK otherwise. * */ -#ifdef MV64340_CHECKSUM_OFFLOAD_TX +#ifdef MV643XX_CHECKSUM_OFFLOAD_TX /* * Modified to include the first descriptor pointer in case of SG */ -static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private * mp, - struct pkt_info * p_pkt_info) +static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, + struct pkt_info *p_pkt_info) { int tx_desc_curr, tx_desc_used, tx_first_desc, tx_next_desc; - volatile struct eth_tx_desc *current_descriptor; - volatile struct eth_tx_desc *first_descriptor; - u32 command_status, first_chip_ptr; + struct eth_tx_desc *current_descriptor; + struct eth_tx_desc *first_descriptor; + u32 command; /* Do not process Tx ring in case of Tx ring resource error */ if (mp->tx_resource_err) return ETH_QUEUE_FULL; + /* + * The hardware requires that each buffer that is <= 8 bytes + * in length must be aligned on an 8 byte boundary. + */ + if (p_pkt_info->byte_cnt <= 8 && p_pkt_info->buf_ptr & 0x7) { + printk(KERN_ERR + "mv643xx_eth port %d: packet size <= 8 problem\n", + mp->port_num); + return ETH_ERROR; + } + /* Get the Tx Desc ring indexes */ tx_desc_curr = mp->tx_curr_desc_q; tx_desc_used = mp->tx_used_desc_q; current_descriptor = &mp->p_tx_desc_area[tx_desc_curr]; - if (current_descriptor == NULL) - return ETH_ERROR; - tx_next_desc = (tx_desc_curr + 1) % MV64340_TX_QUEUE_SIZE; - command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC; + tx_next_desc = (tx_desc_curr + 1) % mp->tx_ring_size; + + current_descriptor->buf_ptr = p_pkt_info->buf_ptr; + current_descriptor->byte_cnt = p_pkt_info->byte_cnt; + current_descriptor->l4i_chk = p_pkt_info->l4i_chk; + mp->tx_skb[tx_desc_curr] = p_pkt_info->return_info; - if (command_status & ETH_TX_FIRST_DESC) { + command = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC | + ETH_BUFFER_OWNED_BY_DMA; + if (command & ETH_TX_FIRST_DESC) { tx_first_desc = tx_desc_curr; mp->tx_first_desc_q = tx_first_desc; + first_descriptor = current_descriptor; + mp->tx_first_command = command; + } else { + tx_first_desc = mp->tx_first_desc_q; + first_descriptor = &mp->p_tx_desc_area[tx_first_desc]; + BUG_ON(first_descriptor == NULL); + current_descriptor->cmd_sts = command; + } - /* fill first descriptor */ - first_descriptor = &mp->p_tx_desc_area[tx_desc_curr]; - first_descriptor->l4i_chk = p_pkt_info->l4i_chk; - first_descriptor->cmd_sts = command_status; - first_descriptor->byte_cnt = p_pkt_info->byte_cnt; - first_descriptor->buf_ptr = p_pkt_info->buf_ptr; - first_descriptor->next_desc_ptr = mp->tx_desc_dma + - tx_next_desc * sizeof(struct eth_tx_desc); + if (command & ETH_TX_LAST_DESC) { wmb(); - } else { - tx_first_desc = mp->tx_first_desc_q; - first_descriptor = &mp->p_tx_desc_area[tx_first_desc]; - if (first_descriptor == NULL) { - printk("First desc is NULL !!\n"); - return ETH_ERROR; - } - if (command_status & ETH_TX_LAST_DESC) - current_descriptor->next_desc_ptr = 0x00000000; - else { - command_status |= ETH_BUFFER_OWNED_BY_DMA; - current_descriptor->next_desc_ptr = mp->tx_desc_dma + - tx_next_desc * sizeof(struct eth_tx_desc); - } - } - - if (p_pkt_info->byte_cnt < 8) { - printk(" < 8 problem \n"); - return ETH_ERROR; - } - - current_descriptor->buf_ptr = p_pkt_info->buf_ptr; - current_descriptor->byte_cnt = p_pkt_info->byte_cnt; - current_descriptor->l4i_chk = p_pkt_info->l4i_chk; - current_descriptor->cmd_sts = command_status; - - mp->tx_skb[tx_desc_curr] = (struct sk_buff*) p_pkt_info->return_info; - - wmb(); - - /* Set last desc with DMA ownership and interrupt enable. */ - if (command_status & ETH_TX_LAST_DESC) { - current_descriptor->cmd_sts = command_status | - ETH_TX_ENABLE_INTERRUPT | - ETH_BUFFER_OWNED_BY_DMA; + first_descriptor->cmd_sts = mp->tx_first_command; - if (!(command_status & ETH_TX_FIRST_DESC)) - first_descriptor->cmd_sts |= ETH_BUFFER_OWNED_BY_DMA; wmb(); - - first_chip_ptr = MV_READ(MV64340_ETH_CURRENT_SERVED_TX_DESC_PTR(mp->port_num)); - - /* Apply send command */ - if (first_chip_ptr == 0x00000000) - MV_WRITE(MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(mp->port_num), (struct eth_tx_desc *) mp->tx_desc_dma + tx_first_desc); - - ETH_ENABLE_TX_QUEUE(mp->port_num); + ETH_ENABLE_TX_QUEUE(mp->port_num); /* * Finish Tx packet. Update first desc in case of Tx resource * error */ - tx_first_desc = tx_next_desc; - mp->tx_first_desc_q = tx_first_desc; - } else { - if (! (command_status & ETH_TX_FIRST_DESC) ) { - current_descriptor->cmd_sts = command_status; - wmb(); - } + tx_first_desc = tx_next_desc; + mp->tx_first_desc_q = tx_first_desc; } - /* Check for ring index overlap in the Tx desc ring */ - if (tx_next_desc == tx_desc_used) { - mp->tx_resource_err = 1; - mp->tx_curr_desc_q = tx_first_desc; + /* Check for ring index overlap in the Tx desc ring */ + if (tx_next_desc == tx_desc_used) { + mp->tx_resource_err = 1; + mp->tx_curr_desc_q = tx_first_desc; - return ETH_QUEUE_LAST_RESOURCE; + return ETH_QUEUE_LAST_RESOURCE; } - mp->tx_curr_desc_q = tx_next_desc; - wmb(); + mp->tx_curr_desc_q = tx_next_desc; - return ETH_OK; + return ETH_OK; } #else -static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private * mp, - struct pkt_info * p_pkt_info) +static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, + struct pkt_info *p_pkt_info) { int tx_desc_curr; int tx_desc_used; - volatile struct eth_tx_desc* current_descriptor; + struct eth_tx_desc *current_descriptor; unsigned int command_status; /* Do not process Tx ring in case of Tx ring resource error */ @@ -2401,39 +2592,24 @@ tx_desc_used = mp->tx_used_desc_q; current_descriptor = &mp->p_tx_desc_area[tx_desc_curr]; - if (current_descriptor == NULL) - return ETH_ERROR; - command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC; - -/* XXX Is this for real ?!?!? */ - /* Buffers with a payload smaller than 8 bytes must be aligned to a - * 64-bit boundary. We use the memory allocated for Tx descriptor. - * This memory is located in TX_BUF_OFFSET_IN_DESC offset within the - * Tx descriptor. */ - if (p_pkt_info->byte_cnt <= 8) { - printk(KERN_ERR - "You have failed in the < 8 bytes errata - fixme\n"); - return ETH_ERROR; - } current_descriptor->buf_ptr = p_pkt_info->buf_ptr; current_descriptor->byte_cnt = p_pkt_info->byte_cnt; - mp->tx_skb[tx_desc_curr] = (struct sk_buff *) p_pkt_info->return_info; - - mb(); + mp->tx_skb[tx_desc_curr] = p_pkt_info->return_info; /* Set last desc with DMA ownership and interrupt enable. */ + wmb(); current_descriptor->cmd_sts = command_status | ETH_BUFFER_OWNED_BY_DMA | ETH_TX_ENABLE_INTERRUPT; - /* Apply send command */ + wmb(); ETH_ENABLE_TX_QUEUE(mp->port_num); /* Finish Tx packet. Update first desc in case of Tx resource error */ - tx_desc_curr = (tx_desc_curr + 1) % MV64340_TX_QUEUE_SIZE; + tx_desc_curr = (tx_desc_curr + 1) % mp->tx_ring_size; /* Update the current descriptor */ - mp->tx_curr_desc_q = tx_desc_curr; + mp->tx_curr_desc_q = tx_desc_curr; /* Check for ring index overlap in the Tx desc ring */ if (tx_desc_curr == tx_desc_used) { @@ -2450,62 +2626,55 @@ * * DESCRIPTION: * This routine returns the transmitted packet information to the caller. - * It uses the 'first' index to support Tx desc return in case a transmit - * of a packet spanned over multiple buffer still in process. - * In case the Tx queue was in "resource error" condition, where there are - * no available Tx resources, the function resets the resource error flag. + * It uses the 'first' index to support Tx desc return in case a transmit + * of a packet spanned over multiple buffer still in process. + * In case the Tx queue was in "resource error" condition, where there are + * no available Tx resources, the function resets the resource error flag. * * INPUT: - * struct mv64340_private *mp Ethernet Port Control srtuct. - * struct pkt_info *p_pkt_info User packet buffer. + * struct mv643xx_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info User packet buffer. * * OUTPUT: - * Tx ring 'first' and 'used' indexes are updated. + * Tx ring 'first' and 'used' indexes are updated. * * RETURN: * ETH_ERROR in case the routine can not access Tx desc ring. - * ETH_RETRY in case there is transmission in process. + * ETH_RETRY in case there is transmission in process. * ETH_END_OF_JOB if the routine has nothing to release. - * ETH_OK otherwise. + * ETH_OK otherwise. * */ -static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv64340_private * mp, - struct pkt_info * p_pkt_info) +static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp, + struct pkt_info *p_pkt_info) { - int tx_desc_used, tx_desc_curr; -#ifdef MV64340_CHECKSUM_OFFLOAD_TX - int tx_first_desc; + int tx_desc_used; +#ifdef MV643XX_CHECKSUM_OFFLOAD_TX + int tx_busy_desc = mp->tx_first_desc_q; +#else + int tx_busy_desc = mp->tx_curr_desc_q; #endif - volatile struct eth_tx_desc *p_tx_desc_used; + struct eth_tx_desc *p_tx_desc_used; unsigned int command_status; /* Get the Tx Desc ring indexes */ - tx_desc_curr = mp->tx_curr_desc_q; tx_desc_used = mp->tx_used_desc_q; -#ifdef MV64340_CHECKSUM_OFFLOAD_TX - tx_first_desc = mp->tx_first_desc_q; -#endif + p_tx_desc_used = &mp->p_tx_desc_area[tx_desc_used]; - /* XXX Sanity check */ + /* Sanity check */ if (p_tx_desc_used == NULL) return ETH_ERROR; + /* Stop release. About to overlap the current available Tx descriptor */ + if (tx_desc_used == tx_busy_desc && !mp->tx_resource_err) + return ETH_END_OF_JOB; + command_status = p_tx_desc_used->cmd_sts; /* Still transmitting... */ -#ifndef MV64340_CHECKSUM_OFFLOAD_TX if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) return ETH_RETRY; -#endif - /* Stop release. About to overlap the current available Tx descriptor */ -#ifdef MV64340_CHECKSUM_OFFLOAD_TX - if (tx_desc_used == tx_first_desc && !mp->tx_resource_err) - return ETH_END_OF_JOB; -#else - if (tx_desc_used == tx_desc_curr && !mp->tx_resource_err) - return ETH_END_OF_JOB; -#endif /* Pass the packet information to the caller */ p_pkt_info->cmd_sts = command_status; @@ -2513,7 +2682,7 @@ mp->tx_skb[tx_desc_used] = NULL; /* Update the next descriptor to release. */ - mp->tx_used_desc_q = (tx_desc_used + 1) % MV64340_TX_QUEUE_SIZE; + mp->tx_used_desc_q = (tx_desc_used + 1) % mp->tx_ring_size; /* Any Tx return cancels the Tx resource error status */ mp->tx_resource_err = 0; @@ -2525,30 +2694,30 @@ * eth_port_receive - Get received information from Rx ring. * * DESCRIPTION: - * This routine returns the received data to the caller. There is no - * data copying during routine operation. All information is returned - * using pointer to packet information struct passed from the caller. - * If the routine exhausts Rx ring resources then the resource error flag - * is set. + * This routine returns the received data to the caller. There is no + * data copying during routine operation. All information is returned + * using pointer to packet information struct passed from the caller. + * If the routine exhausts Rx ring resources then the resource error flag + * is set. * * INPUT: - * struct mv64340_private *mp Ethernet Port Control srtuct. - * struct pkt_info *p_pkt_info User packet buffer. + * struct mv643xx_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info User packet buffer. * * OUTPUT: - * Rx ring current and used indexes are updated. + * Rx ring current and used indexes are updated. * * RETURN: * ETH_ERROR in case the routine can not access Rx desc ring. * ETH_QUEUE_FULL if Rx ring resources are exhausted. * ETH_END_OF_JOB if there is no received data. - * ETH_OK otherwise. + * ETH_OK otherwise. */ -static ETH_FUNC_RET_STATUS eth_port_receive(struct mv64340_private * mp, - struct pkt_info * p_pkt_info) +static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp, + struct pkt_info *p_pkt_info) { int rx_next_curr_desc, rx_curr_desc, rx_used_desc; - volatile struct eth_rx_desc * p_rx_desc; + volatile struct eth_rx_desc *p_rx_desc; unsigned int command_status; /* Do not process Rx ring in case of Rx ring resource error */ @@ -2563,6 +2732,7 @@ /* The following parameters are used to save readings from memory */ command_status = p_rx_desc->cmd_sts; + rmb(); /* Nothing to receive... */ if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) @@ -2575,18 +2745,17 @@ p_pkt_info->l4i_chk = p_rx_desc->buf_size; /* Clean the return info field to indicate that the packet has been */ - /* moved to the upper layers */ + /* moved to the upper layers */ mp->rx_skb[rx_curr_desc] = NULL; /* Update current index in data structure */ - rx_next_curr_desc = (rx_curr_desc + 1) % MV64340_RX_QUEUE_SIZE; + rx_next_curr_desc = (rx_curr_desc + 1) % mp->rx_ring_size; mp->rx_curr_desc_q = rx_next_curr_desc; /* Rx descriptors exhausted. Set the Rx ring resource error flag */ if (rx_next_curr_desc == rx_used_desc) mp->rx_resource_err = 1; - mb(); return ETH_OK; } @@ -2594,27 +2763,27 @@ * eth_rx_return_buff - Returns a Rx buffer back to the Rx ring. * * DESCRIPTION: - * This routine returns a Rx buffer back to the Rx ring. It retrieves the - * next 'used' descriptor and attached the returned buffer to it. - * In case the Rx ring was in "resource error" condition, where there are - * no available Rx resources, the function resets the resource error flag. + * This routine returns a Rx buffer back to the Rx ring. It retrieves the + * next 'used' descriptor and attached the returned buffer to it. + * In case the Rx ring was in "resource error" condition, where there are + * no available Rx resources, the function resets the resource error flag. * * INPUT: - * struct mv64340_private *mp Ethernet Port Control srtuct. - * struct pkt_info *p_pkt_info Information on the returned buffer. + * struct mv643xx_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info Information on returned buffer. * * OUTPUT: * New available Rx resource in Rx descriptor ring. * * RETURN: * ETH_ERROR in case the routine can not access Rx desc ring. - * ETH_OK otherwise. + * ETH_OK otherwise. */ -static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv64340_private * mp, - struct pkt_info * p_pkt_info) +static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv643xx_private *mp, + struct pkt_info *p_pkt_info) { int used_rx_desc; /* Where to return Rx resource */ - volatile struct eth_rx_desc* p_used_rx_desc; + volatile struct eth_rx_desc *p_used_rx_desc; /* Get 'used' Rx descriptor */ used_rx_desc = mp->rx_used_desc_q; @@ -2625,20 +2794,240 @@ mp->rx_skb[used_rx_desc] = p_pkt_info->return_info; /* Flush the write pipe */ - mb(); /* Return the descriptor to DMA ownership */ + wmb(); p_used_rx_desc->cmd_sts = - ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT; - - /* Flush descriptor and CPU pipe */ - mb(); + ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT; + wmb(); /* Move the used descriptor pointer to the next descriptor */ - mp->rx_used_desc_q = (used_rx_desc + 1) % MV64340_RX_QUEUE_SIZE; + mp->rx_used_desc_q = (used_rx_desc + 1) % mp->rx_ring_size; /* Any Rx return cancels the Rx resource error status */ mp->rx_resource_err = 0; return ETH_OK; } + +/************* Begin ethtool support *************************/ + +struct mv643xx_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define MV643XX_STAT(m) sizeof(((struct mv643xx_private *)0)->m), \ + offsetof(struct mv643xx_private, m) + +static const struct mv643xx_stats mv643xx_gstrings_stats[] = { + { "rx_packets", MV643XX_STAT(stats.rx_packets) }, + { "tx_packets", MV643XX_STAT(stats.tx_packets) }, + { "rx_bytes", MV643XX_STAT(stats.rx_bytes) }, + { "tx_bytes", MV643XX_STAT(stats.tx_bytes) }, + { "rx_errors", MV643XX_STAT(stats.rx_errors) }, + { "tx_errors", MV643XX_STAT(stats.tx_errors) }, + { "rx_dropped", MV643XX_STAT(stats.rx_dropped) }, + { "tx_dropped", MV643XX_STAT(stats.tx_dropped) }, + { "good_octets_received", MV643XX_STAT(mib_counters.good_octets_received) }, + { "bad_octets_received", MV643XX_STAT(mib_counters.bad_octets_received) }, + { "internal_mac_transmit_err", MV643XX_STAT(mib_counters.internal_mac_transmit_err) }, + { "good_frames_received", MV643XX_STAT(mib_counters.good_frames_received) }, + { "bad_frames_received", MV643XX_STAT(mib_counters.bad_frames_received) }, + { "broadcast_frames_received", MV643XX_STAT(mib_counters.broadcast_frames_received) }, + { "multicast_frames_received", MV643XX_STAT(mib_counters.multicast_frames_received) }, + { "frames_64_octets", MV643XX_STAT(mib_counters.frames_64_octets) }, + { "frames_65_to_127_octets", MV643XX_STAT(mib_counters.frames_65_to_127_octets) }, + { "frames_128_to_255_octets", MV643XX_STAT(mib_counters.frames_128_to_255_octets) }, + { "frames_256_to_511_octets", MV643XX_STAT(mib_counters.frames_256_to_511_octets) }, + { "frames_512_to_1023_octets", MV643XX_STAT(mib_counters.frames_512_to_1023_octets) }, + { "frames_1024_to_max_octets", MV643XX_STAT(mib_counters.frames_1024_to_max_octets) }, + { "good_octets_sent", MV643XX_STAT(mib_counters.good_octets_sent) }, + { "good_frames_sent", MV643XX_STAT(mib_counters.good_frames_sent) }, + { "excessive_collision", MV643XX_STAT(mib_counters.excessive_collision) }, + { "multicast_frames_sent", MV643XX_STAT(mib_counters.multicast_frames_sent) }, + { "broadcast_frames_sent", MV643XX_STAT(mib_counters.broadcast_frames_sent) }, + { "unrec_mac_control_received", MV643XX_STAT(mib_counters.unrec_mac_control_received) }, + { "fc_sent", MV643XX_STAT(mib_counters.fc_sent) }, + { "good_fc_received", MV643XX_STAT(mib_counters.good_fc_received) }, + { "bad_fc_received", MV643XX_STAT(mib_counters.bad_fc_received) }, + { "undersize_received", MV643XX_STAT(mib_counters.undersize_received) }, + { "fragments_received", MV643XX_STAT(mib_counters.fragments_received) }, + { "oversize_received", MV643XX_STAT(mib_counters.oversize_received) }, + { "jabber_received", MV643XX_STAT(mib_counters.jabber_received) }, + { "mac_receive_error", MV643XX_STAT(mib_counters.mac_receive_error) }, + { "bad_crc_event", MV643XX_STAT(mib_counters.bad_crc_event) }, + { "collision", MV643XX_STAT(mib_counters.collision) }, + { "late_collision", MV643XX_STAT(mib_counters.late_collision) }, +}; + +#define MV643XX_STATS_LEN \ + sizeof(mv643xx_gstrings_stats) / sizeof(struct mv643xx_stats) + +static int +mv643xx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) +{ + struct mv643xx_private *mp = netdev->priv; + int port_num = mp->port_num; + int autoneg = eth_port_autoneg_supported(port_num); + int mode_10_bit; + int auto_duplex; + int half_duplex = 0; + int full_duplex = 0; + int auto_speed; + int speed_10 = 0; + int speed_100 = 0; + int speed_1000 = 0; + + u32 pcs = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); + u32 psr = mv_read(MV643XX_ETH_PORT_STATUS_REG(port_num)); + + mode_10_bit = psr & MV643XX_ETH_PORT_STATUS_MODE_10_BIT; + + if (mode_10_bit) { + ecmd->supported = SUPPORTED_10baseT_Half; + } else { + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + (autoneg ? SUPPORTED_Autoneg : 0) | + SUPPORTED_TP); + + auto_duplex = !(pcs & MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX); + auto_speed = !(pcs & MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII); + + ecmd->advertising = ADVERTISED_TP; + + if (autoneg) { + ecmd->advertising |= ADVERTISED_Autoneg; + + if (auto_duplex) { + half_duplex = 1; + full_duplex = 1; + } else { + if (pcs & MV643XX_ETH_SET_FULL_DUPLEX_MODE) + full_duplex = 1; + else + half_duplex = 1; + } + + if (auto_speed) { + speed_10 = 1; + speed_100 = 1; + speed_1000 = 1; + } else { + if (pcs & MV643XX_ETH_SET_GMII_SPEED_TO_1000) + speed_1000 = 1; + else if (pcs & MV643XX_ETH_SET_MII_SPEED_TO_100) + speed_100 = 1; + else + speed_10 = 1; + } + + if (speed_10 & half_duplex) + ecmd->advertising |= ADVERTISED_10baseT_Half; + if (speed_10 & full_duplex) + ecmd->advertising |= ADVERTISED_10baseT_Full; + if (speed_100 & half_duplex) + ecmd->advertising |= ADVERTISED_100baseT_Half; + if (speed_100 & full_duplex) + ecmd->advertising |= ADVERTISED_100baseT_Full; + if (speed_1000) + ecmd->advertising |= ADVERTISED_1000baseT_Full; + } + } + + ecmd->port = PORT_TP; + ecmd->phy_address = ethernet_phy_get(port_num); + + ecmd->transceiver = XCVR_EXTERNAL; + + if (netif_carrier_ok(netdev)) { + if (mode_10_bit) + ecmd->speed = SPEED_10; + else { + if (psr & MV643XX_ETH_PORT_STATUS_GMII_1000) + ecmd->speed = SPEED_1000; + else if (psr & MV643XX_ETH_PORT_STATUS_MII_100) + ecmd->speed = SPEED_100; + else + ecmd->speed = SPEED_10; + } + + if (psr & MV643XX_ETH_PORT_STATUS_FULL_DUPLEX) + ecmd->duplex = DUPLEX_FULL; + else + ecmd->duplex = DUPLEX_HALF; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + + ecmd->autoneg = autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE; + return 0; +} + +static void +mv643xx_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + strncpy(drvinfo->driver, mv643xx_driver_name, 32); + strncpy(drvinfo->version, mv643xx_driver_version, 32); + strncpy(drvinfo->fw_version, "N/A", 32); + strncpy(drvinfo->bus_info, "mv643xx", 32); + drvinfo->n_stats = MV643XX_STATS_LEN; +} + +static int +mv643xx_get_stats_count(struct net_device *netdev) +{ + return MV643XX_STATS_LEN; +} + +static void +mv643xx_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, uint64_t *data) +{ + struct mv643xx_private *mp = netdev->priv; + int i; + + eth_update_mib_counters(mp); + + for(i = 0; i < MV643XX_STATS_LEN; i++) { + char *p = (char *)mp+mv643xx_gstrings_stats[i].stat_offset; + data[i] = (mv643xx_gstrings_stats[i].sizeof_stat == + sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p; + } +} + +static void +mv643xx_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) +{ + int i; + + switch(stringset) { + case ETH_SS_STATS: + for (i=0; i < MV643XX_STATS_LEN; i++) { + memcpy(data + i * ETH_GSTRING_LEN, + mv643xx_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + } + break; + } +} + +static struct ethtool_ops mv643xx_ethtool_ops = { + .get_settings = mv643xx_get_settings, + .get_drvinfo = mv643xx_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_strings = mv643xx_get_strings, + .get_stats_count = mv643xx_get_stats_count, + .get_ethtool_stats = mv643xx_get_ethtool_stats, +}; + +/************* End ethtool support *************************/ diff -Nru a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h --- a/drivers/net/mv643xx_eth.h 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/mv643xx_eth.h 2005-03-08 14:29:45 -05:00 @@ -1,5 +1,5 @@ -#ifndef __MV64340_ETH_H__ -#define __MV64340_ETH_H__ +#ifndef __MV643XX_ETH_H__ +#define __MV643XX_ETH_H__ #include #include @@ -46,17 +46,16 @@ * The first part is the high level driver of the gigE ethernet ports. */ -#define ETH_PORT0_IRQ_NUM 48 /* main high register, bit0 */ -#define ETH_PORT1_IRQ_NUM ETH_PORT0_IRQ_NUM+1 /* main high register, bit1 */ -#define ETH_PORT2_IRQ_NUM ETH_PORT0_IRQ_NUM+2 /* main high register, bit1 */ - -/* Checksum offload for Tx works */ -#define MV64340_CHECKSUM_OFFLOAD_TX -#define MV64340_NAPI -#define MV64340_TX_FAST_REFILL -#undef MV64340_COAL +/* Checksum offload for Tx works for most packets, but + * fails if previous packet sent did not use hw csum + */ +#undef MV643XX_CHECKSUM_OFFLOAD_TX +#define MV643XX_NAPI +#define MV643XX_TX_FAST_REFILL +#undef MV643XX_RX_QUEUE_FILL_ON_TASK /* Does not work, yet */ +#undef MV643XX_COAL -/* +/* * Number of RX / TX descriptors on RX / TX rings. * Note that allocating RX descriptors is done by allocating the RX * ring AND a preallocated RX buffers (skb's) for each descriptor. @@ -65,89 +64,35 @@ */ /* Default TX ring size is 1000 descriptors */ -#define MV64340_TX_QUEUE_SIZE 1000 +#define MV643XX_DEFAULT_TX_QUEUE_SIZE 1000 /* Default RX ring size is 400 descriptors */ -#define MV64340_RX_QUEUE_SIZE 400 +#define MV643XX_DEFAULT_RX_QUEUE_SIZE 400 -#define MV64340_TX_COAL 100 -#ifdef MV64340_COAL -#define MV64340_RX_COAL 100 +#define MV643XX_TX_COAL 100 +#ifdef MV643XX_COAL +#define MV643XX_RX_COAL 100 #endif - /* - * The second part is the low level driver of the gigE ethernet ports. * + * The second part is the low level driver of the gigE ethernet ports. */ - /* - * Header File for : MV-643xx network interface header + * Header File for : MV-643xx network interface header * * DESCRIPTION: - * This header file contains macros typedefs and function declaration for - * the Marvell Gig Bit Ethernet Controller. + * This header file contains macros typedefs and function declaration for + * the Marvell Gig Bit Ethernet Controller. * * DEPENDENCIES: - * None. + * None. * */ -/* Default port configuration value */ -#define PORT_CONFIG_VALUE \ - ETH_UNICAST_NORMAL_MODE | \ - ETH_DEFAULT_RX_QUEUE_0 | \ - ETH_DEFAULT_RX_ARP_QUEUE_0 | \ - ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP | \ - ETH_RECEIVE_BC_IF_IP | \ - ETH_RECEIVE_BC_IF_ARP | \ - ETH_CAPTURE_TCP_FRAMES_DIS | \ - ETH_CAPTURE_UDP_FRAMES_DIS | \ - ETH_DEFAULT_RX_TCP_QUEUE_0 | \ - ETH_DEFAULT_RX_UDP_QUEUE_0 | \ - ETH_DEFAULT_RX_BPDU_QUEUE_0 - -/* Default port extend configuration value */ -#define PORT_CONFIG_EXTEND_VALUE \ - ETH_SPAN_BPDU_PACKETS_AS_NORMAL | \ - ETH_PARTITION_DISABLE - - -/* Default sdma control value */ -#define PORT_SDMA_CONFIG_VALUE \ - ETH_RX_BURST_SIZE_16_64BIT | \ - GT_ETH_IPG_INT_RX(0) | \ - ETH_TX_BURST_SIZE_16_64BIT; - -#define GT_ETH_IPG_INT_RX(value) \ - ((value & 0x3fff) << 8) - -/* Default port serial control value */ -#define PORT_SERIAL_CONTROL_VALUE \ - ETH_FORCE_LINK_PASS | \ - ETH_ENABLE_AUTO_NEG_FOR_DUPLX | \ - ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL | \ - ETH_ADV_SYMMETRIC_FLOW_CTRL | \ - ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX | \ - ETH_FORCE_BP_MODE_NO_JAM | \ - BIT9 | \ - ETH_DO_NOT_FORCE_LINK_FAIL | \ - ETH_RETRANSMIT_16_ATTEMPTS | \ - ETH_ENABLE_AUTO_NEG_SPEED_GMII | \ - ETH_DTE_ADV_0 | \ - ETH_DISABLE_AUTO_NEG_BYPASS | \ - ETH_AUTO_NEG_NO_CHANGE | \ - ETH_MAX_RX_PACKET_9700BYTE | \ - ETH_CLR_EXT_LOOPBACK | \ - ETH_SET_FULL_DUPLEX_MODE | \ - ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX - -#define RX_BUFFER_MAX_SIZE 0x4000000 -#define TX_BUFFER_MAX_SIZE 0x4000000 - /* MAC accepet/reject macros */ -#define ACCEPT_MAC_ADDR 0 -#define REJECT_MAC_ADDR 1 +#define ACCEPT_MAC_ADDR 0 +#define REJECT_MAC_ADDR 1 /* Buffer offset from buffer pointer */ #define RX_BUF_OFFSET 0x2 @@ -155,277 +100,132 @@ /* Gigabit Ethernet Unit Global Registers */ /* MIB Counters register definitions */ -#define ETH_MIB_GOOD_OCTETS_RECEIVED_LOW 0x0 -#define ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH 0x4 -#define ETH_MIB_BAD_OCTETS_RECEIVED 0x8 -#define ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR 0xc -#define ETH_MIB_GOOD_FRAMES_RECEIVED 0x10 -#define ETH_MIB_BAD_FRAMES_RECEIVED 0x14 -#define ETH_MIB_BROADCAST_FRAMES_RECEIVED 0x18 -#define ETH_MIB_MULTICAST_FRAMES_RECEIVED 0x1c -#define ETH_MIB_FRAMES_64_OCTETS 0x20 -#define ETH_MIB_FRAMES_65_TO_127_OCTETS 0x24 -#define ETH_MIB_FRAMES_128_TO_255_OCTETS 0x28 -#define ETH_MIB_FRAMES_256_TO_511_OCTETS 0x2c -#define ETH_MIB_FRAMES_512_TO_1023_OCTETS 0x30 -#define ETH_MIB_FRAMES_1024_TO_MAX_OCTETS 0x34 -#define ETH_MIB_GOOD_OCTETS_SENT_LOW 0x38 -#define ETH_MIB_GOOD_OCTETS_SENT_HIGH 0x3c -#define ETH_MIB_GOOD_FRAMES_SENT 0x40 -#define ETH_MIB_EXCESSIVE_COLLISION 0x44 -#define ETH_MIB_MULTICAST_FRAMES_SENT 0x48 -#define ETH_MIB_BROADCAST_FRAMES_SENT 0x4c -#define ETH_MIB_UNREC_MAC_CONTROL_RECEIVED 0x50 -#define ETH_MIB_FC_SENT 0x54 -#define ETH_MIB_GOOD_FC_RECEIVED 0x58 -#define ETH_MIB_BAD_FC_RECEIVED 0x5c -#define ETH_MIB_UNDERSIZE_RECEIVED 0x60 -#define ETH_MIB_FRAGMENTS_RECEIVED 0x64 -#define ETH_MIB_OVERSIZE_RECEIVED 0x68 -#define ETH_MIB_JABBER_RECEIVED 0x6c -#define ETH_MIB_MAC_RECEIVE_ERROR 0x70 -#define ETH_MIB_BAD_CRC_EVENT 0x74 -#define ETH_MIB_COLLISION 0x78 -#define ETH_MIB_LATE_COLLISION 0x7c +#define ETH_MIB_GOOD_OCTETS_RECEIVED_LOW 0x0 +#define ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH 0x4 +#define ETH_MIB_BAD_OCTETS_RECEIVED 0x8 +#define ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR 0xc +#define ETH_MIB_GOOD_FRAMES_RECEIVED 0x10 +#define ETH_MIB_BAD_FRAMES_RECEIVED 0x14 +#define ETH_MIB_BROADCAST_FRAMES_RECEIVED 0x18 +#define ETH_MIB_MULTICAST_FRAMES_RECEIVED 0x1c +#define ETH_MIB_FRAMES_64_OCTETS 0x20 +#define ETH_MIB_FRAMES_65_TO_127_OCTETS 0x24 +#define ETH_MIB_FRAMES_128_TO_255_OCTETS 0x28 +#define ETH_MIB_FRAMES_256_TO_511_OCTETS 0x2c +#define ETH_MIB_FRAMES_512_TO_1023_OCTETS 0x30 +#define ETH_MIB_FRAMES_1024_TO_MAX_OCTETS 0x34 +#define ETH_MIB_GOOD_OCTETS_SENT_LOW 0x38 +#define ETH_MIB_GOOD_OCTETS_SENT_HIGH 0x3c +#define ETH_MIB_GOOD_FRAMES_SENT 0x40 +#define ETH_MIB_EXCESSIVE_COLLISION 0x44 +#define ETH_MIB_MULTICAST_FRAMES_SENT 0x48 +#define ETH_MIB_BROADCAST_FRAMES_SENT 0x4c +#define ETH_MIB_UNREC_MAC_CONTROL_RECEIVED 0x50 +#define ETH_MIB_FC_SENT 0x54 +#define ETH_MIB_GOOD_FC_RECEIVED 0x58 +#define ETH_MIB_BAD_FC_RECEIVED 0x5c +#define ETH_MIB_UNDERSIZE_RECEIVED 0x60 +#define ETH_MIB_FRAGMENTS_RECEIVED 0x64 +#define ETH_MIB_OVERSIZE_RECEIVED 0x68 +#define ETH_MIB_JABBER_RECEIVED 0x6c +#define ETH_MIB_MAC_RECEIVE_ERROR 0x70 +#define ETH_MIB_BAD_CRC_EVENT 0x74 +#define ETH_MIB_COLLISION 0x78 +#define ETH_MIB_LATE_COLLISION 0x7c /* Port serial status reg (PSR) */ -#define ETH_INTERFACE_GMII_MII 0 -#define ETH_INTERFACE_PCM BIT0 -#define ETH_LINK_IS_DOWN 0 -#define ETH_LINK_IS_UP BIT1 -#define ETH_PORT_AT_HALF_DUPLEX 0 -#define ETH_PORT_AT_FULL_DUPLEX BIT2 -#define ETH_RX_FLOW_CTRL_DISABLED 0 -#define ETH_RX_FLOW_CTRL_ENBALED BIT3 -#define ETH_GMII_SPEED_100_10 0 -#define ETH_GMII_SPEED_1000 BIT4 -#define ETH_MII_SPEED_10 0 -#define ETH_MII_SPEED_100 BIT5 -#define ETH_NO_TX 0 -#define ETH_TX_IN_PROGRESS BIT7 -#define ETH_BYPASS_NO_ACTIVE 0 -#define ETH_BYPASS_ACTIVE BIT8 -#define ETH_PORT_NOT_AT_PARTITION_STATE 0 -#define ETH_PORT_AT_PARTITION_STATE BIT9 -#define ETH_PORT_TX_FIFO_NOT_EMPTY 0 -#define ETH_PORT_TX_FIFO_EMPTY BIT10 - - -/* These macros describes the Port configuration reg (Px_cR) bits */ -#define ETH_UNICAST_NORMAL_MODE 0 -#define ETH_UNICAST_PROMISCUOUS_MODE BIT0 -#define ETH_DEFAULT_RX_QUEUE_0 0 -#define ETH_DEFAULT_RX_QUEUE_1 BIT1 -#define ETH_DEFAULT_RX_QUEUE_2 BIT2 -#define ETH_DEFAULT_RX_QUEUE_3 (BIT2 | BIT1) -#define ETH_DEFAULT_RX_QUEUE_4 BIT3 -#define ETH_DEFAULT_RX_QUEUE_5 (BIT3 | BIT1) -#define ETH_DEFAULT_RX_QUEUE_6 (BIT3 | BIT2) -#define ETH_DEFAULT_RX_QUEUE_7 (BIT3 | BIT2 | BIT1) -#define ETH_DEFAULT_RX_ARP_QUEUE_0 0 -#define ETH_DEFAULT_RX_ARP_QUEUE_1 BIT4 -#define ETH_DEFAULT_RX_ARP_QUEUE_2 BIT5 -#define ETH_DEFAULT_RX_ARP_QUEUE_3 (BIT5 | BIT4) -#define ETH_DEFAULT_RX_ARP_QUEUE_4 BIT6 -#define ETH_DEFAULT_RX_ARP_QUEUE_5 (BIT6 | BIT4) -#define ETH_DEFAULT_RX_ARP_QUEUE_6 (BIT6 | BIT5) -#define ETH_DEFAULT_RX_ARP_QUEUE_7 (BIT6 | BIT5 | BIT4) -#define ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP 0 -#define ETH_REJECT_BC_IF_NOT_IP_OR_ARP BIT7 -#define ETH_RECEIVE_BC_IF_IP 0 -#define ETH_REJECT_BC_IF_IP BIT8 -#define ETH_RECEIVE_BC_IF_ARP 0 -#define ETH_REJECT_BC_IF_ARP BIT9 -#define ETH_TX_AM_NO_UPDATE_ERROR_SUMMARY BIT12 -#define ETH_CAPTURE_TCP_FRAMES_DIS 0 -#define ETH_CAPTURE_TCP_FRAMES_EN BIT14 -#define ETH_CAPTURE_UDP_FRAMES_DIS 0 -#define ETH_CAPTURE_UDP_FRAMES_EN BIT15 -#define ETH_DEFAULT_RX_TCP_QUEUE_0 0 -#define ETH_DEFAULT_RX_TCP_QUEUE_1 BIT16 -#define ETH_DEFAULT_RX_TCP_QUEUE_2 BIT17 -#define ETH_DEFAULT_RX_TCP_QUEUE_3 (BIT17 | BIT16) -#define ETH_DEFAULT_RX_TCP_QUEUE_4 BIT18 -#define ETH_DEFAULT_RX_TCP_QUEUE_5 (BIT18 | BIT16) -#define ETH_DEFAULT_RX_TCP_QUEUE_6 (BIT18 | BIT17) -#define ETH_DEFAULT_RX_TCP_QUEUE_7 (BIT18 | BIT17 | BIT16) -#define ETH_DEFAULT_RX_UDP_QUEUE_0 0 -#define ETH_DEFAULT_RX_UDP_QUEUE_1 BIT19 -#define ETH_DEFAULT_RX_UDP_QUEUE_2 BIT20 -#define ETH_DEFAULT_RX_UDP_QUEUE_3 (BIT20 | BIT19) -#define ETH_DEFAULT_RX_UDP_QUEUE_4 (BIT21 -#define ETH_DEFAULT_RX_UDP_QUEUE_5 (BIT21 | BIT19) -#define ETH_DEFAULT_RX_UDP_QUEUE_6 (BIT21 | BIT20) -#define ETH_DEFAULT_RX_UDP_QUEUE_7 (BIT21 | BIT20 | BIT19) -#define ETH_DEFAULT_RX_BPDU_QUEUE_0 0 -#define ETH_DEFAULT_RX_BPDU_QUEUE_1 BIT22 -#define ETH_DEFAULT_RX_BPDU_QUEUE_2 BIT23 -#define ETH_DEFAULT_RX_BPDU_QUEUE_3 (BIT23 | BIT22) -#define ETH_DEFAULT_RX_BPDU_QUEUE_4 BIT24 -#define ETH_DEFAULT_RX_BPDU_QUEUE_5 (BIT24 | BIT22) -#define ETH_DEFAULT_RX_BPDU_QUEUE_6 (BIT24 | BIT23) -#define ETH_DEFAULT_RX_BPDU_QUEUE_7 (BIT24 | BIT23 | BIT22) - - -/* These macros describes the Port configuration extend reg (Px_cXR) bits*/ -#define ETH_CLASSIFY_EN BIT0 -#define ETH_SPAN_BPDU_PACKETS_AS_NORMAL 0 -#define ETH_SPAN_BPDU_PACKETS_TO_RX_QUEUE_7 BIT1 -#define ETH_PARTITION_DISABLE 0 -#define ETH_PARTITION_ENABLE BIT2 - - -/* Tx/Rx queue command reg (RQCR/TQCR)*/ -#define ETH_QUEUE_0_ENABLE BIT0 -#define ETH_QUEUE_1_ENABLE BIT1 -#define ETH_QUEUE_2_ENABLE BIT2 -#define ETH_QUEUE_3_ENABLE BIT3 -#define ETH_QUEUE_4_ENABLE BIT4 -#define ETH_QUEUE_5_ENABLE BIT5 -#define ETH_QUEUE_6_ENABLE BIT6 -#define ETH_QUEUE_7_ENABLE BIT7 -#define ETH_QUEUE_0_DISABLE BIT8 -#define ETH_QUEUE_1_DISABLE BIT9 -#define ETH_QUEUE_2_DISABLE BIT10 -#define ETH_QUEUE_3_DISABLE BIT11 -#define ETH_QUEUE_4_DISABLE BIT12 -#define ETH_QUEUE_5_DISABLE BIT13 -#define ETH_QUEUE_6_DISABLE BIT14 -#define ETH_QUEUE_7_DISABLE BIT15 - - -/* These macros describes the Port Sdma configuration reg (SDCR) bits */ -#define ETH_RIFB BIT0 -#define ETH_RX_BURST_SIZE_1_64BIT 0 -#define ETH_RX_BURST_SIZE_2_64BIT BIT1 -#define ETH_RX_BURST_SIZE_4_64BIT BIT2 -#define ETH_RX_BURST_SIZE_8_64BIT (BIT2 | BIT1) -#define ETH_RX_BURST_SIZE_16_64BIT BIT3 -#define ETH_BLM_RX_NO_SWAP BIT4 -#define ETH_BLM_RX_BYTE_SWAP 0 -#define ETH_BLM_TX_NO_SWAP BIT5 -#define ETH_BLM_TX_BYTE_SWAP 0 -#define ETH_DESCRIPTORS_BYTE_SWAP BIT6 -#define ETH_DESCRIPTORS_NO_SWAP 0 -#define ETH_TX_BURST_SIZE_1_64BIT 0 -#define ETH_TX_BURST_SIZE_2_64BIT BIT22 -#define ETH_TX_BURST_SIZE_4_64BIT BIT23 -#define ETH_TX_BURST_SIZE_8_64BIT (BIT23 | BIT22) -#define ETH_TX_BURST_SIZE_16_64BIT BIT24 - - - -/* These macros describes the Port serial control reg (PSCR) bits */ -#define ETH_SERIAL_PORT_DISABLE 0 -#define ETH_SERIAL_PORT_ENABLE BIT0 -#define ETH_FORCE_LINK_PASS BIT1 -#define ETH_DO_NOT_FORCE_LINK_PASS 0 -#define ETH_ENABLE_AUTO_NEG_FOR_DUPLX 0 -#define ETH_DISABLE_AUTO_NEG_FOR_DUPLX BIT2 -#define ETH_ENABLE_AUTO_NEG_FOR_FLOW_CTRL 0 -#define ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL BIT3 -#define ETH_ADV_NO_FLOW_CTRL 0 -#define ETH_ADV_SYMMETRIC_FLOW_CTRL BIT4 -#define ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX 0 -#define ETH_FORCE_FC_MODE_TX_PAUSE_DIS BIT5 -#define ETH_FORCE_BP_MODE_NO_JAM 0 -#define ETH_FORCE_BP_MODE_JAM_TX BIT7 -#define ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR BIT8 -#define ETH_FORCE_LINK_FAIL 0 -#define ETH_DO_NOT_FORCE_LINK_FAIL BIT10 -#define ETH_RETRANSMIT_16_ATTEMPTS 0 -#define ETH_RETRANSMIT_FOREVER BIT11 -#define ETH_DISABLE_AUTO_NEG_SPEED_GMII BIT13 -#define ETH_ENABLE_AUTO_NEG_SPEED_GMII 0 -#define ETH_DTE_ADV_0 0 -#define ETH_DTE_ADV_1 BIT14 -#define ETH_DISABLE_AUTO_NEG_BYPASS 0 -#define ETH_ENABLE_AUTO_NEG_BYPASS BIT15 -#define ETH_AUTO_NEG_NO_CHANGE 0 -#define ETH_RESTART_AUTO_NEG BIT16 -#define ETH_MAX_RX_PACKET_1518BYTE 0 -#define ETH_MAX_RX_PACKET_1522BYTE BIT17 -#define ETH_MAX_RX_PACKET_1552BYTE BIT18 -#define ETH_MAX_RX_PACKET_9022BYTE (BIT18 | BIT17) -#define ETH_MAX_RX_PACKET_9192BYTE BIT19 -#define ETH_MAX_RX_PACKET_9700BYTE (BIT19 | BIT17) -#define ETH_SET_EXT_LOOPBACK BIT20 -#define ETH_CLR_EXT_LOOPBACK 0 -#define ETH_SET_FULL_DUPLEX_MODE BIT21 -#define ETH_SET_HALF_DUPLEX_MODE 0 -#define ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX BIT22 -#define ETH_DISABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX 0 -#define ETH_SET_GMII_SPEED_TO_10_100 0 -#define ETH_SET_GMII_SPEED_TO_1000 BIT23 -#define ETH_SET_MII_SPEED_TO_10 0 -#define ETH_SET_MII_SPEED_TO_100 BIT24 - +#define ETH_INTERFACE_GMII_MII 0 +#define ETH_INTERFACE_PCM BIT0 +#define ETH_LINK_IS_DOWN 0 +#define ETH_LINK_IS_UP BIT1 +#define ETH_PORT_AT_HALF_DUPLEX 0 +#define ETH_PORT_AT_FULL_DUPLEX BIT2 +#define ETH_RX_FLOW_CTRL_DISABLED 0 +#define ETH_RX_FLOW_CTRL_ENBALED BIT3 +#define ETH_GMII_SPEED_100_10 0 +#define ETH_GMII_SPEED_1000 BIT4 +#define ETH_MII_SPEED_10 0 +#define ETH_MII_SPEED_100 BIT5 +#define ETH_NO_TX 0 +#define ETH_TX_IN_PROGRESS BIT7 +#define ETH_BYPASS_NO_ACTIVE 0 +#define ETH_BYPASS_ACTIVE BIT8 +#define ETH_PORT_NOT_AT_PARTITION_STATE 0 +#define ETH_PORT_AT_PARTITION_STATE BIT9 +#define ETH_PORT_TX_FIFO_NOT_EMPTY 0 +#define ETH_PORT_TX_FIFO_EMPTY BIT10 + +#define ETH_DEFAULT_RX_BPDU_QUEUE_3 (BIT23 | BIT22) +#define ETH_DEFAULT_RX_BPDU_QUEUE_4 BIT24 +#define ETH_DEFAULT_RX_BPDU_QUEUE_5 (BIT24 | BIT22) +#define ETH_DEFAULT_RX_BPDU_QUEUE_6 (BIT24 | BIT23) +#define ETH_DEFAULT_RX_BPDU_QUEUE_7 (BIT24 | BIT23 | BIT22) /* SMI reg */ -#define ETH_SMI_BUSY BIT28 /* 0 - Write, 1 - Read */ -#define ETH_SMI_READ_VALID BIT27 /* 0 - Write, 1 - Read */ +#define ETH_SMI_BUSY BIT28 /* 0 - Write, 1 - Read */ +#define ETH_SMI_READ_VALID BIT27 /* 0 - Write, 1 - Read */ #define ETH_SMI_OPCODE_WRITE 0 /* Completion of Read operation */ -#define ETH_SMI_OPCODE_READ BIT26 /* Operation is in progress */ +#define ETH_SMI_OPCODE_READ BIT26 /* Operation is in progress */ /* SDMA command status fields macros */ /* Tx & Rx descriptors status */ -#define ETH_ERROR_SUMMARY (BIT0) +#define ETH_ERROR_SUMMARY (BIT0) /* Tx & Rx descriptors command */ -#define ETH_BUFFER_OWNED_BY_DMA (BIT31) +#define ETH_BUFFER_OWNED_BY_DMA (BIT31) /* Tx descriptors status */ -#define ETH_LC_ERROR (0 ) -#define ETH_UR_ERROR (BIT1 ) -#define ETH_RL_ERROR (BIT2 ) -#define ETH_LLC_SNAP_FORMAT (BIT9 ) +#define ETH_LC_ERROR (0 ) +#define ETH_UR_ERROR (BIT1 ) +#define ETH_RL_ERROR (BIT2 ) +#define ETH_LLC_SNAP_FORMAT (BIT9 ) /* Rx descriptors status */ -#define ETH_CRC_ERROR (0 ) -#define ETH_OVERRUN_ERROR (BIT1 ) -#define ETH_MAX_FRAME_LENGTH_ERROR (BIT2 ) -#define ETH_RESOURCE_ERROR ((BIT2 | BIT1)) -#define ETH_VLAN_TAGGED (BIT19) -#define ETH_BPDU_FRAME (BIT20) -#define ETH_TCP_FRAME_OVER_IP_V_4 (0 ) -#define ETH_UDP_FRAME_OVER_IP_V_4 (BIT21) -#define ETH_OTHER_FRAME_TYPE (BIT22) -#define ETH_LAYER_2_IS_ETH_V_2 (BIT23) -#define ETH_FRAME_TYPE_IP_V_4 (BIT24) -#define ETH_FRAME_HEADER_OK (BIT25) -#define ETH_RX_LAST_DESC (BIT26) -#define ETH_RX_FIRST_DESC (BIT27) -#define ETH_UNKNOWN_DESTINATION_ADDR (BIT28) -#define ETH_RX_ENABLE_INTERRUPT (BIT29) -#define ETH_LAYER_4_CHECKSUM_OK (BIT30) +#define ETH_CRC_ERROR (0 ) +#define ETH_OVERRUN_ERROR (BIT1 ) +#define ETH_MAX_FRAME_LENGTH_ERROR (BIT2 ) +#define ETH_RESOURCE_ERROR ((BIT2 | BIT1)) +#define ETH_VLAN_TAGGED (BIT19) +#define ETH_BPDU_FRAME (BIT20) +#define ETH_TCP_FRAME_OVER_IP_V_4 (0 ) +#define ETH_UDP_FRAME_OVER_IP_V_4 (BIT21) +#define ETH_OTHER_FRAME_TYPE (BIT22) +#define ETH_LAYER_2_IS_ETH_V_2 (BIT23) +#define ETH_FRAME_TYPE_IP_V_4 (BIT24) +#define ETH_FRAME_HEADER_OK (BIT25) +#define ETH_RX_LAST_DESC (BIT26) +#define ETH_RX_FIRST_DESC (BIT27) +#define ETH_UNKNOWN_DESTINATION_ADDR (BIT28) +#define ETH_RX_ENABLE_INTERRUPT (BIT29) +#define ETH_LAYER_4_CHECKSUM_OK (BIT30) /* Rx descriptors byte count */ -#define ETH_FRAME_FRAGMENTED (BIT2) +#define ETH_FRAME_FRAGMENTED (BIT2) /* Tx descriptors command */ #define ETH_LAYER_4_CHECKSUM_FIRST_DESC (BIT10) -#define ETH_FRAME_SET_TO_VLAN (BIT15) -#define ETH_TCP_FRAME (0 ) -#define ETH_UDP_FRAME (BIT16) -#define ETH_GEN_TCP_UDP_CHECKSUM (BIT17) -#define ETH_GEN_IP_V_4_CHECKSUM (BIT18) -#define ETH_ZERO_PADDING (BIT19) -#define ETH_TX_LAST_DESC (BIT20) -#define ETH_TX_FIRST_DESC (BIT21) -#define ETH_GEN_CRC (BIT22) -#define ETH_TX_ENABLE_INTERRUPT (BIT23) -#define ETH_AUTO_MODE (BIT30) +#define ETH_FRAME_SET_TO_VLAN (BIT15) +#define ETH_TCP_FRAME (0 ) +#define ETH_UDP_FRAME (BIT16) +#define ETH_GEN_TCP_UDP_CHECKSUM (BIT17) +#define ETH_GEN_IP_V_4_CHECKSUM (BIT18) +#define ETH_ZERO_PADDING (BIT19) +#define ETH_TX_LAST_DESC (BIT20) +#define ETH_TX_FIRST_DESC (BIT21) +#define ETH_GEN_CRC (BIT22) +#define ETH_TX_ENABLE_INTERRUPT (BIT23) +#define ETH_AUTO_MODE (BIT30) /* typedefs */ typedef enum _eth_func_ret_status { - ETH_OK, /* Returned as expected. */ - ETH_ERROR, /* Fundamental error. */ - ETH_RETRY, /* Could not process request. Try later. */ - ETH_END_OF_JOB, /* Ring has nothing to process. */ - ETH_QUEUE_FULL, /* Ring resource error. */ - ETH_QUEUE_LAST_RESOURCE /* Ring resources about to exhaust. */ + ETH_OK, /* Returned as expected. */ + ETH_ERROR, /* Fundamental error. */ + ETH_RETRY, /* Could not process request. Try later.*/ + ETH_END_OF_JOB, /* Ring has nothing to process. */ + ETH_QUEUE_FULL, /* Ring resource error. */ + ETH_QUEUE_LAST_RESOURCE /* Ring resources about to exhaust. */ } ETH_FUNC_RET_STATUS; typedef enum _eth_target { @@ -441,66 +241,103 @@ */ #if defined(__BIG_ENDIAN) struct eth_rx_desc { - u16 byte_cnt; /* Descriptor buffer byte count */ - u16 buf_size; /* Buffer size */ - u32 cmd_sts; /* Descriptor command status */ - u32 next_desc_ptr; /* Next descriptor pointer */ - u32 buf_ptr; /* Descriptor buffer pointer */ + u16 byte_cnt; /* Descriptor buffer byte count */ + u16 buf_size; /* Buffer size */ + u32 cmd_sts; /* Descriptor command status */ + u32 next_desc_ptr; /* Next descriptor pointer */ + u32 buf_ptr; /* Descriptor buffer pointer */ }; struct eth_tx_desc { - u16 byte_cnt; /* buffer byte count */ - u16 l4i_chk; /* CPU provided TCP checksum */ - u32 cmd_sts; /* Command/status field */ - u32 next_desc_ptr; /* Pointer to next descriptor */ - u32 buf_ptr; /* pointer to buffer for this descriptor */ + u16 byte_cnt; /* buffer byte count */ + u16 l4i_chk; /* CPU provided TCP checksum */ + u32 cmd_sts; /* Command/status field */ + u32 next_desc_ptr; /* Pointer to next descriptor */ + u32 buf_ptr; /* pointer to buffer for this descriptor*/ }; #elif defined(__LITTLE_ENDIAN) struct eth_rx_desc { - u32 cmd_sts; /* Descriptor command status */ - u16 buf_size; /* Buffer size */ - u16 byte_cnt; /* Descriptor buffer byte count */ - u32 buf_ptr; /* Descriptor buffer pointer */ - u32 next_desc_ptr; /* Next descriptor pointer */ + u32 cmd_sts; /* Descriptor command status */ + u16 buf_size; /* Buffer size */ + u16 byte_cnt; /* Descriptor buffer byte count */ + u32 buf_ptr; /* Descriptor buffer pointer */ + u32 next_desc_ptr; /* Next descriptor pointer */ }; struct eth_tx_desc { - u32 cmd_sts; /* Command/status field */ - u16 l4i_chk; /* CPU provided TCP checksum */ - u16 byte_cnt; /* buffer byte count */ - u32 buf_ptr; /* pointer to buffer for this descriptor */ - u32 next_desc_ptr; /* Pointer to next descriptor */ + u32 cmd_sts; /* Command/status field */ + u16 l4i_chk; /* CPU provided TCP checksum */ + u16 byte_cnt; /* buffer byte count */ + u32 buf_ptr; /* pointer to buffer for this descriptor*/ + u32 next_desc_ptr; /* Pointer to next descriptor */ }; #else #error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined #endif -/* Unified struct for Rx and Tx operations. The user is not required to */ -/* be familier with neither Tx nor Rx descriptors. */ +/* Unified struct for Rx and Tx operations. The user is not required to */ +/* be familier with neither Tx nor Rx descriptors. */ struct pkt_info { - unsigned short byte_cnt; /* Descriptor buffer byte count */ - unsigned short l4i_chk; /* Tx CPU provided TCP Checksum */ - unsigned int cmd_sts; /* Descriptor command status */ - dma_addr_t buf_ptr; /* Descriptor buffer pointer */ - struct sk_buff * return_info; /* User resource return information */ + unsigned short byte_cnt; /* Descriptor buffer byte count */ + unsigned short l4i_chk; /* Tx CPU provided TCP Checksum */ + unsigned int cmd_sts; /* Descriptor command status */ + dma_addr_t buf_ptr; /* Descriptor buffer pointer */ + struct sk_buff *return_info; /* User resource return information */ }; - /* Ethernet port specific infomation */ -struct mv64340_private { - int port_num; /* User Ethernet port number */ - u8 port_mac_addr[6]; /* User defined port MAC address. */ - u32 port_config; /* User port configuration value */ - u32 port_config_extend; /* User port config extend value */ - u32 port_sdma_config; /* User port SDMA config value */ - u32 port_serial_control; /* User port serial control value */ - u32 port_tx_queue_command; /* Port active Tx queues summary */ - u32 port_rx_queue_command; /* Port active Rx queues summary */ +struct mv643xx_mib_counters { + u64 good_octets_received; + u32 bad_octets_received; + u32 internal_mac_transmit_err; + u32 good_frames_received; + u32 bad_frames_received; + u32 broadcast_frames_received; + u32 multicast_frames_received; + u32 frames_64_octets; + u32 frames_65_to_127_octets; + u32 frames_128_to_255_octets; + u32 frames_256_to_511_octets; + u32 frames_512_to_1023_octets; + u32 frames_1024_to_max_octets; + u64 good_octets_sent; + u32 good_frames_sent; + u32 excessive_collision; + u32 multicast_frames_sent; + u32 broadcast_frames_sent; + u32 unrec_mac_control_received; + u32 fc_sent; + u32 good_fc_received; + u32 bad_fc_received; + u32 undersize_received; + u32 fragments_received; + u32 oversize_received; + u32 jabber_received; + u32 mac_receive_error; + u32 bad_crc_event; + u32 collision; + u32 late_collision; +}; + +struct mv643xx_private { + int port_num; /* User Ethernet port number */ + u8 port_mac_addr[6]; /* User defined port MAC address.*/ + u32 port_config; /* User port configuration value*/ + u32 port_config_extend; /* User port config extend value*/ + u32 port_sdma_config; /* User port SDMA config value */ + u32 port_serial_control; /* User port serial control value */ + u32 port_tx_queue_command; /* Port active Tx queues summary*/ + u32 port_rx_queue_command; /* Port active Rx queues summary*/ + + u32 rx_sram_addr; /* Base address of rx sram area */ + u32 rx_sram_size; /* Size of rx sram area */ + u32 tx_sram_addr; /* Base address of tx sram area */ + u32 tx_sram_size; /* Size of tx sram area */ - int rx_resource_err; /* Rx ring resource error flag */ - int tx_resource_err; /* Tx ring resource error flag */ + int rx_resource_err; /* Rx ring resource error flag */ + int tx_resource_err; /* Tx ring resource error flag */ /* Tx/Rx rings managment indexes fields. For driver use */ @@ -509,30 +346,32 @@ /* Next available and first returning Tx resource */ int tx_curr_desc_q, tx_used_desc_q; -#ifdef MV64340_CHECKSUM_OFFLOAD_TX - int tx_first_desc_q; +#ifdef MV643XX_CHECKSUM_OFFLOAD_TX + int tx_first_desc_q; + u32 tx_first_command; #endif -#ifdef MV64340_TX_FAST_REFILL - u32 tx_clean_threshold; +#ifdef MV643XX_TX_FAST_REFILL + u32 tx_clean_threshold; #endif - volatile struct eth_rx_desc * p_rx_desc_area; - dma_addr_t rx_desc_dma; - unsigned int rx_desc_area_size; - struct sk_buff * rx_skb[MV64340_RX_QUEUE_SIZE]; - - volatile struct eth_tx_desc * p_tx_desc_area; - dma_addr_t tx_desc_dma; - unsigned int tx_desc_area_size; - struct sk_buff * tx_skb[MV64340_TX_QUEUE_SIZE]; + struct eth_rx_desc *p_rx_desc_area; + dma_addr_t rx_desc_dma; + unsigned int rx_desc_area_size; + struct sk_buff **rx_skb; + + struct eth_tx_desc *p_tx_desc_area; + dma_addr_t tx_desc_dma; + unsigned int tx_desc_area_size; + struct sk_buff **tx_skb; - struct work_struct tx_timeout_task; + struct work_struct tx_timeout_task; /* - * Former struct mv64340_eth_priv members start here + * Former struct mv643xx_eth_priv members start here */ struct net_device_stats stats; + struct mv643xx_mib_counters mib_counters; spinlock_t lock; /* Size of Tx Ring per queue */ unsigned int tx_ring_size; @@ -544,13 +383,13 @@ unsigned int rx_ring_skbs; /* - * rx_task used to fill RX ring out of bottom half context + * rx_task used to fill RX ring out of bottom half context */ struct work_struct rx_task; - /* - * Used in case RX Ring is empty, which can be caused when - * system does not have resources (skb's) + /* + * Used in case RX Ring is empty, which can be caused when + * system does not have resources (skb's) */ struct timer_list timeout; long rx_task_busy __attribute__ ((aligned(SMP_CACHE_BYTES))); @@ -563,9 +402,9 @@ /* ethernet.h API list */ /* Port operation control routines */ -static void eth_port_init(struct mv64340_private *mp); +static void eth_port_init(struct mv643xx_private *mp); static void eth_port_reset(unsigned int eth_port_num); -static int eth_port_start(struct mv64340_private *mp); +static void eth_port_start(struct mv643xx_private *mp); static void ethernet_set_config_reg(unsigned int eth_port_num, unsigned int value); @@ -576,26 +415,24 @@ unsigned char *p_addr); /* PHY and MIB routines */ -static int ethernet_phy_reset(unsigned int eth_port_num); +static void ethernet_phy_reset(unsigned int eth_port_num); + +static void eth_port_write_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, unsigned int value); -static int eth_port_write_smi_reg(unsigned int eth_port_num, - unsigned int phy_reg, - unsigned int value); - -static int eth_port_read_smi_reg(unsigned int eth_port_num, - unsigned int phy_reg, - unsigned int *value); +static void eth_port_read_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, unsigned int *value); static void eth_clear_mib_counters(unsigned int eth_port_num); /* Port data flow control routines */ -static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private *mp, - struct pkt_info * p_pkt_info); -static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv64340_private *mp, - struct pkt_info * p_pkt_info); -static ETH_FUNC_RET_STATUS eth_port_receive(struct mv64340_private *mp, - struct pkt_info * p_pkt_info); -static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv64340_private *mp, - struct pkt_info * p_pkt_info); +static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, + struct pkt_info *p_pkt_info); +static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp, + struct pkt_info *p_pkt_info); +static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp, + struct pkt_info *p_pkt_info); +static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv643xx_private *mp, + struct pkt_info *p_pkt_info); -#endif /* __MV64340_ETH_H__ */ +#endif /* __MV643XX_ETH_H__ */ diff -Nru a/drivers/net/sis900.c b/drivers/net/sis900.c --- a/drivers/net/sis900.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/sis900.c 2005-03-08 14:29:45 -05:00 @@ -1,6 +1,6 @@ /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux. Copyright 1999 Silicon Integrated System Corporation - Revision: 1.08.06 Sep. 24 2002 + Revision: 1.08.08 Jan. 22 2005 Modified from the driver which is originally written by Donald Becker. @@ -16,8 +16,8 @@ preliminary Rev. 1.0 Nov. 10, 1998 SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution, preliminary Rev. 1.0 Jan. 18, 1998 - http://www.sis.com.tw/support/databook.htm + Rev 1.08.08 Jan. 22 2005 Daniele Venzano use netif_msg for debugging messages Rev 1.08.07 Nov. 2 2003 Daniele Venzano add suspend/resume support Rev 1.08.06 Sep. 24 2002 Mufasa Yang bug fix for Tx timeout & add SiS963 support Rev 1.08.05 Jun. 6 2002 Mufasa Yang bug fix for read_eeprom & Tx descriptor over-boundary @@ -74,7 +74,7 @@ #include "sis900.h" #define SIS900_MODULE_NAME "sis900" -#define SIS900_DRV_VERSION "v1.08.07 11/02/2003" +#define SIS900_DRV_VERSION "v1.08.08 Jan. 22 2005" static char version[] __devinitdata = KERN_INFO "sis900.c: " SIS900_DRV_VERSION "\n"; @@ -82,8 +82,13 @@ static int max_interrupt_work = 40; static int multicast_filter_limit = 128; -#define sis900_debug debug -static int sis900_debug; +static int sis900_debug = -1; /* Use SIS900_DEF_MSG as value */ + +#define SIS900_DEF_MSG \ + (NETIF_MSG_DRV | \ + NETIF_MSG_LINK | \ + NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR) /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (4*HZ) @@ -160,6 +165,8 @@ struct timer_list timer; /* Link status detection timer. */ u8 autong_complete; /* 1: auto-negotiate complete */ + u32 msg_enable; + unsigned int cur_rx, dirty_rx; /* producer/comsumer pointers for Tx/Rx ring */ unsigned int cur_tx, dirty_tx; @@ -174,6 +181,7 @@ unsigned int tx_full; /* The Tx queue is full. */ u8 host_bridge_rev; + u8 chipset_rev; }; MODULE_AUTHOR("Jim Huang , Ollie Lho "); @@ -182,11 +190,12 @@ module_param(multicast_filter_limit, int, 0444); module_param(max_interrupt_work, int, 0444); -module_param(debug, int, 0444); +module_param(sis900_debug, int, 0444); MODULE_PARM_DESC(multicast_filter_limit, "SiS 900/7016 maximum number of filtered multicast addresses"); MODULE_PARM_DESC(max_interrupt_work, "SiS 900/7016 maximum events handled per interrupt"); -MODULE_PARM_DESC(debug, "SiS 900/7016 debug level (2-4)"); +MODULE_PARM_DESC(sis900_debug, "SiS 900/7016 bitmapped debugging message level"); +static void sis900_poll(struct net_device *dev); static int sis900_open(struct net_device *net_dev); static int sis900_mii_probe (struct net_device * net_dev); static void sis900_init_rxfilter (struct net_device * net_dev); @@ -235,7 +244,7 @@ /* check to see if we have sane EEPROM */ signature = (u16) read_eeprom(ioaddr, EEPROMSignature); if (signature == 0xffff || signature == 0x0000) { - printk (KERN_INFO "%s: Error EERPOM read %x\n", + printk (KERN_WARNING "%s: Error EERPOM read %x\n", net_dev->name, signature); return 0; } @@ -268,7 +277,7 @@ if (!isa_bridge) isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0018, isa_bridge); if (!isa_bridge) { - printk("%s: Can not find ISA bridge\n", net_dev->name); + printk(KERN_WARNING "%s: Can not find ISA bridge\n", net_dev->name); return 0; } pci_read_config_byte(isa_bridge, 0x48, ®); @@ -386,7 +395,6 @@ void *ring_space; long ioaddr; int i, ret; - u8 revision; char *card_name = card_names[pci_id->driver_data]; /* when built into the kernel, we only print version if device is found */ @@ -456,35 +464,50 @@ net_dev->tx_timeout = sis900_tx_timeout; net_dev->watchdog_timeo = TX_TIMEOUT; net_dev->ethtool_ops = &sis900_ethtool_ops; - + +#ifdef CONFIG_NET_POLL_CONTROLLER + net_dev->poll_controller = &sis900_poll; +#endif + + if (sis900_debug > 0) + sis_priv->msg_enable = sis900_debug; + else + sis_priv->msg_enable = SIS900_DEF_MSG; + ret = register_netdev(net_dev); if (ret) goto err_unmap_rx; /* Get Mac address according to the chip revision */ - pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &(sis_priv->chipset_rev)); + if(netif_msg_probe(sis_priv)) + printk(KERN_DEBUG "%s: detected revision %2.2x, " + "trying to get MAC address...\n", + net_dev->name, sis_priv->chipset_rev); + ret = 0; - - if (revision == SIS630E_900_REV) + if (sis_priv->chipset_rev == SIS630E_900_REV) ret = sis630e_get_mac_addr(pci_dev, net_dev); - else if ((revision > 0x81) && (revision <= 0x90) ) + else if ((sis_priv->chipset_rev > 0x81) && (sis_priv->chipset_rev <= 0x90) ) ret = sis635_get_mac_addr(pci_dev, net_dev); - else if (revision == SIS96x_900_REV) + else if (sis_priv->chipset_rev == SIS96x_900_REV) ret = sis96x_get_mac_addr(pci_dev, net_dev); else ret = sis900_get_mac_addr(pci_dev, net_dev); if (ret == 0) { + printk(KERN_WARNING "%s: Cannot read MAC address.\n", net_dev->name); ret = -ENODEV; goto err_out_unregister; } /* 630ET : set the mii access mode as software-mode */ - if (revision == SIS630ET_900_REV) + if (sis_priv->chipset_rev == SIS630ET_900_REV) outl(ACCESSMODE | inl(ioaddr + cr), ioaddr + cr); /* probe for mii transceiver */ if (sis900_mii_probe(net_dev) == 0) { + printk(KERN_WARNING "%s: Error probing MII device.\n", net_dev->name); ret = -ENODEV; goto err_out_unregister; } @@ -536,7 +559,6 @@ u16 poll_bit = MII_STAT_LINK, status = 0; unsigned long timeout = jiffies + 5 * HZ; int phy_addr; - u8 revision; sis_priv->mii = NULL; @@ -550,12 +572,16 @@ for(i = 0; i < 2; i++) mii_status = mdio_read(net_dev, phy_addr, MII_STATUS); - if (mii_status == 0xffff || mii_status == 0x0000) - /* the mii is not accessible, try next one */ + if (mii_status == 0xffff || mii_status == 0x0000) { + if (netif_msg_probe(sis_priv)) + printk(KERN_DEBUG "%s: MII at address %d" + " not accessible\n", + net_dev->name, phy_addr); continue; + } if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) == NULL) { - printk(KERN_INFO "Cannot allocate mem for struct mii_phy\n"); + printk(KERN_WARNING "Cannot allocate mem for struct mii_phy\n"); mii_phy = sis_priv->first_mii; while (mii_phy) { struct mii_phy *phy; @@ -581,9 +607,11 @@ if (mii_chip_table[i].phy_types == MIX) mii_phy->phy_types = (mii_status & (MII_STAT_CAN_TX_FDX | MII_STAT_CAN_TX)) ? LAN : HOME; - printk(KERN_INFO "%s: %s transceiver found at address %d.\n", - net_dev->name, mii_chip_table[i].name, - phy_addr); + printk(KERN_INFO "%s: %s transceiver found " + "at address %d.\n", + net_dev->name, + mii_chip_table[i].name, + phy_addr); break; } @@ -627,8 +655,7 @@ } } - pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); - if (revision == SIS630E_900_REV) { + if (sis_priv->chipset_rev == SIS630E_900_REV) { /* SiS 630E has some bugs on default value of PHY registers */ mdio_write(net_dev, sis_priv->cur_phy, MII_ANADV, 0x05e1); mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG1, 0x22); @@ -930,6 +957,20 @@ return status; } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. +*/ +static void sis900_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + sis900_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + /** * sis900_open - open sis900 device * @net_dev: the net device to open @@ -943,15 +984,13 @@ { struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; - u8 revision; int ret; /* Soft reset the chip. */ sis900_reset(net_dev); /* Equalizer workaround Rule */ - pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); - sis630_set_eq(net_dev, revision); + sis630_set_eq(net_dev, sis_priv->chipset_rev); ret = request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev); @@ -999,6 +1038,7 @@ static void sis900_init_rxfilter (struct net_device * net_dev) { + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; u32 rfcrSave; u32 i; @@ -1016,8 +1056,8 @@ outl((i << RFADDR_shift), ioaddr + rfcr); outl(w, ioaddr + rfdr); - if (sis900_debug > 2) { - printk(KERN_INFO "%s: Receive Filter Addrss[%d]=%x\n", + if (netif_msg_hw(sis_priv)) { + printk(KERN_DEBUG "%s: Receive Filter Addrss[%d]=%x\n", net_dev->name, i, inl(ioaddr + rfdr)); } } @@ -1054,8 +1094,8 @@ /* load Transmit Descriptor Register */ outl(sis_priv->tx_ring_dma, ioaddr + txdp); - if (sis900_debug > 2) - printk(KERN_INFO "%s: TX descriptor register loaded with: %8.8x\n", + if (netif_msg_hw(sis_priv)) + printk(KERN_DEBUG "%s: TX descriptor register loaded with: %8.8x\n", net_dev->name, inl(ioaddr + txdp)); } @@ -1108,8 +1148,8 @@ /* load Receive Descriptor Register */ outl(sis_priv->rx_ring_dma, ioaddr + rxdp); - if (sis900_debug > 2) - printk(KERN_INFO "%s: RX descriptor register loaded with: %8.8x\n", + if (netif_msg_hw(sis_priv)) + printk(KERN_DEBUG "%s: RX descriptor register loaded with: %8.8x\n", net_dev->name, inl(ioaddr + rxdp)); } @@ -1219,7 +1259,6 @@ struct mii_phy *mii_phy = sis_priv->mii; static int next_tick = 5*HZ; u16 status; - u8 revision; if (!sis_priv->autong_complete){ int speed, duplex = 0; @@ -1227,9 +1266,7 @@ sis900_read_mode(net_dev, &speed, &duplex); if (duplex){ sis900_set_mode(net_dev->base_addr, speed, duplex); - pci_read_config_byte(sis_priv->pci_dev, - PCI_CLASS_REVISION, &revision); - sis630_set_eq(net_dev, revision); + sis630_set_eq(net_dev, sis_priv->chipset_rev); netif_start_queue(net_dev); } @@ -1256,16 +1293,15 @@ /* Link ON -> OFF */ if (!(status & MII_STAT_LINK)){ netif_carrier_off(net_dev); - printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); + if(netif_msg_link(sis_priv)) + printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); /* Change mode issue */ if ((mii_phy->phy_id0 == 0x001D) && ((mii_phy->phy_id1 & 0xFFF0) == 0x8000)) sis900_reset_phy(net_dev, sis_priv->cur_phy); - pci_read_config_byte(sis_priv->pci_dev, - PCI_CLASS_REVISION, &revision); - sis630_set_eq(net_dev, revision); + sis630_set_eq(net_dev, sis_priv->chipset_rev); goto LookForLink; } @@ -1371,7 +1407,8 @@ status = mdio_read(net_dev, phy_addr, MII_STATUS); if (!(status & MII_STAT_LINK)){ - printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); + if(netif_msg_link(sis_priv)) + printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); sis_priv->autong_complete = 1; netif_carrier_off(net_dev); return; @@ -1433,7 +1470,8 @@ *speed = HW_SPEED_100_MBPS; } - printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", + if(netif_msg_link(sis_priv)) + printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", net_dev->name, *speed == HW_SPEED_100_MBPS ? "100mbps" : "10mbps", @@ -1456,8 +1494,9 @@ unsigned long flags; int i; - printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n", - net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr)); + if(netif_msg_tx_err(sis_priv)) + printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n", + net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr)); /* Disable interrupts by clearing the interrupt mask. */ outl(0x0000, ioaddr + imr); @@ -1558,8 +1597,8 @@ net_dev->trans_start = jiffies; - if (sis900_debug > 3) - printk(KERN_INFO "%s: Queued Tx packet at %p size %d " + if (netif_msg_tx_queued(sis_priv)) + printk(KERN_DEBUG "%s: Queued Tx packet at %p size %d " "to slot %d.\n", net_dev->name, skb->data, (int)skb->len, entry); @@ -1606,20 +1645,22 @@ /* something strange happened !!! */ if (status & HIBERR) { - printk(KERN_INFO "%s: Abnormal interrupt," - "status %#8.8x.\n", net_dev->name, status); + if(netif_msg_intr(sis_priv)) + printk(KERN_INFO "%s: Abnormal interrupt," + "status %#8.8x.\n", net_dev->name, status); break; } if (--boguscnt < 0) { - printk(KERN_INFO "%s: Too much work at interrupt, " - "interrupt status = %#8.8x.\n", - net_dev->name, status); + if(netif_msg_intr(sis_priv)) + printk(KERN_INFO "%s: Too much work at interrupt, " + "interrupt status = %#8.8x.\n", + net_dev->name, status); break; } } while (1); - if (sis900_debug > 3) - printk(KERN_INFO "%s: exiting interrupt, " + if(netif_msg_intr(sis_priv)) + printk(KERN_DEBUG "%s: exiting interrupt, " "interrupt status = 0x%#8.8x.\n", net_dev->name, inl(ioaddr + isr)); @@ -1644,8 +1685,8 @@ unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC; u32 rx_status = sis_priv->rx_ring[entry].cmdsts; - if (sis900_debug > 3) - printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d " + if (netif_msg_rx_status(sis_priv)) + printk(KERN_DEBUG "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d " "status:0x%8.8x\n", sis_priv->cur_rx, sis_priv->dirty_rx, rx_status); @@ -1656,8 +1697,8 @@ if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) { /* corrupted packet received */ - if (sis900_debug > 3) - printk(KERN_INFO "%s: Corrupted packet " + if (netif_msg_rx_err(sis_priv)) + printk(KERN_DEBUG "%s: Corrupted packet " "received, buffer status = 0x%8.8x.\n", net_dev->name, rx_status); sis_priv->stats.rx_errors++; @@ -1678,9 +1719,10 @@ some unknow bugs, it is possible that we are working on NULL sk_buff :-( */ if (sis_priv->rx_skbuff[entry] == NULL) { - printk(KERN_INFO "%s: NULL pointer " - "encountered in Rx ring, skipping\n", - net_dev->name); + if (netif_msg_rx_err(sis_priv)) + printk(KERN_INFO "%s: NULL pointer " + "encountered in Rx ring, skipping\n", + net_dev->name); break; } @@ -1707,9 +1749,10 @@ * "hole" on the buffer ring, it is not clear * how the hardware will react to this kind * of degenerated buffer */ - printk(KERN_INFO "%s: Memory squeeze," - "deferring packet.\n", - net_dev->name); + if (netif_msg_rx_status(sis_priv)) + printk(KERN_INFO "%s: Memory squeeze," + "deferring packet.\n", + net_dev->name); sis_priv->rx_skbuff[entry] = NULL; /* reset buffer descriptor state */ sis_priv->rx_ring[entry].cmdsts = 0; @@ -1743,9 +1786,10 @@ * "hole" on the buffer ring, it is not clear * how the hardware will react to this kind * of degenerated buffer */ - printk(KERN_INFO "%s: Memory squeeze," - "deferring packet.\n", - net_dev->name); + if (netif_msg_rx_err(sis_priv)) + printk(KERN_INFO "%s: Memory squeeze," + "deferring packet.\n", + net_dev->name); sis_priv->stats.rx_dropped++; break; } @@ -1794,8 +1838,8 @@ if (tx_status & (ABORT | UNDERRUN | OWCOLL)) { /* packet unsuccessfully transmitted */ - if (sis900_debug > 3) - printk(KERN_INFO "%s: Transmit " + if (netif_msg_tx_err(sis_priv)) + printk(KERN_DEBUG "%s: Transmit " "error, Tx status %8.8x.\n", net_dev->name, tx_status); sis_priv->stats.tx_errors++; @@ -1906,8 +1950,22 @@ strcpy (info->bus_info, pci_name(sis_priv->pci_dev)); } +static u32 sis900_get_msglevel(struct net_device *net_dev) +{ + struct sis900_private *sis_priv = net_dev->priv; + return sis_priv->msg_enable; +} + +static void sis900_set_msglevel(struct net_device *net_dev, u32 value) +{ + struct sis900_private *sis_priv = net_dev->priv; + sis_priv->msg_enable = value; +} + static struct ethtool_ops sis900_ethtool_ops = { - .get_drvinfo = sis900_get_drvinfo, + .get_drvinfo = sis900_get_drvinfo, + .get_msglevel = sis900_get_msglevel, + .set_msglevel = sis900_set_msglevel, }; /** @@ -2048,12 +2106,10 @@ case IF_PORT_AUI: /* AUI */ case IF_PORT_100BASEFX: /* 100BaseFx */ /* These Modes are not supported (are they?)*/ - printk(KERN_INFO "Not supported"); return -EOPNOTSUPP; break; default: - printk(KERN_INFO "Invalid"); return -EINVAL; } } @@ -2099,11 +2155,10 @@ u16 mc_filter[16] = {0}; /* 256/128 bits multicast hash table */ int i, table_entries; u32 rx_mode; - u8 revision; /* 635 Hash Table entires = 256(2^16) */ - pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); - if((revision >= SIS635A_900_REV) || (revision == SIS900B_900_REV)) + if((sis_priv->chipset_rev >= SIS635A_900_REV) || + (sis_priv->chipset_rev == SIS900B_900_REV)) table_entries = 16; else table_entries = 8; @@ -2129,7 +2184,7 @@ mclist && i < net_dev->mc_count; i++, mclist = mclist->next) { unsigned int bit_nr = - sis900_mcast_bitnr(mclist->dmi_addr, revision); + sis900_mcast_bitnr(mclist->dmi_addr, sis_priv->chipset_rev); mc_filter[bit_nr >> 4] |= (1 << (bit_nr & 0xf)); } } @@ -2175,7 +2230,6 @@ long ioaddr = net_dev->base_addr; int i = 0; u32 status = TxRCMP | RxRCMP; - u8 revision; outl(0, ioaddr + ier); outl(0, ioaddr + imr); @@ -2188,8 +2242,8 @@ status ^= (inl(isr + ioaddr) & status); } - pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); - if( (revision >= SIS635A_900_REV) || (revision == SIS900B_900_REV) ) + if( (sis_priv->chipset_rev >= SIS635A_900_REV) || + (sis_priv->chipset_rev == SIS900B_900_REV) ) outl(PESEL | RND_CNT, ioaddr + cfg); else outl(PESEL, ioaddr + cfg); diff -Nru a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c --- a/drivers/net/via-rhine.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/via-rhine.c 2005-03-08 14:29:45 -05:00 @@ -1197,8 +1197,10 @@ dev->name, rp->pdev->irq); rc = alloc_ring(dev); - if (rc) + if (rc) { + free_irq(rp->pdev->irq, dev); return rc; + } alloc_rbufs(dev); alloc_tbufs(dev); rhine_chip_reset(dev); diff -Nru a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c --- a/drivers/net/wireless/airport.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/wireless/airport.c 2005-03-08 14:29:45 -05:00 @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -45,7 +44,7 @@ struct airport { struct macio_dev *mdev; - void *vaddr; + void __iomem *vaddr; int irq_requested; int ndev_registered; }; @@ -150,7 +149,7 @@ ssleep(1); macio_set_drvdata(mdev, NULL); - free_netdev(dev); + free_orinocodev(dev); return 0; } @@ -194,14 +193,14 @@ hermes_t *hw; if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) { - printk(KERN_ERR PFX "wrong interrupt/addresses in OF tree\n"); + printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n"); return -ENODEV; } /* Allocate space for private device-specific data */ dev = alloc_orinocodev(sizeof(*card), airport_hard_reset); if (! dev) { - printk(KERN_ERR PFX "can't allocate device datas\n"); + printk(KERN_ERR PFX "Cannot allocate network device\n"); return -ENODEV; } priv = netdev_priv(dev); @@ -212,7 +211,7 @@ if (macio_request_resource(mdev, 0, "airport")) { printk(KERN_ERR PFX "can't request IO resource !\n"); - free_netdev(dev); + free_orinocodev(dev); return -EBUSY; } @@ -224,16 +223,15 @@ /* Setup interrupts & base address */ dev->irq = macio_irq(mdev, 0); phys_addr = macio_resource_start(mdev, 0); /* Physical address */ - printk(KERN_DEBUG PFX "Airport at physical address %lx\n", phys_addr); + printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr); dev->base_addr = phys_addr; card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); if (!card->vaddr) { - printk(PFX "ioremap() failed\n"); + printk(KERN_ERR PFX "ioremap() failed\n"); goto failed; } - hermes_struct_init(hw, (ulong)card->vaddr, - HERMES_MEM, HERMES_16BIT_REGSPACING); + hermes_struct_init(hw, card->vaddr, HERMES_16BIT_REGSPACING); /* Power up card */ pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1); @@ -242,7 +240,7 @@ /* Reset it before we get the interrupt */ hermes_init(hw); - if (request_irq(dev->irq, orinoco_interrupt, 0, "Airport", dev)) { + if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) { printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq); goto failed; } @@ -253,7 +251,7 @@ printk(KERN_ERR PFX "register_netdev() failed\n"); goto failed; } - printk(KERN_DEBUG PFX "card registered for interface %s\n", dev->name); + printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name); card->ndev_registered = 1; return 0; failed: diff -Nru a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c --- a/drivers/net/wireless/hermes.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/wireless/hermes.c 2005-03-08 14:29:45 -05:00 @@ -48,6 +48,7 @@ #include #include #include +#include #include #include "hermes.h" @@ -67,8 +68,7 @@ * Debugging helpers */ -#define IO_TYPE(hw) ((hw)->io_space ? "IO " : "MEM ") -#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %s0x%x: " , IO_TYPE(hw), hw->iobase); \ +#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \ printk(stuff);} while (0) #undef HERMES_DEBUG @@ -123,11 +123,9 @@ * Function definitions */ -void hermes_struct_init(hermes_t *hw, ulong address, - int io_space, int reg_spacing) +void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing) { hw->iobase = address; - hw->io_space = io_space; hw->reg_spacing = reg_spacing; hw->inten = 0x0; @@ -200,9 +198,9 @@ } if (! (reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ %s0x%lx: " + printk(KERN_ERR "hermes @ %p: " "Timeout waiting for card to reset (reg=0x%04x)!\n", - IO_TYPE(hw), hw->iobase, reg); + hw->iobase, reg); err = -ETIMEDOUT; goto out; } @@ -235,13 +233,16 @@ err = hermes_issue_cmd(hw, cmd, parm0); if (err) { if (! hermes_present(hw)) { - printk(KERN_WARNING "hermes @ %s0x%lx: " - "Card removed while issuing command.\n", - IO_TYPE(hw), hw->iobase); + if (net_ratelimit()) + printk(KERN_WARNING "hermes @ %p: " + "Card removed while issuing command " + "0x%04x.\n", hw->iobase, cmd); err = -ENODEV; } else - printk(KERN_ERR "hermes @ %s0x%lx: Error %d issuing command.\n", - IO_TYPE(hw), hw->iobase, err); + if (net_ratelimit()) + printk(KERN_ERR "hermes @ %p: " + "Error %d issuing command 0x%04x.\n", + hw->iobase, err, cmd); goto out; } @@ -254,17 +255,16 @@ } if (! hermes_present(hw)) { - printk(KERN_WARNING "hermes @ %s0x%lx: " - "Card removed while waiting for command completion.\n", - IO_TYPE(hw), hw->iobase); + printk(KERN_WARNING "hermes @ %p: Card removed " + "while waiting for command 0x%04x completion.\n", + hw->iobase, cmd); err = -ENODEV; goto out; } if (! (reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ %s0x%lx: " - "Timeout waiting for command completion.\n", - IO_TYPE(hw), hw->iobase); + printk(KERN_ERR "hermes @ %p: Timeout waiting for " + "command 0x%04x completion.\n", hw->iobase, cmd); err = -ETIMEDOUT; goto out; } @@ -309,16 +309,16 @@ } if (! hermes_present(hw)) { - printk(KERN_WARNING "hermes @ %s0x%lx: " + printk(KERN_WARNING "hermes @ %p: " "Card removed waiting for frame allocation.\n", - IO_TYPE(hw), hw->iobase); + hw->iobase); return -ENODEV; } if (! (reg & HERMES_EV_ALLOC)) { - printk(KERN_ERR "hermes @ %s0x%lx: " + printk(KERN_ERR "hermes @ %p: " "Timeout waiting for frame allocation\n", - IO_TYPE(hw), hw->iobase); + hw->iobase); return -ETIMEDOUT; } @@ -383,12 +383,17 @@ reg = hermes_read_reg(hw, oreg); } - if (reg & HERMES_OFFSET_BUSY) { - return -ETIMEDOUT; - } + if (reg != offset) { + printk(KERN_ERR "hermes @ %p: BAP%d offset %s: " + "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap, + (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error", + reg, id, offset); + + if (reg & HERMES_OFFSET_BUSY) { + return -ETIMEDOUT; + } - if (reg & HERMES_OFFSET_ERR) { - return -EIO; + return -EIO; /* error or wrong offset */ } return 0; @@ -476,7 +481,7 @@ rlength = hermes_read_reg(hw, dreg); if (! rlength) - return -ENOENT; + return -ENODATA; rtype = hermes_read_reg(hw, dreg); @@ -484,14 +489,13 @@ *length = rlength; if (rtype != rid) - printk(KERN_WARNING "hermes @ %s0x%lx: " - "hermes_read_ltv(): rid (0x%04x) does not match type (0x%04x)\n", - IO_TYPE(hw), hw->iobase, rid, rtype); + printk(KERN_WARNING "hermes @ %p: %s(): " + "rid (0x%04x) does not match type (0x%04x)\n", + hw->iobase, __FUNCTION__, rid, rtype); if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize) - printk(KERN_WARNING "hermes @ %s0x%lx: " + printk(KERN_WARNING "hermes @ %p: " "Truncating LTV record from %d to %d bytes. " - "(rid=0x%04x, len=0x%04x)\n", - IO_TYPE(hw), hw->iobase, + "(rid=0x%04x, len=0x%04x)\n", hw->iobase, HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength); nwords = min((unsigned)rlength - 1, bufsize / 2); diff -Nru a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h --- a/drivers/net/wireless/hermes.h 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/wireless/hermes.h 2005-03-08 14:29:45 -05:00 @@ -340,14 +340,11 @@ #ifdef __KERNEL__ /* Timeouts */ -#define HERMES_BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */ +#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */ /* Basic control structure */ typedef struct hermes { - unsigned long iobase; - int io_space; /* 1 if we IO-mapped IO, 0 for memory-mapped IO? */ -#define HERMES_IO 1 -#define HERMES_MEM 0 + void __iomem *iobase; int reg_spacing; #define HERMES_16BIT_REGSPACING 0 #define HERMES_32BIT_REGSPACING 1 @@ -362,21 +359,15 @@ } hermes_t; /* Register access convenience macros */ -#define hermes_read_reg(hw, off) ((hw)->io_space ? \ - inw((hw)->iobase + ( (off) << (hw)->reg_spacing )) : \ - readw((hw)->iobase + ( (off) << (hw)->reg_spacing ))) -#define hermes_write_reg(hw, off, val) do { \ - if ((hw)->io_space) \ - outw_p((val), (hw)->iobase + ((off) << (hw)->reg_spacing)); \ - else \ - writew((val), (hw)->iobase + ((off) << (hw)->reg_spacing)); \ - } while (0) +#define hermes_read_reg(hw, off) \ + (ioread16((hw)->iobase + ( (off) << (hw)->reg_spacing ))) +#define hermes_write_reg(hw, off, val) \ + (iowrite16((val), (hw)->iobase + ((off) << (hw)->reg_spacing))) #define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name) #define hermes_write_regn(hw, name, val) hermes_write_reg((hw), HERMES_##name, (val)) /* Function prototypes */ -void hermes_struct_init(hermes_t *hw, ulong address, int io_space, - int reg_spacing); +void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing); int hermes_init(hermes_t *hw); int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, struct hermes_response *resp); @@ -430,41 +421,13 @@ static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsigned count) { off = off << hw->reg_spacing; - - if (hw->io_space) { - insw(hw->iobase + off, buf, count); - } else { - unsigned i; - u16 *p; - - /* This needs to *not* byteswap (like insw()) but - * readw() does byteswap hence the conversion. I hope - * gcc is smart enough to fold away the two swaps on - * big-endian platforms. */ - for (i = 0, p = buf; i < count; i++) { - *p++ = cpu_to_le16(readw(hw->iobase + off)); - } - } + ioread16_rep(hw->iobase + off, buf, count); } static inline void hermes_write_words(struct hermes *hw, int off, const void *buf, unsigned count) { off = off << hw->reg_spacing; - - if (hw->io_space) { - outsw(hw->iobase + off, buf, count); - } else { - unsigned i; - const u16 *p; - - /* This needs to *not* byteswap (like outsw()) but - * writew() does byteswap hence the conversion. I - * hope gcc is smart enough to fold away the two swaps - * on big-endian platforms. */ - for (i = 0, p = buf; i < count; i++) { - writew(le16_to_cpu(*p++), hw->iobase + off); - } - } + iowrite16_rep(hw->iobase + off, buf, count); } static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count) @@ -473,13 +436,8 @@ off = off << hw->reg_spacing; - if (hw->io_space) { - for (i = 0; i < count; i++) - outw(0, hw->iobase + off); - } else { - for (i = 0; i < count; i++) - writew(0, hw->iobase + off); - } + for (i = 0; i < count; i++) + iowrite16(0, hw->iobase + off); } #define HERMES_READ_RECORD(hw, bap, rid, buf) \ diff -Nru a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c --- a/drivers/net/wireless/orinoco.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/wireless/orinoco.c 2005-03-08 14:29:45 -05:00 @@ -393,6 +393,29 @@ * in the rx_dropped statistics. * o Provided a module parameter to suppress linkstatus messages. * + * v0.13e -> v0.14alpha1 - 30 Sep 2003 - David Gibson + * o Replaced priv->connected logic with netif_carrier_on/off() + * calls. + * o Remove has_ibss_any and never set the CREATEIBSS RID when + * the ESSID is empty. Too many firmwares break if we do. + * o 2.6 merges: Replace pdev->slot_name with pci_name(), remove + * __devinitdata from PCI ID tables, use free_netdev(). + * o Enabled shared-key authentication for Agere firmware (from + * Robert J. Moore + * o Move netif_wake_queue() (back) to the Tx completion from the + * ALLOC event. This seems to prevent/mitigate the rolling + * error -110 problems at least on some Intersil firmwares. + * Theoretically reduces performance, but I can't measure it. + * Patch from Andrew Tridgell + * + * v0.14alpha1 -> v0.14alpha2 - 20 Oct 2003 - David Gibson + * o Correctly turn off shared-key authentication when requested + * (bugfix from Robert J. Moore). + * o Correct airport sleep interfaces for current 2.6 kernels. + * o Add code for key change without disabling/enabling the MAC + * port. This is supposed to allow 802.1x to work sanely, but + * doesn't seem to yet. + * * TODO * o New wireless extensions API (patch from Moustafa * Youssef, updated by Jim Carter and Pavel Roskin). @@ -461,12 +484,14 @@ /* Level of debugging. Used in the macros in orinoco.h */ #ifdef ORINOCO_DEBUG int orinoco_debug = ORINOCO_DEBUG; -module_param(orinoco_debug, int, 0); +module_param(orinoco_debug, int, 0644); +MODULE_PARM_DESC(orinoco_debug, "Debug level"); EXPORT_SYMBOL(orinoco_debug); #endif static int suppress_linkstatus; /* = 0 */ -module_param(suppress_linkstatus, bool, 0); +module_param(suppress_linkstatus, bool, 0644); +MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes"); /********************************************************************/ /* Compile time configuration and compatibility stuff */ @@ -784,7 +809,7 @@ return 1; } - if (! priv->connected) { + if (! netif_carrier_ok(dev)) { /* Oops, the firmware hasn't established a connection, silently drop the packet (this seems to be the safest approach). */ @@ -805,8 +830,9 @@ desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX); err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0); if (err) { - printk(KERN_ERR "%s: Error %d writing Tx descriptor to BAP\n", - dev->name, err); + if (net_ratelimit()) + printk(KERN_ERR "%s: Error %d writing Tx descriptor " + "to BAP\n", dev->name, err); stats->tx_errors++; goto fail; } @@ -836,8 +862,9 @@ err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), txfid, HERMES_802_3_OFFSET); if (err) { - printk(KERN_ERR "%s: Error %d writing packet header to BAP\n", - dev->name, err); + if (net_ratelimit()) + printk(KERN_ERR "%s: Error %d writing packet " + "header to BAP\n", dev->name, err); stats->tx_errors++; goto fail; } @@ -897,8 +924,6 @@ printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", dev->name, fid); return; - } else { - netif_wake_queue(dev); } hermes_write_regn(hw, ALLOCFID, DUMMY_FID); @@ -911,6 +936,8 @@ stats->tx_packets++; + netif_wake_queue(dev); + hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); } @@ -937,6 +964,7 @@ stats->tx_errors++; + netif_wake_queue(dev); hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); } @@ -962,15 +990,17 @@ /* Does the frame have a SNAP header indicating it should be * de-encapsulated to Ethernet-II? */ -static inline int is_ethersnap(struct header_struct *hdr) +static inline int is_ethersnap(void *_hdr) { + u8 *hdr = _hdr; + /* We de-encapsulate all packets which, a) have SNAP headers * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header * and where b) the OUI of the SNAP header is 00:00:00 or * 00:00:f8 - we need both because different APs appear to use * different OUIs for some reason */ - return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0) - && ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) ); + return (memcmp(hdr, &encaps_hdr, 5) == 0) + && ( (hdr[5] == 0x00) || (hdr[5] == 0xf8) ); } static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, @@ -1269,6 +1299,7 @@ case HERMES_INQ_LINKSTATUS: { struct hermes_linkstatus linkstatus; u16 newstatus; + int connected; if (len != sizeof(linkstatus)) { printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", @@ -1280,15 +1311,14 @@ len / 2); newstatus = le16_to_cpu(linkstatus.linkstatus); - if ( (newstatus == HERMES_LINKSTATUS_CONNECTED) - || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) - || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE) ) - priv->connected = 1; - else if ( (newstatus == HERMES_LINKSTATUS_NOT_CONNECTED) - || (newstatus == HERMES_LINKSTATUS_DISCONNECTED) - || (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE) - || (newstatus == HERMES_LINKSTATUS_ASSOC_FAILED) ) - priv->connected = 0; + connected = (newstatus == HERMES_LINKSTATUS_CONNECTED) + || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) + || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE); + + if (connected) + netif_carrier_on(dev); + else + netif_carrier_off(dev); if (newstatus != priv->last_linkstatus) print_linkstatus(dev, newstatus); @@ -1297,8 +1327,8 @@ } break; default: - printk(KERN_DEBUG "%s: Unknown information frame received " - "(type %04x).\n", dev->name, type); + printk(KERN_DEBUG "%s: Unknown information frame received: " + "type 0x%04x, length %d\n", dev->name, type, len); /* We don't actually do anything about it */ break; } @@ -1307,7 +1337,7 @@ static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) { if (net_ratelimit()) - printk(KERN_WARNING "%s: Information frame lost.\n", dev->name); + printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name); } /********************************************************************/ @@ -1366,8 +1396,8 @@ } /* firmware will have to reassociate */ + netif_carrier_off(dev); priv->last_linkstatus = 0xffff; - priv->connected = 0; return 0; } @@ -1430,55 +1460,46 @@ return err; } -static int __orinoco_hw_setup_wep(struct orinoco_private *priv) +/* Change the WEP keys and/or the current keys. Can be called + * either from __orinoco_hw_setup_wep() or directly from + * orinoco_ioctl_setiwencode(). In the later case the association + * with the AP is not broken (if the firmware can handle it), + * which is needed for 802.1x implementations. */ +static int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) { hermes_t *hw = &priv->hw; int err = 0; - int master_wep_flag; - int auth_flag; switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ - if (priv->wep_on) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXKEY_AGERE, - priv->tx_key); - if (err) - return err; - - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFWEPKEYS_AGERE, - &priv->keys); - if (err) - return err; - } + case FIRMWARE_TYPE_AGERE: + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFWEPKEYS_AGERE, + &priv->keys); + if (err) + return err; err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPENABLED_AGERE, - priv->wep_on); + HERMES_RID_CNFTXKEY_AGERE, + priv->tx_key); if (err) return err; break; - - case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ - master_wep_flag = 0; /* Off */ - if (priv->wep_on) { + case FIRMWARE_TYPE_INTERSIL: + case FIRMWARE_TYPE_SYMBOL: + { int keylen; int i; - /* Fudge around firmware weirdness */ + /* Force uniform key length to work around firmware bugs */ keylen = le16_to_cpu(priv->keys[priv->tx_key].len); + if (keylen > LARGE_KEY_SIZE) { + printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", + priv->ndev->name, priv->tx_key, keylen); + return -E2BIG; + } + /* Write all 4 keys */ for(i = 0; i < ORINOCO_MAX_KEYS; i++) { -/* int keylen = le16_to_cpu(priv->keys[i].len); */ - - if (keylen > LARGE_KEY_SIZE) { - printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", - priv->ndev->name, i, keylen); - return -E2BIG; - } - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDEFAULTKEY0 + i, HERMES_BYTES_TO_RECLEN(keylen), @@ -1493,27 +1514,63 @@ priv->tx_key); if (err) return err; - - if (priv->wep_restrict) { - auth_flag = 2; - master_wep_flag = 3; - } else { - /* Authentication is where Intersil and Symbol - * firmware differ... */ - auth_flag = 1; - if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) - master_wep_flag = 3; /* Symbol */ - else - master_wep_flag = 1; /* Intersil */ - } + } + break; + } + return 0; +} + +static int __orinoco_hw_setup_wep(struct orinoco_private *priv) +{ + hermes_t *hw = &priv->hw; + int err = 0; + int master_wep_flag; + int auth_flag; + + if (priv->wep_on) + __orinoco_hw_setup_wepkeys(priv); + + if (priv->wep_restrict) + auth_flag = HERMES_AUTH_SHARED_KEY; + else + auth_flag = HERMES_AUTH_OPEN; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ + if (priv->wep_on) { + /* Enable the shared-key authentication. */ + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFAUTHENTICATION_AGERE, + auth_flag); + } + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFWEPENABLED_AGERE, + priv->wep_on); + if (err) + return err; + break; + + case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ + if (priv->wep_on) { + if (priv->wep_restrict || + (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) + master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | + HERMES_WEP_EXCL_UNENCRYPTED; + else + master_wep_flag = HERMES_WEP_PRIVACY_INVOKED; err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFAUTHENTICATION, auth_flag); if (err) return err; - } + } else + master_wep_flag = 0; + + if (priv->iw_mode == IW_MODE_MONITOR) + master_wep_flag |= HERMES_WEP_HOST_DECRYPT; /* Master WEP setting : on/off */ err = hermes_write_wordrec(hw, USER_BAP, @@ -1523,13 +1580,6 @@ return err; break; - - default: - if (priv->wep_on) { - printk(KERN_ERR "%s: WEP enabled, although not supported!\n", - priv->ndev->name); - return -EINVAL; - } } return 0; @@ -1574,21 +1624,26 @@ } if (priv->has_ibss) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFCREATEIBSS, - priv->createibss); - if (err) { - printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", dev->name, err); - return err; - } + u16 createibss; - if ((strlen(priv->desired_essid) == 0) && (priv->createibss) - && (!priv->has_ibss_any)) { + if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) { printk(KERN_WARNING "%s: This firmware requires an " "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); /* With wvlan_cs, in this case, we would crash. * hopefully, this driver will behave better... * Jean II */ + createibss = 0; + } else { + createibss = priv->createibss; + } + + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFCREATEIBSS, + createibss); + if (err) { + printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", + dev->name, err); + return err; } } @@ -1785,7 +1840,8 @@ } if (p) - printk(KERN_WARNING "Multicast list is longer than mc_count\n"); + printk(KERN_WARNING "%s: Multicast list is " + "longer than mc_count\n", dev->name); err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES, HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), @@ -1878,7 +1934,7 @@ priv->hw_unavailable++; priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */ - priv->connected = 0; + netif_carrier_off(dev); orinoco_unlock(priv, &flags); @@ -2014,51 +2070,81 @@ /* Initialization */ /********************************************************************/ -struct sta_id { +struct comp_id { u16 id, variant, major, minor; } __attribute__ ((packed)); -static int determine_firmware_type(struct net_device *dev, struct sta_id *sta_id) +static inline fwtype_t determine_firmware_type(struct comp_id *nic_id) { - /* FIXME: this is fundamentally broken */ - unsigned int firmver = ((u32)sta_id->major << 16) | sta_id->minor; - - if (sta_id->variant == 1) + if (nic_id->id < 0x8000) return FIRMWARE_TYPE_AGERE; - else if ((sta_id->variant == 2) && - ((firmver == 0x10001) || (firmver == 0x20001))) + else if (nic_id->id == 0x8000 && nic_id->major == 0) return FIRMWARE_TYPE_SYMBOL; else return FIRMWARE_TYPE_INTERSIL; } -static void determine_firmware(struct net_device *dev) +/* Set priv->firmware type, determine firmware properties */ +static int determine_firmware(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err; - struct sta_id sta_id; + struct comp_id nic_id, sta_id; unsigned int firmver; char tmp[SYMBOL_MAX_VER_LEN+1]; + /* Get the hardware version */ + err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); + if (err) { + printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n", + dev->name, err); + return err; + } + + le16_to_cpus(&nic_id.id); + le16_to_cpus(&nic_id.variant); + le16_to_cpus(&nic_id.major); + le16_to_cpus(&nic_id.minor); + printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n", + dev->name, nic_id.id, nic_id.variant, + nic_id.major, nic_id.minor); + + priv->firmware_type = determine_firmware_type(&nic_id); + /* Get the firmware version */ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); if (err) { - printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", + printk(KERN_ERR "%s: Cannot read station identity: error %d\n", dev->name, err); - memset(&sta_id, 0, sizeof(sta_id)); + return err; } le16_to_cpus(&sta_id.id); le16_to_cpus(&sta_id.variant); le16_to_cpus(&sta_id.major); le16_to_cpus(&sta_id.minor); - printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", + printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", dev->name, sta_id.id, sta_id.variant, sta_id.major, sta_id.minor); - if (! priv->firmware_type) - priv->firmware_type = determine_firmware_type(dev, &sta_id); + switch (sta_id.id) { + case 0x15: + printk(KERN_ERR "%s: Primary firmware is active\n", + dev->name); + return -ENODEV; + case 0x14b: + printk(KERN_ERR "%s: Tertiary firmware is active\n", + dev->name); + return -ENODEV; + case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ + case 0x21: /* Symbol Spectrum24 Trilogy */ + break; + default: + printk(KERN_NOTICE "%s: Unknown station ID, please report\n", + dev->name); + break; + } /* Default capabilities */ priv->has_sensitivity = 1; @@ -2066,7 +2152,6 @@ priv->has_preamble = 0; priv->has_port3 = 1; priv->has_ibss = 1; - priv->has_ibss_any = 0; priv->has_wep = 0; priv->has_big_wep = 0; @@ -2075,14 +2160,12 @@ case FIRMWARE_TYPE_AGERE: /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ - printk(KERN_DEBUG "%s: Looks like a Lucent/Agere firmware " - "version %d.%02d\n", dev->name, - sta_id.major, sta_id.minor); + snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, + "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor); firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; priv->has_ibss = (firmver >= 0x60006); - priv->has_ibss_any = (firmver >= 0x60010); priv->has_wep = (firmver >= 0x40020); priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell Gold cards from the others? */ @@ -2121,14 +2204,15 @@ tmp[SYMBOL_MAX_VER_LEN] = '\0'; } - printk(KERN_DEBUG "%s: Looks like a Symbol firmware " - "version [%s] (parsing to %X)\n", dev->name, - tmp, firmver); + snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, + "Symbol %s", tmp); priv->has_ibss = (firmver >= 0x20000); priv->has_wep = (firmver >= 0x15012); priv->has_big_wep = (firmver >= 0x20000); - priv->has_pm = (firmver >= 0x20000) && (firmver < 0x22000); + priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || + (firmver >= 0x29000 && firmver < 0x30000) || + firmver >= 0x31000; priv->has_preamble = (firmver >= 0x20000); priv->ibss_port = 4; /* Tested with Intel firmware : 0x20015 => Jean II */ @@ -2140,9 +2224,9 @@ * different and less well tested */ /* D-Link MAC : 00:40:05:* */ /* Addtron MAC : 00:90:D1:* */ - printk(KERN_DEBUG "%s: Looks like an Intersil firmware " - "version %d.%d.%d\n", dev->name, - sta_id.major, sta_id.minor, sta_id.variant); + snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, + "Intersil %d.%d.%d", sta_id.major, sta_id.minor, + sta_id.variant); firmver = ((unsigned long)sta_id.major << 16) | ((unsigned long)sta_id.minor << 8) | sta_id.variant; @@ -2160,9 +2244,11 @@ priv->ibss_port = 1; } break; - default: - break; } + printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name, + priv->fw_name); + + return 0; } static int orinoco_init(struct net_device *dev) @@ -2188,7 +2274,12 @@ goto out; } - determine_firmware(dev); + err = determine_firmware(dev); + if (err != 0) { + printk(KERN_ERR "%s: Incompatible firmware, aborting\n", + dev->name); + goto out; + } if (priv->has_port3) printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name); @@ -2388,13 +2479,18 @@ * hardware */ INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); + netif_carrier_off(dev); priv->last_linkstatus = 0xffff; - priv->connected = 0; return dev; } +void free_orinocodev(struct net_device *dev) +{ + free_netdev(dev); +} + /********************************************************************/ /* Wireless extensions */ /********************************************************************/ @@ -2686,11 +2782,17 @@ int err = 0; char keybuf[ORINOCO_MAX_KEY_SIZE]; unsigned long flags; - + + if (! priv->has_wep) + return -EOPNOTSUPP; + if (erq->pointer) { - /* We actually have a key to set */ - if ( (erq->length < SMALL_KEY_SIZE) || (erq->length > ORINOCO_MAX_KEY_SIZE) ) - return -EINVAL; + /* We actually have a key to set - check its length */ + if (erq->length > LARGE_KEY_SIZE) + return -E2BIG; + + if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep ) + return -E2BIG; if (copy_from_user(keybuf, erq->pointer, erq->length)) return -EFAULT; @@ -2698,19 +2800,8 @@ if (orinoco_lock(priv, &flags) != 0) return -EBUSY; - + if (erq->pointer) { - if (erq->length > ORINOCO_MAX_KEY_SIZE) { - err = -E2BIG; - goto out; - } - - if ( (erq->length > LARGE_KEY_SIZE) - || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE)) ) { - err = -EINVAL; - goto out; - } - if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) index = priv->tx_key; @@ -2721,7 +2812,7 @@ xlen = SMALL_KEY_SIZE; } else xlen = 0; - + /* Switch on WEP if off */ if ((!enable) && (xlen > 0)) { setindex = index; @@ -2745,10 +2836,9 @@ setindex = index; } } - + if (erq->flags & IW_ENCODE_DISABLED) enable = 0; - /* Only for Prism2 & Symbol cards (so far) - Jean II */ if (erq->flags & IW_ENCODE_OPEN) restricted = 0; if (erq->flags & IW_ENCODE_RESTRICTED) @@ -2761,6 +2851,15 @@ memcpy(priv->keys[index].data, keybuf, erq->length); } priv->tx_key = setindex; + + /* Try fast key change if connected and only keys are changed */ + if (priv->wep_on && enable && (priv->wep_restrict == restricted) && + netif_carrier_ok(dev)) { + err = __orinoco_hw_setup_wepkeys(priv); + /* No need to commit if successful */ + goto out; + } + priv->wep_on = enable; priv->wep_restrict = restricted; @@ -2778,6 +2877,9 @@ char keybuf[ORINOCO_MAX_KEY_SIZE]; unsigned long flags; + if (! priv->has_wep) + return -EOPNOTSUPP; + if (orinoco_lock(priv, &flags) != 0) return -EBUSY; @@ -2788,23 +2890,18 @@ if (! priv->wep_on) erq->flags |= IW_ENCODE_DISABLED; erq->flags |= index + 1; - - /* Only for symbol cards - Jean II */ - if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { - if(priv->wep_restrict) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - } + + if (priv->wep_restrict) + erq->flags |= IW_ENCODE_RESTRICTED; + else + erq->flags |= IW_ENCODE_OPEN; xlen = le16_to_cpu(priv->keys[index].len); erq->length = xlen; - if (erq->pointer) { - memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); - } - + memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); + orinoco_unlock(priv, &flags); if (erq->pointer) { @@ -3045,8 +3142,9 @@ priv->mwo_robust = 0; else { if (frq->fixed) - printk(KERN_WARNING "%s: Fixed fragmentation not \ -supported on this firmware. Using MWO robust instead.\n", dev->name); + printk(KERN_WARNING "%s: Fixed fragmentation is " + "not supported on this firmware. " + "Using MWO robust instead.\n", dev->name); priv->mwo_robust = 1; } } else { @@ -3518,7 +3616,7 @@ } /* Copy stats */ /* In theory, we should disable irqs while copying the stats - * because the rx path migh update it in the middle... + * because the rx path might update it in the middle... * Bah, who care ? - Jean II */ memcpy(&spy_stat, priv->spy_stat, sizeof(struct iw_quality) * IW_MAX_SPY); @@ -3609,22 +3707,12 @@ break; case SIOCSIWENCODE: - if (! priv->has_wep) { - err = -EOPNOTSUPP; - break; - } - err = orinoco_ioctl_setiwencode(dev, &wrq->u.encoding); if (! err) changed = 1; break; case SIOCGIWENCODE: - if (! priv->has_wep) { - err = -EOPNOTSUPP; - break; - } - if (! capable(CAP_NET_ADMIN)) { err = -EPERM; break; @@ -4127,6 +4215,7 @@ /********************************************************************/ EXPORT_SYMBOL(alloc_orinocodev); +EXPORT_SYMBOL(free_orinocodev); EXPORT_SYMBOL(__orinoco_up); EXPORT_SYMBOL(__orinoco_down); diff -Nru a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h --- a/drivers/net/wireless/orinoco.h 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/wireless/orinoco.h 2005-03-08 14:29:45 -05:00 @@ -7,7 +7,7 @@ #ifndef _ORINOCO_H #define _ORINOCO_H -#define DRIVER_VERSION "0.13e" +#define DRIVER_VERSION "0.14alpha2" #include #include @@ -30,6 +30,12 @@ char data[ORINOCO_MAX_KEY_SIZE]; } __attribute__ ((packed)); +typedef enum { + FIRMWARE_TYPE_AGERE, + FIRMWARE_TYPE_INTERSIL, + FIRMWARE_TYPE_SYMBOL +} fwtype_t; + struct orinoco_private { void *card; /* Pointer to card dependent structure */ int (*hard_reset)(struct orinoco_private *); @@ -42,7 +48,6 @@ /* driver state */ int open; u16 last_linkstatus; - int connected; /* Net device stuff */ struct net_device *ndev; @@ -54,19 +59,22 @@ u16 txfid; /* Capabilities of the hardware/firmware */ - int firmware_type; -#define FIRMWARE_TYPE_AGERE 1 -#define FIRMWARE_TYPE_INTERSIL 2 -#define FIRMWARE_TYPE_SYMBOL 3 - int has_ibss, has_port3, has_ibss_any, ibss_port; - int has_wep, has_big_wep; - int has_mwo; - int has_pm; - int has_preamble; - int has_sensitivity; + fwtype_t firmware_type; + char fw_name[32]; + int ibss_port; int nicbuf_size; u16 channel_mask; - int broken_disableport; + + /* Boolean capabilities */ + unsigned int has_ibss:1; + unsigned int has_port3:1; + unsigned int has_wep:1; + unsigned int has_big_wep:1; + unsigned int has_mwo:1; + unsigned int has_pm:1; + unsigned int has_preamble:1; + unsigned int has_sensitivity:1; + unsigned int broken_disableport:1; /* Configuration paramaters */ u32 iw_mode; @@ -108,6 +116,7 @@ extern struct net_device *alloc_orinocodev(int sizeof_card, int (*hard_reset)(struct orinoco_private *)); +extern void free_orinocodev(struct net_device *dev); extern int __orinoco_up(struct net_device *dev); extern int __orinoco_down(struct net_device *dev); extern int orinoco_stop(struct net_device *dev); @@ -127,7 +136,7 @@ { spin_lock_irqsave(&priv->lock, *flags); if (priv->hw_unavailable) { - printk(KERN_DEBUG "orinoco_lock() called with hw_unavailable (dev=%p)\n", + DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n", priv->ndev); spin_unlock_irqrestore(&priv->lock, *flags); return -EBUSY; diff -Nru a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c --- a/drivers/net/wireless/orinoco_cs.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/wireless/orinoco_cs.c 2005-03-08 14:29:45 -05:00 @@ -57,8 +57,8 @@ /* Some D-Link cards have buggy CIS. They do work at 5v properly, but * don't have any CIS entry for it. This workaround it... */ static int ignore_cis_vcc; /* = 0 */ - module_param(ignore_cis_vcc, int, 0); +MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); /********************************************************************/ /* Magic constants */ @@ -128,6 +128,7 @@ if (err) return err; + msleep(100); clear_bit(0, &card->hard_reset_in_progress); return 0; @@ -166,9 +167,10 @@ link->priv = dev; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->irq.Handler = NULL; + link->irq.Handler = orinoco_interrupt; + link->irq.Instance = dev; /* General socket configuration defaults can go here. In this * client, we assume very little, and rely on the CIS for @@ -235,7 +237,7 @@ dev); unregister_netdev(dev); } - free_netdev(dev); + free_orinocodev(dev); } /* orinoco_cs_detach */ /* @@ -262,6 +264,7 @@ cisinfo_t info; tuple_t tuple; cisparse_t parse; + void __iomem *mem; CS_CHECK(ValidateCIS, pcmcia_validate_cis(handle, &info)); @@ -308,8 +311,8 @@ cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); cistpl_cftable_entry_t dflt = { .index = 0 }; - if (pcmcia_get_tuple_data(handle, &tuple) != 0 || - pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + if ( (pcmcia_get_tuple_data(handle, &tuple) != 0) + || (pcmcia_parse_tuple(handle, &tuple, &parse) != 0)) goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) @@ -348,8 +351,7 @@ dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; + link->conf.Attributes |= CONF_ENABLE_IRQ; /* IO window settings */ link->io.NumPorts1 = link->io.NumPorts2 = 0; @@ -390,7 +392,7 @@ last_ret = pcmcia_get_next_tuple(handle, &tuple); if (last_ret == CS_NO_MORE_ITEMS) { printk(KERN_ERR PFX "GetNextTuple(): No matching " - "CIS configuration, maybe you need the " + "CIS configuration. Maybe you need the " "ignore_cis_vcc=1 parameter.\n"); goto cs_failed; } @@ -401,20 +403,16 @@ * a handler to the interrupt, unless the 'Handler' member of * the irq structure is initialized. */ - if (link->conf.Attributes & CONF_ENABLE_IRQ) { - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->irq.Handler = orinoco_interrupt; - link->irq.Instance = dev; - - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); - } + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); /* We initialize the hermes structure before completing PCMCIA * configuration just in case the interrupt handler gets * called. */ - hermes_struct_init(hw, link->io.BasePort1, - HERMES_IO, HERMES_16BIT_REGSPACING); + mem = ioport_map(link->io.BasePort1, link->io.NumPorts1); + if (!mem) + goto cs_failed; + + hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); /* * This actually configures the PCMCIA socket -- setting up @@ -430,8 +428,6 @@ SET_MODULE_OWNER(dev); card->node.major = card->node.minor = 0; - /* register_netdev will give us an ethX name */ - dev->name[0] = '\0'; SET_NETDEV_DEV(dev, &handle_to_dev(handle)); /* Tell the stack we exist */ if (register_netdev(dev) != 0) { @@ -454,8 +450,7 @@ if (link->conf.Vpp1) printk(", Vpp %d.%d", link->conf.Vpp1 / 10, link->conf.Vpp1 % 10); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %d", link->irq.AssignedIRQ); + printk(", irq %d", link->irq.AssignedIRQ); if (link->io.NumPorts1) printk(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); @@ -498,6 +493,8 @@ if (link->irq.AssignedIRQ) pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; + if (priv->hw.iobase) + ioport_unmap(priv->hw.iobase); } /* orinoco_cs_release */ /* @@ -519,12 +516,12 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - orinoco_lock(priv, &flags); + unsigned long flags; + spin_lock_irqsave(&priv->lock, flags); netif_device_detach(dev); priv->hw_unavailable++; - - orinoco_unlock(priv, &flags); + spin_unlock_irqrestore(&priv->lock, flags); } break; diff -Nru a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c --- a/drivers/net/wireless/orinoco_pci.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/wireless/orinoco_pci.c 2005-03-08 14:29:45 -05:00 @@ -129,6 +129,11 @@ #define HERMES_PCI_COR_OFFT (500) /* ms */ #define HERMES_PCI_COR_BUSYT (500) /* ms */ +/* Orinoco PCI specific data */ +struct orinoco_pci_card { + void __iomem *pci_ioaddr; +}; + /* * Do a soft reset of the PCI card using the Configuration Option Register * We need this to get going... @@ -151,25 +156,11 @@ /* Assert the reset until the card notice */ hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK); - printk(KERN_NOTICE "Reset done"); - timeout = jiffies + (HERMES_PCI_COR_ONT * HZ / 1000); - while(time_before(jiffies, timeout)) { - printk("."); - mdelay(1); - } - printk(";\n"); - //mdelay(HERMES_PCI_COR_ONT); + mdelay(HERMES_PCI_COR_ONT); /* Give time for the card to recover from this hard effort */ hermes_write_regn(hw, PCI_COR, 0x0000); - printk(KERN_NOTICE "Clear Reset"); - timeout = jiffies + (HERMES_PCI_COR_OFFT * HZ / 1000); - while(time_before(jiffies, timeout)) { - printk("."); - mdelay(1); - } - printk(";\n"); - //mdelay(HERMES_PCI_COR_OFFT); + mdelay(HERMES_PCI_COR_OFFT); /* The card is ready when it's no longer busy */ timeout = jiffies + (HERMES_PCI_COR_BUSYT * HZ / 1000); @@ -178,12 +169,12 @@ mdelay(1); reg = hermes_read_regn(hw, CMD); } - /* Did we timeout ? */ - if(time_after_eq(jiffies, timeout)) { + + /* Still busy? */ + if (reg & HERMES_CMD_BUSY) { printk(KERN_ERR PFX "Busy timeout\n"); return -ETIMEDOUT; } - printk(KERN_NOTICE "pci_cor : reg = 0x%X - %lX - %lX\n", reg, timeout, jiffies); return 0; } @@ -196,84 +187,93 @@ { int err = 0; unsigned long pci_iorange; - u16 *pci_ioaddr = NULL; + u16 __iomem *pci_ioaddr = NULL; unsigned long pci_iolen; struct orinoco_private *priv = NULL; + struct orinoco_pci_card *card; struct net_device *dev = NULL; err = pci_enable_device(pdev); - if (err) - return -EIO; + if (err) { + printk(KERN_ERR PFX "Cannot enable PCI device\n"); + return err; + } + + err = pci_request_regions(pdev, DRIVER_NAME); + if (err != 0) { + printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); + goto fail_resources; + } /* Resource 0 is mapped to the hermes registers */ pci_iorange = pci_resource_start(pdev, 0); pci_iolen = pci_resource_len(pdev, 0); pci_ioaddr = ioremap(pci_iorange, pci_iolen); - if (! pci_iorange) - goto fail; + if (!pci_iorange) { + printk(KERN_ERR PFX "Cannot remap hardware registers\n"); + goto fail_map; + } /* Allocate network device */ - dev = alloc_orinocodev(0, NULL); + dev = alloc_orinocodev(sizeof(*card), orinoco_pci_cor_reset); if (! dev) { err = -ENOMEM; - goto fail; + goto fail_alloc; } priv = netdev_priv(dev); - dev->base_addr = (unsigned long) pci_ioaddr; + card = priv->card; + card->pci_ioaddr = pci_ioaddr; dev->mem_start = pci_iorange; dev->mem_end = pci_iorange + pci_iolen - 1; SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - printk(KERN_DEBUG PFX - "Detected Orinoco/Prism2 PCI device at %s, mem:0x%lX to 0x%lX -> 0x%p, irq:%d\n", - pci_name(pdev), dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq); + hermes_struct_init(&priv->hw, pci_ioaddr, HERMES_32BIT_REGSPACING); - hermes_struct_init(&priv->hw, dev->base_addr, - HERMES_MEM, HERMES_32BIT_REGSPACING); - pci_set_drvdata(pdev, dev); + printk(KERN_DEBUG PFX "Detected device %s, mem:0x%lx-0x%lx, irq %d\n", + pci_name(pdev), dev->mem_start, dev->mem_end, pdev->irq); err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, dev); if (err) { - printk(KERN_ERR PFX "Error allocating IRQ %d.\n", - pdev->irq); + printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; - goto fail; + goto fail_irq; } dev->irq = pdev->irq; /* Perform a COR reset to start the card */ - if(orinoco_pci_cor_reset(priv) != 0) { - printk(KERN_ERR "%s: Failed to start the card\n", dev->name); - err = -ETIMEDOUT; + err = orinoco_pci_cor_reset(priv); + if (err) { + printk(KERN_ERR PFX "Initial reset failed\n"); goto fail; } - /* Override the normal firmware detection - the Prism 2.5 PCI - * cards look like Lucent firmware but are actually Intersil */ - priv->firmware_type = FIRMWARE_TYPE_INTERSIL; - err = register_netdev(dev); if (err) { - printk(KERN_ERR "%s: Failed to register net device\n", dev->name); + printk(KERN_ERR PFX "Failed to register net device\n"); goto fail; } + pci_set_drvdata(pdev, dev); + return 0; fail: - if (dev) { - if (dev->irq) - free_irq(dev->irq, dev); + free_irq(pdev->irq, dev); - free_netdev(dev); - } + fail_irq: + pci_set_drvdata(pdev, NULL); + free_orinocodev(dev); - if (pci_ioaddr) - iounmap(pci_ioaddr); + fail_alloc: + iounmap(pci_ioaddr); + fail_map: + pci_release_regions(pdev); + + fail_resources: pci_disable_device(pdev); return err; @@ -283,18 +283,14 @@ { struct net_device *dev = pci_get_drvdata(pdev); struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_pci_card *card = priv->card; unregister_netdev(dev); - - if (dev->irq) - free_irq(dev->irq, dev); - - if (priv->hw.iobase) - iounmap((unsigned char *) priv->hw.iobase); - + free_irq(dev->irq, dev); pci_set_drvdata(pdev, NULL); - free_netdev(dev); - + free_orinocodev(dev); + iounmap(card->pci_ioaddr); + pci_release_regions(pdev); pci_disable_device(pdev); } @@ -326,6 +322,9 @@ orinoco_unlock(priv, &flags); + pci_save_state(pdev); + pci_set_power_state(pdev, 3); + return 0; } @@ -338,6 +337,9 @@ printk(KERN_DEBUG "%s: Orinoco-PCI waking up\n", dev->name); + pci_set_power_state(pdev, 0); + pci_restore_state(pdev); + err = orinoco_reinit_firmware(dev); if (err) { printk(KERN_ERR "%s: Error %d re-initializing firmware on orinoco_pci_resume()\n", @@ -368,6 +370,8 @@ {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, /* Intersil Prism 2.5 */ {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, + /* Samsung MagicLAN SWL-2210P */ + {0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,}, {0,}, }; diff -Nru a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c --- a/drivers/net/wireless/orinoco_plx.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/wireless/orinoco_plx.c 2005-03-08 14:29:45 -05:00 @@ -142,146 +142,199 @@ #include "hermes.h" #include "orinoco.h" -#define COR_OFFSET (0x3e0/2) /* COR attribute offset of Prism2 PC card */ +#define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */ #define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ +#define COR_RESET (0x80) /* reset bit in the COR register */ +#define PLX_RESET_TIME (500) /* milliseconds */ #define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */ #define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */ -static const u16 cis_magic[] = { - 0x0001, 0x0003, 0x0000, 0x0000, 0x00ff, 0x0017, 0x0004, 0x0067 +static const u8 cis_magic[] = { + 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67 }; +/* Orinoco PLX specific data */ +struct orinoco_plx_card { + void __iomem *attr_mem; +}; + +/* + * Do a soft reset of the card using the Configuration Option Register + */ +static int orinoco_plx_cor_reset(struct orinoco_private *priv) +{ + hermes_t *hw = &priv->hw; + struct orinoco_plx_card *card = priv->card; + u8 __iomem *attr_mem = card->attr_mem; + unsigned long timeout; + u16 reg; + + writeb(COR_VALUE | COR_RESET, attr_mem + COR_OFFSET); + mdelay(1); + + writeb(COR_VALUE, attr_mem + COR_OFFSET); + mdelay(1); + + /* Just in case, wait more until the card is no longer busy */ + timeout = jiffies + (PLX_RESET_TIME * HZ / 1000); + reg = hermes_read_regn(hw, CMD); + while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { + mdelay(1); + reg = hermes_read_regn(hw, CMD); + } + + /* Did we timeout ? */ + if (reg & HERMES_CMD_BUSY) { + printk(KERN_ERR PFX "Busy timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + + static int orinoco_plx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0; - u16 *attr_mem = NULL; - u32 reg, addr; + u8 __iomem *attr_mem = NULL; + u32 csr_reg, plx_addr; struct orinoco_private *priv = NULL; + struct orinoco_plx_card *card; unsigned long pccard_ioaddr = 0; unsigned long pccard_iolen = 0; struct net_device *dev = NULL; + void __iomem *mem; int i; err = pci_enable_device(pdev); - if (err) - return -EIO; - - /* Resource 2 is mapped to the PCMCIA space */ - attr_mem = ioremap(pci_resource_start(pdev, 2), PAGE_SIZE); - if (! attr_mem) - goto fail; - - printk(KERN_DEBUG "orinoco_plx: CIS: "); - for (i = 0; i < 16; i++) { - printk("%02X:", (int)attr_mem[i]); + if (err) { + printk(KERN_ERR PFX "Cannot enable PCI device\n"); + return err; } - printk("\n"); - /* Verify whether PC card is present */ - /* FIXME: we probably need to be smarted about this */ - if (memcmp(attr_mem, cis_magic, sizeof(cis_magic)) != 0) { - printk(KERN_ERR "orinoco_plx: The CIS value of Prism2 PC card is invalid.\n"); - err = -EIO; - goto fail; + err = pci_request_regions(pdev, DRIVER_NAME); + if (err != 0) { + printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); + goto fail_resources; } - /* PCMCIA COR is the first byte following CIS: this write should - * enable I/O mode and select level-triggered interrupts */ - attr_mem[COR_OFFSET] = COR_VALUE; - mdelay(1); - reg = attr_mem[COR_OFFSET]; - if (reg != COR_VALUE) { - printk(KERN_ERR "orinoco_plx: Error setting COR value (reg=%x)\n", reg); - goto fail; - } - - iounmap(attr_mem); - attr_mem = NULL; /* done with this now, it seems */ + /* Resource 1 is mapped to PLX-specific registers */ + plx_addr = pci_resource_start(pdev, 1); - /* bjoern: We need to tell the card to enable interrupts, in - case the serial eprom didn't do this already. See the - PLX9052 data book, p8-1 and 8-24 for reference. */ - addr = pci_resource_start(pdev, 1); - reg = 0; - reg = inl(addr+PLX_INTCSR); - if (reg & PLX_INTCSR_INTEN) - printk(KERN_DEBUG "orinoco_plx: " - "Local Interrupt already enabled\n"); - else { - reg |= PLX_INTCSR_INTEN; - outl(reg, addr+PLX_INTCSR); - reg = inl(addr+PLX_INTCSR); - if(!(reg & PLX_INTCSR_INTEN)) { - printk(KERN_ERR "orinoco_plx: " - "Couldn't enable Local Interrupts\n"); - goto fail; - } + /* Resource 2 is mapped to the PCMCIA attribute memory */ + attr_mem = ioremap(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + if (!attr_mem) { + printk(KERN_ERR PFX "Cannot remap PCMCIA space\n"); + goto fail_map_attr; } - /* and 3 to the PCMCIA slot I/O address space */ + /* Resource 3 is mapped to the PCMCIA I/O address space */ pccard_ioaddr = pci_resource_start(pdev, 3); pccard_iolen = pci_resource_len(pdev, 3); - if (! request_region(pccard_ioaddr, pccard_iolen, DRIVER_NAME)) { - printk(KERN_ERR "orinoco_plx: I/O resource 0x%lx @ 0x%lx busy\n", - pccard_iolen, pccard_ioaddr); - pccard_ioaddr = 0; - err = -EBUSY; - goto fail; + + mem = pci_iomap(pdev, 3, 0); + if (!mem) { + err = -ENOMEM; + goto fail_map_io; } /* Allocate network device */ - dev = alloc_orinocodev(0, NULL); - if (! dev) { + dev = alloc_orinocodev(sizeof(*card), orinoco_plx_cor_reset); + if (!dev) { + printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; - goto fail; + goto fail_alloc; } priv = netdev_priv(dev); + card = priv->card; + card->attr_mem = attr_mem; dev->base_addr = pccard_ioaddr; SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); + hermes_struct_init(&priv->hw, mem, HERMES_16BIT_REGSPACING); + printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 PLX device " "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq, pccard_ioaddr); - hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_IO, - HERMES_16BIT_REGSPACING); - pci_set_drvdata(pdev, dev); - err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, dev); if (err) { - printk(KERN_ERR PFX "Error allocating IRQ %d.\n", pdev->irq); + printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; - goto fail; + goto fail_irq; } dev->irq = pdev->irq; + /* bjoern: We need to tell the card to enable interrupts, in + case the serial eprom didn't do this already. See the + PLX9052 data book, p8-1 and 8-24 for reference. */ + csr_reg = inl(plx_addr + PLX_INTCSR); + if (!(csr_reg & PLX_INTCSR_INTEN)) { + csr_reg |= PLX_INTCSR_INTEN; + outl(csr_reg, plx_addr + PLX_INTCSR); + csr_reg = inl(plx_addr + PLX_INTCSR); + if (!(csr_reg & PLX_INTCSR_INTEN)) { + printk(KERN_ERR PFX "Cannot enable interrupts\n"); + goto fail; + } + } + + err = orinoco_plx_cor_reset(priv); + if (err) { + printk(KERN_ERR PFX "Initial reset failed\n"); + goto fail; + } + + printk(KERN_DEBUG PFX "CIS: "); + for (i = 0; i < 16; i++) { + printk("%02X:", readb(attr_mem + 2*i)); + } + printk("\n"); + + /* Verify whether a supported PC card is present */ + /* FIXME: we probably need to be smarted about this */ + for (i = 0; i < sizeof(cis_magic); i++) { + if (cis_magic[i] != readb(attr_mem +2*i)) { + printk(KERN_ERR PFX "The CIS value of Prism2 PC " + "card is unexpected\n"); + err = -EIO; + goto fail; + } + } + err = register_netdev(dev); - if (err) + if (err) { + printk(KERN_ERR PFX "Cannot register network device\n"); goto fail; + } + + pci_set_drvdata(pdev, dev); return 0; fail: - printk(KERN_DEBUG PFX "init_one(), FAIL!\n"); + free_irq(pdev->irq, dev); - if (dev) { - if (dev->irq) - free_irq(dev->irq, dev); - - free_netdev(dev); - } + fail_irq: + pci_set_drvdata(pdev, NULL); + free_orinocodev(dev); - if (pccard_ioaddr) - release_region(pccard_ioaddr, pccard_iolen); + fail_alloc: + pci_iounmap(pdev, mem); + + fail_map_io: + iounmap(attr_mem); - if (attr_mem) - iounmap(attr_mem); + fail_map_attr: + pci_release_regions(pdev); + fail_resources: pci_disable_device(pdev); return err; @@ -290,20 +343,19 @@ static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_plx_card *card = priv->card; + u8 __iomem *attr_mem = card->attr_mem; BUG_ON(! dev); unregister_netdev(dev); - - if (dev->irq) - free_irq(dev->irq, dev); - + free_irq(dev->irq, dev); pci_set_drvdata(pdev, NULL); - - free_netdev(dev); - - release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3)); - + free_orinocodev(dev); + pci_iounmap(pdev, priv->hw.iobase); + iounmap(attr_mem); + pci_release_regions(pdev); pci_disable_device(pdev); } @@ -352,8 +404,7 @@ static void __exit orinoco_plx_exit(void) { pci_unregister_driver(&orinoco_plx_driver); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ); + ssleep(1); } module_init(orinoco_plx_init); diff -Nru a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c --- a/drivers/net/wireless/orinoco_tmd.c 2005-03-08 14:29:45 -05:00 +++ b/drivers/net/wireless/orinoco_tmd.c 2005-03-08 14:29:45 -05:00 @@ -79,90 +79,137 @@ #include "orinoco.h" #define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ +#define COR_RESET (0x80) /* reset bit in the COR register */ +#define TMD_RESET_TIME (500) /* milliseconds */ + +/* Orinoco TMD specific data */ +struct orinoco_tmd_card { + u32 tmd_io; +}; + + +/* + * Do a soft reset of the card using the Configuration Option Register + */ +static int orinoco_tmd_cor_reset(struct orinoco_private *priv) +{ + hermes_t *hw = &priv->hw; + struct orinoco_tmd_card *card = priv->card; + u32 addr = card->tmd_io; + unsigned long timeout; + u16 reg; + + outb(COR_VALUE | COR_RESET, addr); + mdelay(1); + + outb(COR_VALUE, addr); + mdelay(1); + + /* Just in case, wait more until the card is no longer busy */ + timeout = jiffies + (TMD_RESET_TIME * HZ / 1000); + reg = hermes_read_regn(hw, CMD); + while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { + mdelay(1); + reg = hermes_read_regn(hw, CMD); + } + + /* Did we timeout ? */ + if (reg & HERMES_CMD_BUSY) { + printk(KERN_ERR PFX "Busy timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + static int orinoco_tmd_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0; - u32 reg, addr; struct orinoco_private *priv = NULL; - unsigned long pccard_ioaddr = 0; - unsigned long pccard_iolen = 0; + struct orinoco_tmd_card *card; struct net_device *dev = NULL; + void __iomem *mem; err = pci_enable_device(pdev); - if (err) - return -EIO; + if (err) { + printk(KERN_ERR PFX "Cannot enable PCI device\n"); + return err; + } - printk(KERN_DEBUG PFX "TMD setup\n"); - pccard_ioaddr = pci_resource_start(pdev, 2); - pccard_iolen = pci_resource_len(pdev, 2); - if (! request_region(pccard_ioaddr, pccard_iolen, DRIVER_NAME)) { - printk(KERN_ERR PFX "I/O resource at 0x%lx len 0x%lx busy\n", - pccard_ioaddr, pccard_iolen); - pccard_ioaddr = 0; - err = -EBUSY; - goto fail; + err = pci_request_regions(pdev, DRIVER_NAME); + if (err != 0) { + printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); + goto fail_resources; } - addr = pci_resource_start(pdev, 1); - outb(COR_VALUE, addr); - mdelay(1); - reg = inb(addr); - if (reg != COR_VALUE) { - printk(KERN_ERR PFX "Error setting TMD COR values %x should be %x\n", reg, COR_VALUE); - err = -EIO; - goto fail; + + mem = pci_iomap(pdev, 2, 0); + if (! mem) { + err = -ENOMEM; + goto fail_iomap; } /* Allocate network device */ - dev = alloc_orinocodev(0, NULL); + dev = alloc_orinocodev(sizeof(*card), orinoco_tmd_cor_reset); if (! dev) { + printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; - goto fail; + goto fail_alloc; } priv = netdev_priv(dev); - dev->base_addr = pccard_ioaddr; + card = priv->card; + card->tmd_io = pci_resource_start(pdev, 1); + dev->base_addr = pci_resource_start(pdev, 2); SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); + hermes_struct_init(&priv->hw, mem, HERMES_16BIT_REGSPACING); + printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 TMD device " "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq, - pccard_ioaddr); - - hermes_struct_init(&(priv->hw), dev->base_addr, - HERMES_IO, HERMES_16BIT_REGSPACING); - pci_set_drvdata(pdev, dev); + dev->base_addr); err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, dev); if (err) { - printk(KERN_ERR PFX "Error allocating IRQ %d.\n", - pdev->irq); + printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; - goto fail; + goto fail_irq; } dev->irq = pdev->irq; + err = orinoco_tmd_cor_reset(priv); + if (err) { + printk(KERN_ERR PFX "Initial reset failed\n"); + goto fail; + } + err = register_netdev(dev); - if (err) + if (err) { + printk(KERN_ERR PFX "Cannot register network device\n"); goto fail; + } + + pci_set_drvdata(pdev, dev); return 0; fail: - printk(KERN_DEBUG PFX "init_one(), FAIL!\n"); + free_irq(pdev->irq, dev); - if (dev) { - if (dev->irq) - free_irq(dev->irq, dev); - - free_netdev(dev); - } + fail_irq: + pci_set_drvdata(pdev, NULL); + free_orinocodev(dev); + + fail_alloc: + pci_iounmap(pdev, mem); - if (pccard_ioaddr) - release_region(pccard_ioaddr, pccard_iolen); + fail_iomap: + pci_release_regions(pdev); + fail_resources: pci_disable_device(pdev); return err; @@ -171,20 +218,16 @@ static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = dev->priv; BUG_ON(! dev); unregister_netdev(dev); - - if (dev->irq) - free_irq(dev->irq, dev); - + free_irq(dev->irq, dev); pci_set_drvdata(pdev, NULL); - - free_netdev(dev); - - release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); - + free_orinocodev(dev); + pci_iounmap(pdev, priv->hw.iobase); + pci_release_regions(pdev); pci_disable_device(pdev); } @@ -218,8 +261,7 @@ static void __exit orinoco_tmd_exit(void) { pci_unregister_driver(&orinoco_tmd_driver); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ); + ssleep(1); } module_init(orinoco_tmd_init); diff -Nru a/include/linux/mv643xx.h b/include/linux/mv643xx.h --- a/include/linux/mv643xx.h 2005-03-08 14:29:45 -05:00 +++ b/include/linux/mv643xx.h 2005-03-08 14:29:45 -05:00 @@ -1,5 +1,5 @@ /* - * mv64340.h - MV-64340 Internal registers definition file. + * mv643xx.h - MV-643XX Internal registers definition file. * * Copyright 2002 Momentum Computer, Inc. * Author: Matthew Dharm @@ -10,8 +10,8 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ -#ifndef __ASM_MV64340_H -#define __ASM_MV64340_H +#ifndef __ASM_MV643XX_H +#define __ASM_MV643XX_H #ifdef __MIPS__ #include @@ -662,116 +662,119 @@ /* Ethernet Unit Registers */ /****************************************/ -#define MV64340_ETH_PHY_ADDR_REG 0x2000 -#define MV64340_ETH_SMI_REG 0x2004 -#define MV64340_ETH_UNIT_DEFAULT_ADDR_REG 0x2008 -#define MV64340_ETH_UNIT_DEFAULTID_REG 0x200c -#define MV64340_ETH_UNIT_INTERRUPT_CAUSE_REG 0x2080 -#define MV64340_ETH_UNIT_INTERRUPT_MASK_REG 0x2084 -#define MV64340_ETH_UNIT_INTERNAL_USE_REG 0x24fc -#define MV64340_ETH_UNIT_ERROR_ADDR_REG 0x2094 -#define MV64340_ETH_BAR_0 0x2200 -#define MV64340_ETH_BAR_1 0x2208 -#define MV64340_ETH_BAR_2 0x2210 -#define MV64340_ETH_BAR_3 0x2218 -#define MV64340_ETH_BAR_4 0x2220 -#define MV64340_ETH_BAR_5 0x2228 -#define MV64340_ETH_SIZE_REG_0 0x2204 -#define MV64340_ETH_SIZE_REG_1 0x220c -#define MV64340_ETH_SIZE_REG_2 0x2214 -#define MV64340_ETH_SIZE_REG_3 0x221c -#define MV64340_ETH_SIZE_REG_4 0x2224 -#define MV64340_ETH_SIZE_REG_5 0x222c -#define MV64340_ETH_HEADERS_RETARGET_BASE_REG 0x2230 -#define MV64340_ETH_HEADERS_RETARGET_CONTROL_REG 0x2234 -#define MV64340_ETH_HIGH_ADDR_REMAP_REG_0 0x2280 -#define MV64340_ETH_HIGH_ADDR_REMAP_REG_1 0x2284 -#define MV64340_ETH_HIGH_ADDR_REMAP_REG_2 0x2288 -#define MV64340_ETH_HIGH_ADDR_REMAP_REG_3 0x228c -#define MV64340_ETH_BASE_ADDR_ENABLE_REG 0x2290 -#define MV64340_ETH_ACCESS_PROTECTION_REG(port) (0x2294 + (port<<2)) -#define MV64340_ETH_MIB_COUNTERS_BASE(port) (0x3000 + (port<<7)) -#define MV64340_ETH_PORT_CONFIG_REG(port) (0x2400 + (port<<10)) -#define MV64340_ETH_PORT_CONFIG_EXTEND_REG(port) (0x2404 + (port<<10)) -#define MV64340_ETH_MII_SERIAL_PARAMETRS_REG(port) (0x2408 + (port<<10)) -#define MV64340_ETH_GMII_SERIAL_PARAMETRS_REG(port) (0x240c + (port<<10)) -#define MV64340_ETH_VLAN_ETHERTYPE_REG(port) (0x2410 + (port<<10)) -#define MV64340_ETH_MAC_ADDR_LOW(port) (0x2414 + (port<<10)) -#define MV64340_ETH_MAC_ADDR_HIGH(port) (0x2418 + (port<<10)) -#define MV64340_ETH_SDMA_CONFIG_REG(port) (0x241c + (port<<10)) -#define MV64340_ETH_DSCP_0(port) (0x2420 + (port<<10)) -#define MV64340_ETH_DSCP_1(port) (0x2424 + (port<<10)) -#define MV64340_ETH_DSCP_2(port) (0x2428 + (port<<10)) -#define MV64340_ETH_DSCP_3(port) (0x242c + (port<<10)) -#define MV64340_ETH_DSCP_4(port) (0x2430 + (port<<10)) -#define MV64340_ETH_DSCP_5(port) (0x2434 + (port<<10)) -#define MV64340_ETH_DSCP_6(port) (0x2438 + (port<<10)) -#define MV64340_ETH_PORT_SERIAL_CONTROL_REG(port) (0x243c + (port<<10)) -#define MV64340_ETH_VLAN_PRIORITY_TAG_TO_PRIORITY(port) (0x2440 + (port<<10)) -#define MV64340_ETH_PORT_STATUS_REG(port) (0x2444 + (port<<10)) -#define MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port) (0x2448 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_FIXED_PRIORITY(port) (0x244c + (port<<10)) -#define MV64340_ETH_PORT_TX_TOKEN_BUCKET_RATE_CONFIG(port) (0x2450 + (port<<10)) -#define MV64340_ETH_MAXIMUM_TRANSMIT_UNIT(port) (0x2458 + (port<<10)) -#define MV64340_ETH_PORT_MAXIMUM_TOKEN_BUCKET_SIZE(port) (0x245c + (port<<10)) -#define MV64340_ETH_INTERRUPT_CAUSE_REG(port) (0x2460 + (port<<10)) -#define MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port) (0x2464 + (port<<10)) -#define MV64340_ETH_INTERRUPT_MASK_REG(port) (0x2468 + (port<<10)) -#define MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port) (0x246c + (port<<10)) -#define MV64340_ETH_RX_FIFO_URGENT_THRESHOLD_REG(port) (0x2470 + (port<<10)) -#define MV64340_ETH_TX_FIFO_URGENT_THRESHOLD_REG(port) (0x2474 + (port<<10)) -#define MV64340_ETH_RX_MINIMAL_FRAME_SIZE_REG(port) (0x247c + (port<<10)) -#define MV64340_ETH_RX_DISCARDED_FRAMES_COUNTER(port) (0x2484 + (port<<10) -#define MV64340_ETH_PORT_DEBUG_0_REG(port) (0x248c + (port<<10)) -#define MV64340_ETH_PORT_DEBUG_1_REG(port) (0x2490 + (port<<10)) -#define MV64340_ETH_PORT_INTERNAL_ADDR_ERROR_REG(port) (0x2494 + (port<<10)) -#define MV64340_ETH_INTERNAL_USE_REG(port) (0x24fc + (port<<10)) -#define MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port) (0x2680 + (port<<10)) -#define MV64340_ETH_CURRENT_SERVED_TX_DESC_PTR(port) (0x2684 + (port<<10)) -#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port) (0x260c + (port<<10)) -#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_1(port) (0x261c + (port<<10)) -#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_2(port) (0x262c + (port<<10)) -#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_3(port) (0x263c + (port<<10)) -#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_4(port) (0x264c + (port<<10)) -#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_5(port) (0x265c + (port<<10)) -#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_6(port) (0x266c + (port<<10)) -#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_7(port) (0x267c + (port<<10)) -#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(port) (0x26c0 + (port<<10)) -#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_1(port) (0x26c4 + (port<<10)) -#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_2(port) (0x26c8 + (port<<10)) -#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_3(port) (0x26cc + (port<<10)) -#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_4(port) (0x26d0 + (port<<10)) -#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_5(port) (0x26d4 + (port<<10)) -#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_6(port) (0x26d8 + (port<<10)) -#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_7(port) (0x26dc + (port<<10)) -#define MV64340_ETH_TX_QUEUE_0_TOKEN_BUCKET_COUNT(port) (0x2700 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_1_TOKEN_BUCKET_COUNT(port) (0x2710 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_2_TOKEN_BUCKET_COUNT(port) (0x2720 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_3_TOKEN_BUCKET_COUNT(port) (0x2730 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_4_TOKEN_BUCKET_COUNT(port) (0x2740 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_5_TOKEN_BUCKET_COUNT(port) (0x2750 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_6_TOKEN_BUCKET_COUNT(port) (0x2760 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_7_TOKEN_BUCKET_COUNT(port) (0x2770 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_0_TOKEN_BUCKET_CONFIG(port) (0x2704 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_1_TOKEN_BUCKET_CONFIG(port) (0x2714 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_2_TOKEN_BUCKET_CONFIG(port) (0x2724 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_3_TOKEN_BUCKET_CONFIG(port) (0x2734 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_4_TOKEN_BUCKET_CONFIG(port) (0x2744 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_5_TOKEN_BUCKET_CONFIG(port) (0x2754 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_6_TOKEN_BUCKET_CONFIG(port) (0x2764 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_7_TOKEN_BUCKET_CONFIG(port) (0x2774 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_0_ARBITER_CONFIG(port) (0x2708 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_1_ARBITER_CONFIG(port) (0x2718 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_2_ARBITER_CONFIG(port) (0x2728 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_3_ARBITER_CONFIG(port) (0x2738 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_4_ARBITER_CONFIG(port) (0x2748 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_5_ARBITER_CONFIG(port) (0x2758 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_6_ARBITER_CONFIG(port) (0x2768 + (port<<10)) -#define MV64340_ETH_TX_QUEUE_7_ARBITER_CONFIG(port) (0x2778 + (port<<10)) -#define MV64340_ETH_PORT_TX_TOKEN_BUCKET_COUNT(port) (0x2780 + (port<<10)) -#define MV64340_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(port) (0x3400 + (port<<10)) -#define MV64340_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(port) (0x3500 + (port<<10)) -#define MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE(port) (0x3600 + (port<<10)) +#define MV643XX_ETH_SHARED_REGS 0x2000 +#define MV643XX_ETH_SHARED_REGS_SIZE 0x2000 + +#define MV643XX_ETH_PHY_ADDR_REG 0x2000 +#define MV643XX_ETH_SMI_REG 0x2004 +#define MV643XX_ETH_UNIT_DEFAULT_ADDR_REG 0x2008 +#define MV643XX_ETH_UNIT_DEFAULTID_REG 0x200c +#define MV643XX_ETH_UNIT_INTERRUPT_CAUSE_REG 0x2080 +#define MV643XX_ETH_UNIT_INTERRUPT_MASK_REG 0x2084 +#define MV643XX_ETH_UNIT_INTERNAL_USE_REG 0x24fc +#define MV643XX_ETH_UNIT_ERROR_ADDR_REG 0x2094 +#define MV643XX_ETH_BAR_0 0x2200 +#define MV643XX_ETH_BAR_1 0x2208 +#define MV643XX_ETH_BAR_2 0x2210 +#define MV643XX_ETH_BAR_3 0x2218 +#define MV643XX_ETH_BAR_4 0x2220 +#define MV643XX_ETH_BAR_5 0x2228 +#define MV643XX_ETH_SIZE_REG_0 0x2204 +#define MV643XX_ETH_SIZE_REG_1 0x220c +#define MV643XX_ETH_SIZE_REG_2 0x2214 +#define MV643XX_ETH_SIZE_REG_3 0x221c +#define MV643XX_ETH_SIZE_REG_4 0x2224 +#define MV643XX_ETH_SIZE_REG_5 0x222c +#define MV643XX_ETH_HEADERS_RETARGET_BASE_REG 0x2230 +#define MV643XX_ETH_HEADERS_RETARGET_CONTROL_REG 0x2234 +#define MV643XX_ETH_HIGH_ADDR_REMAP_REG_0 0x2280 +#define MV643XX_ETH_HIGH_ADDR_REMAP_REG_1 0x2284 +#define MV643XX_ETH_HIGH_ADDR_REMAP_REG_2 0x2288 +#define MV643XX_ETH_HIGH_ADDR_REMAP_REG_3 0x228c +#define MV643XX_ETH_BASE_ADDR_ENABLE_REG 0x2290 +#define MV643XX_ETH_ACCESS_PROTECTION_REG(port) (0x2294 + (port<<2)) +#define MV643XX_ETH_MIB_COUNTERS_BASE(port) (0x3000 + (port<<7)) +#define MV643XX_ETH_PORT_CONFIG_REG(port) (0x2400 + (port<<10)) +#define MV643XX_ETH_PORT_CONFIG_EXTEND_REG(port) (0x2404 + (port<<10)) +#define MV643XX_ETH_MII_SERIAL_PARAMETRS_REG(port) (0x2408 + (port<<10)) +#define MV643XX_ETH_GMII_SERIAL_PARAMETRS_REG(port) (0x240c + (port<<10)) +#define MV643XX_ETH_VLAN_ETHERTYPE_REG(port) (0x2410 + (port<<10)) +#define MV643XX_ETH_MAC_ADDR_LOW(port) (0x2414 + (port<<10)) +#define MV643XX_ETH_MAC_ADDR_HIGH(port) (0x2418 + (port<<10)) +#define MV643XX_ETH_SDMA_CONFIG_REG(port) (0x241c + (port<<10)) +#define MV643XX_ETH_DSCP_0(port) (0x2420 + (port<<10)) +#define MV643XX_ETH_DSCP_1(port) (0x2424 + (port<<10)) +#define MV643XX_ETH_DSCP_2(port) (0x2428 + (port<<10)) +#define MV643XX_ETH_DSCP_3(port) (0x242c + (port<<10)) +#define MV643XX_ETH_DSCP_4(port) (0x2430 + (port<<10)) +#define MV643XX_ETH_DSCP_5(port) (0x2434 + (port<<10)) +#define MV643XX_ETH_DSCP_6(port) (0x2438 + (port<<10)) +#define MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port) (0x243c + (port<<10)) +#define MV643XX_ETH_VLAN_PRIORITY_TAG_TO_PRIORITY(port) (0x2440 + (port<<10)) +#define MV643XX_ETH_PORT_STATUS_REG(port) (0x2444 + (port<<10)) +#define MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port) (0x2448 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_FIXED_PRIORITY(port) (0x244c + (port<<10)) +#define MV643XX_ETH_PORT_TX_TOKEN_BUCKET_RATE_CONFIG(port) (0x2450 + (port<<10)) +#define MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port) (0x2458 + (port<<10)) +#define MV643XX_ETH_PORT_MAXIMUM_TOKEN_BUCKET_SIZE(port) (0x245c + (port<<10)) +#define MV643XX_ETH_INTERRUPT_CAUSE_REG(port) (0x2460 + (port<<10)) +#define MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port) (0x2464 + (port<<10)) +#define MV643XX_ETH_INTERRUPT_MASK_REG(port) (0x2468 + (port<<10)) +#define MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port) (0x246c + (port<<10)) +#define MV643XX_ETH_RX_FIFO_URGENT_THRESHOLD_REG(port) (0x2470 + (port<<10)) +#define MV643XX_ETH_TX_FIFO_URGENT_THRESHOLD_REG(port) (0x2474 + (port<<10)) +#define MV643XX_ETH_RX_MINIMAL_FRAME_SIZE_REG(port) (0x247c + (port<<10)) +#define MV643XX_ETH_RX_DISCARDED_FRAMES_COUNTER(port) (0x2484 + (port<<10) +#define MV643XX_ETH_PORT_DEBUG_0_REG(port) (0x248c + (port<<10)) +#define MV643XX_ETH_PORT_DEBUG_1_REG(port) (0x2490 + (port<<10)) +#define MV643XX_ETH_PORT_INTERNAL_ADDR_ERROR_REG(port) (0x2494 + (port<<10)) +#define MV643XX_ETH_INTERNAL_USE_REG(port) (0x24fc + (port<<10)) +#define MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port) (0x2680 + (port<<10)) +#define MV643XX_ETH_CURRENT_SERVED_TX_DESC_PTR(port) (0x2684 + (port<<10)) +#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port) (0x260c + (port<<10)) +#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_1(port) (0x261c + (port<<10)) +#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_2(port) (0x262c + (port<<10)) +#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_3(port) (0x263c + (port<<10)) +#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_4(port) (0x264c + (port<<10)) +#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_5(port) (0x265c + (port<<10)) +#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_6(port) (0x266c + (port<<10)) +#define MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_7(port) (0x267c + (port<<10)) +#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(port) (0x26c0 + (port<<10)) +#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_1(port) (0x26c4 + (port<<10)) +#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_2(port) (0x26c8 + (port<<10)) +#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_3(port) (0x26cc + (port<<10)) +#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_4(port) (0x26d0 + (port<<10)) +#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_5(port) (0x26d4 + (port<<10)) +#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_6(port) (0x26d8 + (port<<10)) +#define MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_7(port) (0x26dc + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_0_TOKEN_BUCKET_COUNT(port) (0x2700 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_1_TOKEN_BUCKET_COUNT(port) (0x2710 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_2_TOKEN_BUCKET_COUNT(port) (0x2720 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_3_TOKEN_BUCKET_COUNT(port) (0x2730 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_4_TOKEN_BUCKET_COUNT(port) (0x2740 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_5_TOKEN_BUCKET_COUNT(port) (0x2750 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_6_TOKEN_BUCKET_COUNT(port) (0x2760 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_7_TOKEN_BUCKET_COUNT(port) (0x2770 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_0_TOKEN_BUCKET_CONFIG(port) (0x2704 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_1_TOKEN_BUCKET_CONFIG(port) (0x2714 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_2_TOKEN_BUCKET_CONFIG(port) (0x2724 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_3_TOKEN_BUCKET_CONFIG(port) (0x2734 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_4_TOKEN_BUCKET_CONFIG(port) (0x2744 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_5_TOKEN_BUCKET_CONFIG(port) (0x2754 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_6_TOKEN_BUCKET_CONFIG(port) (0x2764 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_7_TOKEN_BUCKET_CONFIG(port) (0x2774 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_0_ARBITER_CONFIG(port) (0x2708 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_1_ARBITER_CONFIG(port) (0x2718 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_2_ARBITER_CONFIG(port) (0x2728 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_3_ARBITER_CONFIG(port) (0x2738 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_4_ARBITER_CONFIG(port) (0x2748 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_5_ARBITER_CONFIG(port) (0x2758 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_6_ARBITER_CONFIG(port) (0x2768 + (port<<10)) +#define MV643XX_ETH_TX_QUEUE_7_ARBITER_CONFIG(port) (0x2778 + (port<<10)) +#define MV643XX_ETH_PORT_TX_TOKEN_BUCKET_COUNT(port) (0x2780 + (port<<10)) +#define MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(port) (0x3400 + (port<<10)) +#define MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(port) (0x3500 + (port<<10)) +#define MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(port) (0x3600 + (port<<10)) /*******************************************/ /* CUNIT Registers */ @@ -1090,4 +1093,221 @@ u32 retries; }; -#endif /* __ASM_MV64340_H */ +/* These macros describe Ethernet Port configuration reg (Px_cR) bits */ +#define MV643XX_ETH_UNICAST_NORMAL_MODE 0 +#define MV643XX_ETH_UNICAST_PROMISCUOUS_MODE (1<<0) +#define MV643XX_ETH_DEFAULT_RX_QUEUE_0 0 +#define MV643XX_ETH_DEFAULT_RX_QUEUE_1 (1<<1) +#define MV643XX_ETH_DEFAULT_RX_QUEUE_2 (1<<2) +#define MV643XX_ETH_DEFAULT_RX_QUEUE_3 ((1<<2) | (1<<1)) +#define MV643XX_ETH_DEFAULT_RX_QUEUE_4 (1<<3) +#define MV643XX_ETH_DEFAULT_RX_QUEUE_5 ((1<<3) | (1<<1)) +#define MV643XX_ETH_DEFAULT_RX_QUEUE_6 ((1<<3) | (1<<2)) +#define MV643XX_ETH_DEFAULT_RX_QUEUE_7 ((1<<3) | (1<<2) | (1<<1)) +#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_0 0 +#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_1 (1<<4) +#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_2 (1<<5) +#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_3 ((1<<5) | (1<<4)) +#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_4 (1<<6) +#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_5 ((1<<6) | (1<<4)) +#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_6 ((1<<6) | (1<<5)) +#define MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_7 ((1<<6) | (1<<5) | (1<<4)) +#define MV643XX_ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP 0 +#define MV643XX_ETH_REJECT_BC_IF_NOT_IP_OR_ARP (1<<7) +#define MV643XX_ETH_RECEIVE_BC_IF_IP 0 +#define MV643XX_ETH_REJECT_BC_IF_IP (1<<8) +#define MV643XX_ETH_RECEIVE_BC_IF_ARP 0 +#define MV643XX_ETH_REJECT_BC_IF_ARP (1<<9) +#define MV643XX_ETH_TX_AM_NO_UPDATE_ERROR_SUMMARY (1<<12) +#define MV643XX_ETH_CAPTURE_TCP_FRAMES_DIS 0 +#define MV643XX_ETH_CAPTURE_TCP_FRAMES_EN (1<<14) +#define MV643XX_ETH_CAPTURE_UDP_FRAMES_DIS 0 +#define MV643XX_ETH_CAPTURE_UDP_FRAMES_EN (1<<15) +#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_0 0 +#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_1 (1<<16) +#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_2 (1<<17) +#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_3 ((1<<17) | (1<<16)) +#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_4 (1<<18) +#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_5 ((1<<18) | (1<<16)) +#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_6 ((1<<18) | (1<<17)) +#define MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_7 ((1<<18) | (1<<17) | (1<<16)) +#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_0 0 +#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_1 (1<<19) +#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_2 (1<<20) +#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_3 ((1<<20) | (1<<19)) +#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_4 ((1<<21) +#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_5 ((1<<21) | (1<<19)) +#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_6 ((1<<21) | (1<<20)) +#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_7 ((1<<21) | (1<<20) | (1<<19)) +#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_0 0 +#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_1 (1<<22) +#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_2 (1<<23) +#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_3 ((1<<23) | (1<<22)) +#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_4 (1<<24) +#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_5 ((1<<24) | (1<<22)) +#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_6 ((1<<24) | (1<<23)) +#define MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_7 ((1<<24) | (1<<23) | (1<<22)) + +#define MV643XX_ETH_PORT_CONFIG_DEFAULT_VALUE \ + MV643XX_ETH_UNICAST_NORMAL_MODE | \ + MV643XX_ETH_DEFAULT_RX_QUEUE_0 | \ + MV643XX_ETH_DEFAULT_RX_ARP_QUEUE_0 | \ + MV643XX_ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP | \ + MV643XX_ETH_RECEIVE_BC_IF_IP | \ + MV643XX_ETH_RECEIVE_BC_IF_ARP | \ + MV643XX_ETH_CAPTURE_TCP_FRAMES_DIS | \ + MV643XX_ETH_CAPTURE_UDP_FRAMES_DIS | \ + MV643XX_ETH_DEFAULT_RX_TCP_QUEUE_0 | \ + MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_0 | \ + MV643XX_ETH_DEFAULT_RX_BPDU_QUEUE_0 + +/* These macros describe Ethernet Port configuration extend reg (Px_cXR) bits*/ +#define MV643XX_ETH_CLASSIFY_EN (1<<0) +#define MV643XX_ETH_SPAN_BPDU_PACKETS_AS_NORMAL 0 +#define MV643XX_ETH_SPAN_BPDU_PACKETS_TO_RX_QUEUE_7 (1<<1) +#define MV643XX_ETH_PARTITION_DISABLE 0 +#define MV643XX_ETH_PARTITION_ENABLE (1<<2) + +#define MV643XX_ETH_PORT_CONFIG_EXTEND_DEFAULT_VALUE \ + MV643XX_ETH_SPAN_BPDU_PACKETS_AS_NORMAL | \ + MV643XX_ETH_PARTITION_DISABLE + +/* These macros describe Ethernet Port Sdma configuration reg (SDCR) bits */ +#define MV643XX_ETH_RIFB (1<<0) +#define MV643XX_ETH_RX_BURST_SIZE_1_64BIT 0 +#define MV643XX_ETH_RX_BURST_SIZE_2_64BIT (1<<1) +#define MV643XX_ETH_RX_BURST_SIZE_4_64BIT (1<<2) +#define MV643XX_ETH_RX_BURST_SIZE_8_64BIT ((1<<2) | (1<<1)) +#define MV643XX_ETH_RX_BURST_SIZE_16_64BIT (1<<3) +#define MV643XX_ETH_BLM_RX_NO_SWAP (1<<4) +#define MV643XX_ETH_BLM_RX_BYTE_SWAP 0 +#define MV643XX_ETH_BLM_TX_NO_SWAP (1<<5) +#define MV643XX_ETH_BLM_TX_BYTE_SWAP 0 +#define MV643XX_ETH_DESCRIPTORS_BYTE_SWAP (1<<6) +#define MV643XX_ETH_DESCRIPTORS_NO_SWAP 0 +#define MV643XX_ETH_TX_BURST_SIZE_1_64BIT 0 +#define MV643XX_ETH_TX_BURST_SIZE_2_64BIT (1<<22) +#define MV643XX_ETH_TX_BURST_SIZE_4_64BIT (1<<23) +#define MV643XX_ETH_TX_BURST_SIZE_8_64BIT ((1<<23) | (1<<22)) +#define MV643XX_ETH_TX_BURST_SIZE_16_64BIT (1<<24) + +#define MV643XX_ETH_IPG_INT_RX(value) ((value & 0x3fff) << 8) + +#define MV643XX_ETH_PORT_SDMA_CONFIG_DEFAULT_VALUE \ + MV643XX_ETH_RX_BURST_SIZE_4_64BIT | \ + MV643XX_ETH_IPG_INT_RX(0) | \ + MV643XX_ETH_TX_BURST_SIZE_4_64BIT + +/* These macros describe Ethernet Port serial control reg (PSCR) bits */ +#define MV643XX_ETH_SERIAL_PORT_DISABLE 0 +#define MV643XX_ETH_SERIAL_PORT_ENABLE (1<<0) +#define MV643XX_ETH_FORCE_LINK_PASS (1<<1) +#define MV643XX_ETH_DO_NOT_FORCE_LINK_PASS 0 +#define MV643XX_ETH_ENABLE_AUTO_NEG_FOR_DUPLX 0 +#define MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX (1<<2) +#define MV643XX_ETH_ENABLE_AUTO_NEG_FOR_FLOW_CTRL 0 +#define MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL (1<<3) +#define MV643XX_ETH_ADV_NO_FLOW_CTRL 0 +#define MV643XX_ETH_ADV_SYMMETRIC_FLOW_CTRL (1<<4) +#define MV643XX_ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX 0 +#define MV643XX_ETH_FORCE_FC_MODE_TX_PAUSE_DIS (1<<5) +#define MV643XX_ETH_FORCE_BP_MODE_NO_JAM 0 +#define MV643XX_ETH_FORCE_BP_MODE_JAM_TX (1<<7) +#define MV643XX_ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR (1<<8) +#define MV643XX_ETH_FORCE_LINK_FAIL 0 +#define MV643XX_ETH_DO_NOT_FORCE_LINK_FAIL (1<<10) +#define MV643XX_ETH_RETRANSMIT_16_ATTEMPTS 0 +#define MV643XX_ETH_RETRANSMIT_FOREVER (1<<11) +#define MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII (1<<13) +#define MV643XX_ETH_ENABLE_AUTO_NEG_SPEED_GMII 0 +#define MV643XX_ETH_DTE_ADV_0 0 +#define MV643XX_ETH_DTE_ADV_1 (1<<14) +#define MV643XX_ETH_DISABLE_AUTO_NEG_BYPASS 0 +#define MV643XX_ETH_ENABLE_AUTO_NEG_BYPASS (1<<15) +#define MV643XX_ETH_AUTO_NEG_NO_CHANGE 0 +#define MV643XX_ETH_RESTART_AUTO_NEG (1<<16) +#define MV643XX_ETH_MAX_RX_PACKET_1518BYTE 0 +#define MV643XX_ETH_MAX_RX_PACKET_1522BYTE (1<<17) +#define MV643XX_ETH_MAX_RX_PACKET_1552BYTE (1<<18) +#define MV643XX_ETH_MAX_RX_PACKET_9022BYTE ((1<<18) | (1<<17)) +#define MV643XX_ETH_MAX_RX_PACKET_9192BYTE (1<<19) +#define MV643XX_ETH_MAX_RX_PACKET_9700BYTE ((1<<19) | (1<<17)) +#define MV643XX_ETH_SET_EXT_LOOPBACK (1<<20) +#define MV643XX_ETH_CLR_EXT_LOOPBACK 0 +#define MV643XX_ETH_SET_FULL_DUPLEX_MODE (1<<21) +#define MV643XX_ETH_SET_HALF_DUPLEX_MODE 0 +#define MV643XX_ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX (1<<22) +#define MV643XX_ETH_DISABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX 0 +#define MV643XX_ETH_SET_GMII_SPEED_TO_10_100 0 +#define MV643XX_ETH_SET_GMII_SPEED_TO_1000 (1<<23) +#define MV643XX_ETH_SET_MII_SPEED_TO_10 0 +#define MV643XX_ETH_SET_MII_SPEED_TO_100 (1<<24) + +#define MV643XX_ETH_PORT_SERIAL_CONTROL_DEFAULT_VALUE \ + MV643XX_ETH_DO_NOT_FORCE_LINK_PASS | \ + MV643XX_ETH_ENABLE_AUTO_NEG_FOR_DUPLX | \ + MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL | \ + MV643XX_ETH_ADV_SYMMETRIC_FLOW_CTRL | \ + MV643XX_ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX | \ + MV643XX_ETH_FORCE_BP_MODE_NO_JAM | \ + (1<<9) /* reserved */ | \ + MV643XX_ETH_DO_NOT_FORCE_LINK_FAIL | \ + MV643XX_ETH_RETRANSMIT_16_ATTEMPTS | \ + MV643XX_ETH_ENABLE_AUTO_NEG_SPEED_GMII | \ + MV643XX_ETH_DTE_ADV_0 | \ + MV643XX_ETH_DISABLE_AUTO_NEG_BYPASS | \ + MV643XX_ETH_AUTO_NEG_NO_CHANGE | \ + MV643XX_ETH_MAX_RX_PACKET_9700BYTE | \ + MV643XX_ETH_CLR_EXT_LOOPBACK | \ + MV643XX_ETH_SET_FULL_DUPLEX_MODE | \ + MV643XX_ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX + +/* These macros describe Ethernet Serial Status reg (PSR) bits */ +#define MV643XX_ETH_PORT_STATUS_MODE_10_BIT (1<<0) +#define MV643XX_ETH_PORT_STATUS_LINK_UP (1<<1) +#define MV643XX_ETH_PORT_STATUS_FULL_DUPLEX (1<<2) +#define MV643XX_ETH_PORT_STATUS_FLOW_CONTROL (1<<3) +#define MV643XX_ETH_PORT_STATUS_GMII_1000 (1<<4) +#define MV643XX_ETH_PORT_STATUS_MII_100 (1<<5) +/* PSR bit 6 is undocumented */ +#define MV643XX_ETH_PORT_STATUS_TX_IN_PROGRESS (1<<7) +#define MV643XX_ETH_PORT_STATUS_AUTONEG_BYPASSED (1<<8) +#define MV643XX_ETH_PORT_STATUS_PARTITION (1<<9) +#define MV643XX_ETH_PORT_STATUS_TX_FIFO_EMPTY (1<<10) +/* PSR bits 11-31 are reserved */ + +#define MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE 800 +#define MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE 400 + +#define MV643XX_ETH_DESC_SIZE 64 + +#define MV643XX_ETH_SHARED_NAME "mv643xx_eth_shared" +#define MV643XX_ETH_NAME "mv643xx_eth" + +struct mv643xx_eth_platform_data { + /* + * Non-values for mac_addr, phy_addr, port_config, etc. + * override the default value. Setting the corresponding + * force_* field, causes the default value to be overridden + * even when zero. + */ + unsigned int force_phy_addr:1; + unsigned int force_port_config:1; + unsigned int force_port_config_extend:1; + unsigned int force_port_sdma_config:1; + unsigned int force_port_serial_control:1; + int phy_addr; + char *mac_addr; /* pointer to mac address */ + u32 port_config; + u32 port_config_extend; + u32 port_sdma_config; + u32 port_serial_control; + u32 tx_queue_size; + u32 rx_queue_size; + u32 tx_sram_addr; + u32 tx_sram_size; + u32 rx_sram_addr; + u32 rx_sram_size; +}; + +#endif /* __ASM_MV643XX_H */