| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1 | /* | 
|  | 2 | * Atmel MACB Ethernet Controller driver | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 2004-2006 Atmel Corporation | 
|  | 5 | * | 
|  | 6 | * This program is free software; you can redistribute it and/or modify | 
|  | 7 | * it under the terms of the GNU General Public License version 2 as | 
|  | 8 | * published by the Free Software Foundation. | 
|  | 9 | */ | 
|  | 10 |  | 
|  | 11 | #include <linux/clk.h> | 
|  | 12 | #include <linux/module.h> | 
|  | 13 | #include <linux/moduleparam.h> | 
|  | 14 | #include <linux/kernel.h> | 
|  | 15 | #include <linux/types.h> | 
|  | 16 | #include <linux/slab.h> | 
|  | 17 | #include <linux/init.h> | 
|  | 18 | #include <linux/netdevice.h> | 
|  | 19 | #include <linux/etherdevice.h> | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 20 | #include <linux/dma-mapping.h> | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 21 | #include <linux/platform_device.h> | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 22 | #include <linux/phy.h> | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 23 |  | 
| Russell King | a09e64f | 2008-08-05 16:14:15 +0100 | [diff] [blame] | 24 | #include <mach/board.h> | 
|  | 25 | #include <mach/cpu.h> | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 26 |  | 
|  | 27 | #include "macb.h" | 
|  | 28 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 29 | #define RX_BUFFER_SIZE		128 | 
|  | 30 | #define RX_RING_SIZE		512 | 
|  | 31 | #define RX_RING_BYTES		(sizeof(struct dma_desc) * RX_RING_SIZE) | 
|  | 32 |  | 
|  | 33 | /* Make the IP header word-aligned (the ethernet header is 14 bytes) */ | 
|  | 34 | #define RX_OFFSET		2 | 
|  | 35 |  | 
|  | 36 | #define TX_RING_SIZE		128 | 
|  | 37 | #define DEF_TX_RING_PENDING	(TX_RING_SIZE - 1) | 
|  | 38 | #define TX_RING_BYTES		(sizeof(struct dma_desc) * TX_RING_SIZE) | 
|  | 39 |  | 
|  | 40 | #define TX_RING_GAP(bp)						\ | 
|  | 41 | (TX_RING_SIZE - (bp)->tx_pending) | 
|  | 42 | #define TX_BUFFS_AVAIL(bp)					\ | 
|  | 43 | (((bp)->tx_tail <= (bp)->tx_head) ?			\ | 
|  | 44 | (bp)->tx_tail + (bp)->tx_pending - (bp)->tx_head :	\ | 
|  | 45 | (bp)->tx_tail - (bp)->tx_head - TX_RING_GAP(bp)) | 
|  | 46 | #define NEXT_TX(n)		(((n) + 1) & (TX_RING_SIZE - 1)) | 
|  | 47 |  | 
|  | 48 | #define NEXT_RX(n)		(((n) + 1) & (RX_RING_SIZE - 1)) | 
|  | 49 |  | 
|  | 50 | /* minimum number of free TX descriptors before waking up TX process */ | 
|  | 51 | #define MACB_TX_WAKEUP_THRESH	(TX_RING_SIZE / 4) | 
|  | 52 |  | 
|  | 53 | #define MACB_RX_INT_FLAGS	(MACB_BIT(RCOMP) | MACB_BIT(RXUBR)	\ | 
|  | 54 | | MACB_BIT(ISR_ROVR)) | 
|  | 55 |  | 
|  | 56 | static void __macb_set_hwaddr(struct macb *bp) | 
|  | 57 | { | 
|  | 58 | u32 bottom; | 
|  | 59 | u16 top; | 
|  | 60 |  | 
|  | 61 | bottom = cpu_to_le32(*((u32 *)bp->dev->dev_addr)); | 
|  | 62 | macb_writel(bp, SA1B, bottom); | 
|  | 63 | top = cpu_to_le16(*((u16 *)(bp->dev->dev_addr + 4))); | 
|  | 64 | macb_writel(bp, SA1T, top); | 
|  | 65 | } | 
|  | 66 |  | 
|  | 67 | static void __init macb_get_hwaddr(struct macb *bp) | 
|  | 68 | { | 
|  | 69 | u32 bottom; | 
|  | 70 | u16 top; | 
|  | 71 | u8 addr[6]; | 
|  | 72 |  | 
|  | 73 | bottom = macb_readl(bp, SA1B); | 
|  | 74 | top = macb_readl(bp, SA1T); | 
|  | 75 |  | 
|  | 76 | addr[0] = bottom & 0xff; | 
|  | 77 | addr[1] = (bottom >> 8) & 0xff; | 
|  | 78 | addr[2] = (bottom >> 16) & 0xff; | 
|  | 79 | addr[3] = (bottom >> 24) & 0xff; | 
|  | 80 | addr[4] = top & 0xff; | 
|  | 81 | addr[5] = (top >> 8) & 0xff; | 
|  | 82 |  | 
| Sven Schnelle | d1d5741 | 2008-06-09 16:33:57 -0700 | [diff] [blame] | 83 | if (is_valid_ether_addr(addr)) { | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 84 | memcpy(bp->dev->dev_addr, addr, sizeof(addr)); | 
| Sven Schnelle | d1d5741 | 2008-06-09 16:33:57 -0700 | [diff] [blame] | 85 | } else { | 
|  | 86 | dev_info(&bp->pdev->dev, "invalid hw address, using random\n"); | 
|  | 87 | random_ether_addr(bp->dev->dev_addr); | 
|  | 88 | } | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 89 | } | 
|  | 90 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 91 | static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum) | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 92 | { | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 93 | struct macb *bp = bus->priv; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 94 | int value; | 
|  | 95 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 96 | macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) | 
|  | 97 | | MACB_BF(RW, MACB_MAN_READ) | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 98 | | MACB_BF(PHYA, mii_id) | 
|  | 99 | | MACB_BF(REGA, regnum) | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 100 | | MACB_BF(CODE, MACB_MAN_CODE))); | 
|  | 101 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 102 | /* wait for end of transfer */ | 
|  | 103 | while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR))) | 
|  | 104 | cpu_relax(); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 105 |  | 
|  | 106 | value = MACB_BFEXT(DATA, macb_readl(bp, MAN)); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 107 |  | 
|  | 108 | return value; | 
|  | 109 | } | 
|  | 110 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 111 | static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum, | 
|  | 112 | u16 value) | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 113 | { | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 114 | struct macb *bp = bus->priv; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 115 |  | 
|  | 116 | macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) | 
|  | 117 | | MACB_BF(RW, MACB_MAN_WRITE) | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 118 | | MACB_BF(PHYA, mii_id) | 
|  | 119 | | MACB_BF(REGA, regnum) | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 120 | | MACB_BF(CODE, MACB_MAN_CODE) | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 121 | | MACB_BF(DATA, value))); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 122 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 123 | /* wait for end of transfer */ | 
|  | 124 | while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR))) | 
|  | 125 | cpu_relax(); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 126 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 127 | return 0; | 
|  | 128 | } | 
|  | 129 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 130 | static int macb_mdio_reset(struct mii_bus *bus) | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 131 | { | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 132 | return 0; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 133 | } | 
|  | 134 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 135 | static void macb_handle_link_change(struct net_device *dev) | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 136 | { | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 137 | struct macb *bp = netdev_priv(dev); | 
|  | 138 | struct phy_device *phydev = bp->phy_dev; | 
|  | 139 | unsigned long flags; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 140 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 141 | int status_change = 0; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 142 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 143 | spin_lock_irqsave(&bp->lock, flags); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 144 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 145 | if (phydev->link) { | 
|  | 146 | if ((bp->speed != phydev->speed) || | 
|  | 147 | (bp->duplex != phydev->duplex)) { | 
|  | 148 | u32 reg; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 149 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 150 | reg = macb_readl(bp, NCFGR); | 
|  | 151 | reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); | 
|  | 152 |  | 
|  | 153 | if (phydev->duplex) | 
|  | 154 | reg |= MACB_BIT(FD); | 
| Atsushi Nemoto | 179956f | 2008-02-21 22:50:54 +0900 | [diff] [blame] | 155 | if (phydev->speed == SPEED_100) | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 156 | reg |= MACB_BIT(SPD); | 
|  | 157 |  | 
|  | 158 | macb_writel(bp, NCFGR, reg); | 
|  | 159 |  | 
|  | 160 | bp->speed = phydev->speed; | 
|  | 161 | bp->duplex = phydev->duplex; | 
|  | 162 | status_change = 1; | 
|  | 163 | } | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 164 | } | 
|  | 165 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 166 | if (phydev->link != bp->link) { | 
| Anton Vorontsov | c8f1568 | 2008-07-22 15:41:24 -0700 | [diff] [blame] | 167 | if (!phydev->link) { | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 168 | bp->speed = 0; | 
|  | 169 | bp->duplex = -1; | 
|  | 170 | } | 
|  | 171 | bp->link = phydev->link; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 172 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 173 | status_change = 1; | 
|  | 174 | } | 
|  | 175 |  | 
|  | 176 | spin_unlock_irqrestore(&bp->lock, flags); | 
|  | 177 |  | 
|  | 178 | if (status_change) { | 
|  | 179 | if (phydev->link) | 
|  | 180 | printk(KERN_INFO "%s: link up (%d/%s)\n", | 
|  | 181 | dev->name, phydev->speed, | 
|  | 182 | DUPLEX_FULL == phydev->duplex ? "Full":"Half"); | 
|  | 183 | else | 
|  | 184 | printk(KERN_INFO "%s: link down\n", dev->name); | 
|  | 185 | } | 
|  | 186 | } | 
|  | 187 |  | 
|  | 188 | /* based on au1000_eth. c*/ | 
|  | 189 | static int macb_mii_probe(struct net_device *dev) | 
|  | 190 | { | 
|  | 191 | struct macb *bp = netdev_priv(dev); | 
|  | 192 | struct phy_device *phydev = NULL; | 
|  | 193 | struct eth_platform_data *pdata; | 
|  | 194 | int phy_addr; | 
|  | 195 |  | 
|  | 196 | /* find the first phy */ | 
|  | 197 | for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { | 
| Lennert Buytenhek | 298cf9b | 2008-10-08 16:29:57 -0700 | [diff] [blame] | 198 | if (bp->mii_bus->phy_map[phy_addr]) { | 
|  | 199 | phydev = bp->mii_bus->phy_map[phy_addr]; | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 200 | break; | 
|  | 201 | } | 
|  | 202 | } | 
|  | 203 |  | 
|  | 204 | if (!phydev) { | 
|  | 205 | printk (KERN_ERR "%s: no PHY found\n", dev->name); | 
|  | 206 | return -1; | 
|  | 207 | } | 
|  | 208 |  | 
|  | 209 | pdata = bp->pdev->dev.platform_data; | 
|  | 210 | /* TODO : add pin_irq */ | 
|  | 211 |  | 
|  | 212 | /* attach the mac to the phy */ | 
|  | 213 | if (pdata && pdata->is_rmii) { | 
| Kay Sievers | db1d7bf | 2009-01-26 21:12:58 -0800 | [diff] [blame] | 214 | phydev = phy_connect(dev, dev_name(&phydev->dev), | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 215 | &macb_handle_link_change, 0, PHY_INTERFACE_MODE_RMII); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 216 | } else { | 
| Kay Sievers | db1d7bf | 2009-01-26 21:12:58 -0800 | [diff] [blame] | 217 | phydev = phy_connect(dev, dev_name(&phydev->dev), | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 218 | &macb_handle_link_change, 0, PHY_INTERFACE_MODE_MII); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 219 | } | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 220 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 221 | if (IS_ERR(phydev)) { | 
|  | 222 | printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); | 
|  | 223 | return PTR_ERR(phydev); | 
|  | 224 | } | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 225 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 226 | /* mask with MAC supported features */ | 
|  | 227 | phydev->supported &= PHY_BASIC_FEATURES; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 228 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 229 | phydev->advertising = phydev->supported; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 230 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 231 | bp->link = 0; | 
|  | 232 | bp->speed = 0; | 
|  | 233 | bp->duplex = -1; | 
|  | 234 | bp->phy_dev = phydev; | 
|  | 235 |  | 
|  | 236 | return 0; | 
|  | 237 | } | 
|  | 238 |  | 
|  | 239 | static int macb_mii_init(struct macb *bp) | 
|  | 240 | { | 
|  | 241 | struct eth_platform_data *pdata; | 
|  | 242 | int err = -ENXIO, i; | 
|  | 243 |  | 
|  | 244 | /* Enable managment port */ | 
|  | 245 | macb_writel(bp, NCR, MACB_BIT(MPE)); | 
|  | 246 |  | 
| Lennert Buytenhek | 298cf9b | 2008-10-08 16:29:57 -0700 | [diff] [blame] | 247 | bp->mii_bus = mdiobus_alloc(); | 
|  | 248 | if (bp->mii_bus == NULL) { | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 249 | err = -ENOMEM; | 
|  | 250 | goto err_out; | 
|  | 251 | } | 
|  | 252 |  | 
| Lennert Buytenhek | 298cf9b | 2008-10-08 16:29:57 -0700 | [diff] [blame] | 253 | bp->mii_bus->name = "MACB_mii_bus"; | 
|  | 254 | bp->mii_bus->read = &macb_mdio_read; | 
|  | 255 | bp->mii_bus->write = &macb_mdio_write; | 
|  | 256 | bp->mii_bus->reset = &macb_mdio_reset; | 
|  | 257 | snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", bp->pdev->id); | 
|  | 258 | bp->mii_bus->priv = bp; | 
|  | 259 | bp->mii_bus->parent = &bp->dev->dev; | 
|  | 260 | pdata = bp->pdev->dev.platform_data; | 
|  | 261 |  | 
|  | 262 | if (pdata) | 
|  | 263 | bp->mii_bus->phy_mask = pdata->phy_mask; | 
|  | 264 |  | 
|  | 265 | bp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); | 
|  | 266 | if (!bp->mii_bus->irq) { | 
|  | 267 | err = -ENOMEM; | 
|  | 268 | goto err_out_free_mdiobus; | 
|  | 269 | } | 
|  | 270 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 271 | for (i = 0; i < PHY_MAX_ADDR; i++) | 
| Lennert Buytenhek | 298cf9b | 2008-10-08 16:29:57 -0700 | [diff] [blame] | 272 | bp->mii_bus->irq[i] = PHY_POLL; | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 273 |  | 
| Lennert Buytenhek | 298cf9b | 2008-10-08 16:29:57 -0700 | [diff] [blame] | 274 | platform_set_drvdata(bp->dev, bp->mii_bus); | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 275 |  | 
| Lennert Buytenhek | 298cf9b | 2008-10-08 16:29:57 -0700 | [diff] [blame] | 276 | if (mdiobus_register(bp->mii_bus)) | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 277 | goto err_out_free_mdio_irq; | 
|  | 278 |  | 
|  | 279 | if (macb_mii_probe(bp->dev) != 0) { | 
|  | 280 | goto err_out_unregister_bus; | 
|  | 281 | } | 
|  | 282 |  | 
|  | 283 | return 0; | 
|  | 284 |  | 
|  | 285 | err_out_unregister_bus: | 
| Lennert Buytenhek | 298cf9b | 2008-10-08 16:29:57 -0700 | [diff] [blame] | 286 | mdiobus_unregister(bp->mii_bus); | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 287 | err_out_free_mdio_irq: | 
| Lennert Buytenhek | 298cf9b | 2008-10-08 16:29:57 -0700 | [diff] [blame] | 288 | kfree(bp->mii_bus->irq); | 
|  | 289 | err_out_free_mdiobus: | 
|  | 290 | mdiobus_free(bp->mii_bus); | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 291 | err_out: | 
|  | 292 | return err; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 293 | } | 
|  | 294 |  | 
|  | 295 | static void macb_update_stats(struct macb *bp) | 
|  | 296 | { | 
|  | 297 | u32 __iomem *reg = bp->regs + MACB_PFR; | 
|  | 298 | u32 *p = &bp->hw_stats.rx_pause_frames; | 
|  | 299 | u32 *end = &bp->hw_stats.tx_pause_frames + 1; | 
|  | 300 |  | 
|  | 301 | WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4); | 
|  | 302 |  | 
|  | 303 | for(; p < end; p++, reg++) | 
| Haavard Skinnemoen | 0f0d84e | 2006-12-08 14:38:30 +0100 | [diff] [blame] | 304 | *p += __raw_readl(reg); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 305 | } | 
|  | 306 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 307 | static void macb_tx(struct macb *bp) | 
|  | 308 | { | 
|  | 309 | unsigned int tail; | 
|  | 310 | unsigned int head; | 
|  | 311 | u32 status; | 
|  | 312 |  | 
|  | 313 | status = macb_readl(bp, TSR); | 
|  | 314 | macb_writel(bp, TSR, status); | 
|  | 315 |  | 
|  | 316 | dev_dbg(&bp->pdev->dev, "macb_tx status = %02lx\n", | 
|  | 317 | (unsigned long)status); | 
|  | 318 |  | 
|  | 319 | if (status & MACB_BIT(UND)) { | 
| Gregory CLEMENT | bdcba151 | 2007-12-19 18:23:44 +0100 | [diff] [blame] | 320 | int i; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 321 | printk(KERN_ERR "%s: TX underrun, resetting buffers\n", | 
| Gregory CLEMENT | bdcba151 | 2007-12-19 18:23:44 +0100 | [diff] [blame] | 322 | bp->dev->name); | 
|  | 323 |  | 
| Richard Röjfors | 39eddb4 | 2009-01-18 21:57:35 -0800 | [diff] [blame] | 324 | /* Transfer ongoing, disable transmitter, to avoid confusion */ | 
|  | 325 | if (status & MACB_BIT(TGO)) | 
|  | 326 | macb_writel(bp, NCR, macb_readl(bp, NCR) & ~MACB_BIT(TE)); | 
|  | 327 |  | 
| Gregory CLEMENT | bdcba151 | 2007-12-19 18:23:44 +0100 | [diff] [blame] | 328 | head = bp->tx_head; | 
|  | 329 |  | 
|  | 330 | /*Mark all the buffer as used to avoid sending a lost buffer*/ | 
|  | 331 | for (i = 0; i < TX_RING_SIZE; i++) | 
|  | 332 | bp->tx_ring[i].ctrl = MACB_BIT(TX_USED); | 
|  | 333 |  | 
|  | 334 | /* free transmit buffer in upper layer*/ | 
|  | 335 | for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) { | 
|  | 336 | struct ring_info *rp = &bp->tx_skb[tail]; | 
|  | 337 | struct sk_buff *skb = rp->skb; | 
|  | 338 |  | 
|  | 339 | BUG_ON(skb == NULL); | 
|  | 340 |  | 
|  | 341 | rmb(); | 
|  | 342 |  | 
|  | 343 | dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len, | 
|  | 344 | DMA_TO_DEVICE); | 
|  | 345 | rp->skb = NULL; | 
|  | 346 | dev_kfree_skb_irq(skb); | 
|  | 347 | } | 
|  | 348 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 349 | bp->tx_head = bp->tx_tail = 0; | 
| Richard Röjfors | 39eddb4 | 2009-01-18 21:57:35 -0800 | [diff] [blame] | 350 |  | 
|  | 351 | /* Enable the transmitter again */ | 
|  | 352 | if (status & MACB_BIT(TGO)) | 
|  | 353 | macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TE)); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 354 | } | 
|  | 355 |  | 
|  | 356 | if (!(status & MACB_BIT(COMP))) | 
|  | 357 | /* | 
|  | 358 | * This may happen when a buffer becomes complete | 
|  | 359 | * between reading the ISR and scanning the | 
|  | 360 | * descriptors.  Nothing to worry about. | 
|  | 361 | */ | 
|  | 362 | return; | 
|  | 363 |  | 
|  | 364 | head = bp->tx_head; | 
|  | 365 | for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) { | 
|  | 366 | struct ring_info *rp = &bp->tx_skb[tail]; | 
|  | 367 | struct sk_buff *skb = rp->skb; | 
|  | 368 | u32 bufstat; | 
|  | 369 |  | 
|  | 370 | BUG_ON(skb == NULL); | 
|  | 371 |  | 
|  | 372 | rmb(); | 
|  | 373 | bufstat = bp->tx_ring[tail].ctrl; | 
|  | 374 |  | 
|  | 375 | if (!(bufstat & MACB_BIT(TX_USED))) | 
|  | 376 | break; | 
|  | 377 |  | 
|  | 378 | dev_dbg(&bp->pdev->dev, "skb %u (data %p) TX complete\n", | 
|  | 379 | tail, skb->data); | 
|  | 380 | dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len, | 
|  | 381 | DMA_TO_DEVICE); | 
|  | 382 | bp->stats.tx_packets++; | 
|  | 383 | bp->stats.tx_bytes += skb->len; | 
|  | 384 | rp->skb = NULL; | 
|  | 385 | dev_kfree_skb_irq(skb); | 
|  | 386 | } | 
|  | 387 |  | 
|  | 388 | bp->tx_tail = tail; | 
|  | 389 | if (netif_queue_stopped(bp->dev) && | 
|  | 390 | TX_BUFFS_AVAIL(bp) > MACB_TX_WAKEUP_THRESH) | 
|  | 391 | netif_wake_queue(bp->dev); | 
|  | 392 | } | 
|  | 393 |  | 
|  | 394 | static int macb_rx_frame(struct macb *bp, unsigned int first_frag, | 
|  | 395 | unsigned int last_frag) | 
|  | 396 | { | 
|  | 397 | unsigned int len; | 
|  | 398 | unsigned int frag; | 
|  | 399 | unsigned int offset = 0; | 
|  | 400 | struct sk_buff *skb; | 
|  | 401 |  | 
|  | 402 | len = MACB_BFEXT(RX_FRMLEN, bp->rx_ring[last_frag].ctrl); | 
|  | 403 |  | 
|  | 404 | dev_dbg(&bp->pdev->dev, "macb_rx_frame frags %u - %u (len %u)\n", | 
|  | 405 | first_frag, last_frag, len); | 
|  | 406 |  | 
|  | 407 | skb = dev_alloc_skb(len + RX_OFFSET); | 
|  | 408 | if (!skb) { | 
|  | 409 | bp->stats.rx_dropped++; | 
|  | 410 | for (frag = first_frag; ; frag = NEXT_RX(frag)) { | 
|  | 411 | bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); | 
|  | 412 | if (frag == last_frag) | 
|  | 413 | break; | 
|  | 414 | } | 
|  | 415 | wmb(); | 
|  | 416 | return 1; | 
|  | 417 | } | 
|  | 418 |  | 
|  | 419 | skb_reserve(skb, RX_OFFSET); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 420 | skb->ip_summed = CHECKSUM_NONE; | 
|  | 421 | skb_put(skb, len); | 
|  | 422 |  | 
|  | 423 | for (frag = first_frag; ; frag = NEXT_RX(frag)) { | 
|  | 424 | unsigned int frag_len = RX_BUFFER_SIZE; | 
|  | 425 |  | 
|  | 426 | if (offset + frag_len > len) { | 
|  | 427 | BUG_ON(frag != last_frag); | 
|  | 428 | frag_len = len - offset; | 
|  | 429 | } | 
| Arnaldo Carvalho de Melo | 27d7ff4 | 2007-03-31 11:55:19 -0300 | [diff] [blame] | 430 | skb_copy_to_linear_data_offset(skb, offset, | 
|  | 431 | (bp->rx_buffers + | 
|  | 432 | (RX_BUFFER_SIZE * frag)), | 
|  | 433 | frag_len); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 434 | offset += RX_BUFFER_SIZE; | 
|  | 435 | bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); | 
|  | 436 | wmb(); | 
|  | 437 |  | 
|  | 438 | if (frag == last_frag) | 
|  | 439 | break; | 
|  | 440 | } | 
|  | 441 |  | 
|  | 442 | skb->protocol = eth_type_trans(skb, bp->dev); | 
|  | 443 |  | 
|  | 444 | bp->stats.rx_packets++; | 
|  | 445 | bp->stats.rx_bytes += len; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 446 | dev_dbg(&bp->pdev->dev, "received skb of length %u, csum: %08x\n", | 
|  | 447 | skb->len, skb->csum); | 
|  | 448 | netif_receive_skb(skb); | 
|  | 449 |  | 
|  | 450 | return 0; | 
|  | 451 | } | 
|  | 452 |  | 
|  | 453 | /* Mark DMA descriptors from begin up to and not including end as unused */ | 
|  | 454 | static void discard_partial_frame(struct macb *bp, unsigned int begin, | 
|  | 455 | unsigned int end) | 
|  | 456 | { | 
|  | 457 | unsigned int frag; | 
|  | 458 |  | 
|  | 459 | for (frag = begin; frag != end; frag = NEXT_RX(frag)) | 
|  | 460 | bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); | 
|  | 461 | wmb(); | 
|  | 462 |  | 
|  | 463 | /* | 
|  | 464 | * When this happens, the hardware stats registers for | 
|  | 465 | * whatever caused this is updated, so we don't have to record | 
|  | 466 | * anything. | 
|  | 467 | */ | 
|  | 468 | } | 
|  | 469 |  | 
|  | 470 | static int macb_rx(struct macb *bp, int budget) | 
|  | 471 | { | 
|  | 472 | int received = 0; | 
|  | 473 | unsigned int tail = bp->rx_tail; | 
|  | 474 | int first_frag = -1; | 
|  | 475 |  | 
|  | 476 | for (; budget > 0; tail = NEXT_RX(tail)) { | 
|  | 477 | u32 addr, ctrl; | 
|  | 478 |  | 
|  | 479 | rmb(); | 
|  | 480 | addr = bp->rx_ring[tail].addr; | 
|  | 481 | ctrl = bp->rx_ring[tail].ctrl; | 
|  | 482 |  | 
|  | 483 | if (!(addr & MACB_BIT(RX_USED))) | 
|  | 484 | break; | 
|  | 485 |  | 
|  | 486 | if (ctrl & MACB_BIT(RX_SOF)) { | 
|  | 487 | if (first_frag != -1) | 
|  | 488 | discard_partial_frame(bp, first_frag, tail); | 
|  | 489 | first_frag = tail; | 
|  | 490 | } | 
|  | 491 |  | 
|  | 492 | if (ctrl & MACB_BIT(RX_EOF)) { | 
|  | 493 | int dropped; | 
|  | 494 | BUG_ON(first_frag == -1); | 
|  | 495 |  | 
|  | 496 | dropped = macb_rx_frame(bp, first_frag, tail); | 
|  | 497 | first_frag = -1; | 
|  | 498 | if (!dropped) { | 
|  | 499 | received++; | 
|  | 500 | budget--; | 
|  | 501 | } | 
|  | 502 | } | 
|  | 503 | } | 
|  | 504 |  | 
|  | 505 | if (first_frag != -1) | 
|  | 506 | bp->rx_tail = first_frag; | 
|  | 507 | else | 
|  | 508 | bp->rx_tail = tail; | 
|  | 509 |  | 
|  | 510 | return received; | 
|  | 511 | } | 
|  | 512 |  | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 513 | static int macb_poll(struct napi_struct *napi, int budget) | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 514 | { | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 515 | struct macb *bp = container_of(napi, struct macb, napi); | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 516 | int work_done; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 517 | u32 status; | 
|  | 518 |  | 
|  | 519 | status = macb_readl(bp, RSR); | 
|  | 520 | macb_writel(bp, RSR, status); | 
|  | 521 |  | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 522 | work_done = 0; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 523 | if (!status) { | 
|  | 524 | /* | 
|  | 525 | * This may happen if an interrupt was pending before | 
|  | 526 | * this function was called last time, and no packets | 
|  | 527 | * have been received since. | 
|  | 528 | */ | 
| Ben Hutchings | 288379f | 2009-01-19 16:43:59 -0800 | [diff] [blame] | 529 | napi_complete(napi); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 530 | goto out; | 
|  | 531 | } | 
|  | 532 |  | 
|  | 533 | dev_dbg(&bp->pdev->dev, "poll: status = %08lx, budget = %d\n", | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 534 | (unsigned long)status, budget); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 535 |  | 
|  | 536 | if (!(status & MACB_BIT(REC))) { | 
|  | 537 | dev_warn(&bp->pdev->dev, | 
|  | 538 | "No RX buffers complete, status = %02lx\n", | 
|  | 539 | (unsigned long)status); | 
| Ben Hutchings | 288379f | 2009-01-19 16:43:59 -0800 | [diff] [blame] | 540 | napi_complete(napi); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 541 | goto out; | 
|  | 542 | } | 
|  | 543 |  | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 544 | work_done = macb_rx(bp, budget); | 
|  | 545 | if (work_done < budget) | 
| Ben Hutchings | 288379f | 2009-01-19 16:43:59 -0800 | [diff] [blame] | 546 | napi_complete(napi); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 547 |  | 
|  | 548 | /* | 
|  | 549 | * We've done what we can to clean the buffers. Make sure we | 
|  | 550 | * get notified when new packets arrive. | 
|  | 551 | */ | 
|  | 552 | out: | 
|  | 553 | macb_writel(bp, IER, MACB_RX_INT_FLAGS); | 
|  | 554 |  | 
|  | 555 | /* TODO: Handle errors */ | 
|  | 556 |  | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 557 | return work_done; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 558 | } | 
|  | 559 |  | 
|  | 560 | static irqreturn_t macb_interrupt(int irq, void *dev_id) | 
|  | 561 | { | 
|  | 562 | struct net_device *dev = dev_id; | 
|  | 563 | struct macb *bp = netdev_priv(dev); | 
|  | 564 | u32 status; | 
|  | 565 |  | 
|  | 566 | status = macb_readl(bp, ISR); | 
|  | 567 |  | 
|  | 568 | if (unlikely(!status)) | 
|  | 569 | return IRQ_NONE; | 
|  | 570 |  | 
|  | 571 | spin_lock(&bp->lock); | 
|  | 572 |  | 
|  | 573 | while (status) { | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 574 | /* close possible race with dev_close */ | 
|  | 575 | if (unlikely(!netif_running(dev))) { | 
|  | 576 | macb_writel(bp, IDR, ~0UL); | 
|  | 577 | break; | 
|  | 578 | } | 
|  | 579 |  | 
|  | 580 | if (status & MACB_RX_INT_FLAGS) { | 
| Ben Hutchings | 288379f | 2009-01-19 16:43:59 -0800 | [diff] [blame] | 581 | if (napi_schedule_prep(&bp->napi)) { | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 582 | /* | 
|  | 583 | * There's no point taking any more interrupts | 
|  | 584 | * until we have processed the buffers | 
|  | 585 | */ | 
|  | 586 | macb_writel(bp, IDR, MACB_RX_INT_FLAGS); | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 587 | dev_dbg(&bp->pdev->dev, | 
|  | 588 | "scheduling RX softirq\n"); | 
| Ben Hutchings | 288379f | 2009-01-19 16:43:59 -0800 | [diff] [blame] | 589 | __napi_schedule(&bp->napi); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 590 | } | 
|  | 591 | } | 
|  | 592 |  | 
|  | 593 | if (status & (MACB_BIT(TCOMP) | MACB_BIT(ISR_TUND))) | 
|  | 594 | macb_tx(bp); | 
|  | 595 |  | 
|  | 596 | /* | 
|  | 597 | * Link change detection isn't possible with RMII, so we'll | 
|  | 598 | * add that if/when we get our hands on a full-blown MII PHY. | 
|  | 599 | */ | 
|  | 600 |  | 
|  | 601 | if (status & MACB_BIT(HRESP)) { | 
|  | 602 | /* | 
|  | 603 | * TODO: Reset the hardware, and maybe move the printk | 
|  | 604 | * to a lower-priority context as well (work queue?) | 
|  | 605 | */ | 
|  | 606 | printk(KERN_ERR "%s: DMA bus error: HRESP not OK\n", | 
|  | 607 | dev->name); | 
|  | 608 | } | 
|  | 609 |  | 
|  | 610 | status = macb_readl(bp, ISR); | 
|  | 611 | } | 
|  | 612 |  | 
|  | 613 | spin_unlock(&bp->lock); | 
|  | 614 |  | 
|  | 615 | return IRQ_HANDLED; | 
|  | 616 | } | 
|  | 617 |  | 
|  | 618 | static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) | 
|  | 619 | { | 
|  | 620 | struct macb *bp = netdev_priv(dev); | 
|  | 621 | dma_addr_t mapping; | 
|  | 622 | unsigned int len, entry; | 
|  | 623 | u32 ctrl; | 
|  | 624 |  | 
|  | 625 | #ifdef DEBUG | 
|  | 626 | int i; | 
|  | 627 | dev_dbg(&bp->pdev->dev, | 
|  | 628 | "start_xmit: len %u head %p data %p tail %p end %p\n", | 
| Arnaldo Carvalho de Melo | 27a884d | 2007-04-19 20:29:13 -0700 | [diff] [blame] | 629 | skb->len, skb->head, skb->data, | 
| Arnaldo Carvalho de Melo | 4305b54 | 2007-04-19 20:43:29 -0700 | [diff] [blame] | 630 | skb_tail_pointer(skb), skb_end_pointer(skb)); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 631 | dev_dbg(&bp->pdev->dev, | 
|  | 632 | "data:"); | 
|  | 633 | for (i = 0; i < 16; i++) | 
|  | 634 | printk(" %02x", (unsigned int)skb->data[i]); | 
|  | 635 | printk("\n"); | 
|  | 636 | #endif | 
|  | 637 |  | 
|  | 638 | len = skb->len; | 
|  | 639 | spin_lock_irq(&bp->lock); | 
|  | 640 |  | 
|  | 641 | /* This is a hard error, log it. */ | 
|  | 642 | if (TX_BUFFS_AVAIL(bp) < 1) { | 
|  | 643 | netif_stop_queue(dev); | 
|  | 644 | spin_unlock_irq(&bp->lock); | 
|  | 645 | dev_err(&bp->pdev->dev, | 
|  | 646 | "BUG! Tx Ring full when queue awake!\n"); | 
|  | 647 | dev_dbg(&bp->pdev->dev, "tx_head = %u, tx_tail = %u\n", | 
|  | 648 | bp->tx_head, bp->tx_tail); | 
|  | 649 | return 1; | 
|  | 650 | } | 
|  | 651 |  | 
|  | 652 | entry = bp->tx_head; | 
|  | 653 | dev_dbg(&bp->pdev->dev, "Allocated ring entry %u\n", entry); | 
|  | 654 | mapping = dma_map_single(&bp->pdev->dev, skb->data, | 
|  | 655 | len, DMA_TO_DEVICE); | 
|  | 656 | bp->tx_skb[entry].skb = skb; | 
|  | 657 | bp->tx_skb[entry].mapping = mapping; | 
|  | 658 | dev_dbg(&bp->pdev->dev, "Mapped skb data %p to DMA addr %08lx\n", | 
|  | 659 | skb->data, (unsigned long)mapping); | 
|  | 660 |  | 
|  | 661 | ctrl = MACB_BF(TX_FRMLEN, len); | 
|  | 662 | ctrl |= MACB_BIT(TX_LAST); | 
|  | 663 | if (entry == (TX_RING_SIZE - 1)) | 
|  | 664 | ctrl |= MACB_BIT(TX_WRAP); | 
|  | 665 |  | 
|  | 666 | bp->tx_ring[entry].addr = mapping; | 
|  | 667 | bp->tx_ring[entry].ctrl = ctrl; | 
|  | 668 | wmb(); | 
|  | 669 |  | 
|  | 670 | entry = NEXT_TX(entry); | 
|  | 671 | bp->tx_head = entry; | 
|  | 672 |  | 
|  | 673 | macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); | 
|  | 674 |  | 
|  | 675 | if (TX_BUFFS_AVAIL(bp) < 1) | 
|  | 676 | netif_stop_queue(dev); | 
|  | 677 |  | 
|  | 678 | spin_unlock_irq(&bp->lock); | 
|  | 679 |  | 
|  | 680 | dev->trans_start = jiffies; | 
|  | 681 |  | 
|  | 682 | return 0; | 
|  | 683 | } | 
|  | 684 |  | 
|  | 685 | static void macb_free_consistent(struct macb *bp) | 
|  | 686 | { | 
|  | 687 | if (bp->tx_skb) { | 
|  | 688 | kfree(bp->tx_skb); | 
|  | 689 | bp->tx_skb = NULL; | 
|  | 690 | } | 
|  | 691 | if (bp->rx_ring) { | 
|  | 692 | dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES, | 
|  | 693 | bp->rx_ring, bp->rx_ring_dma); | 
|  | 694 | bp->rx_ring = NULL; | 
|  | 695 | } | 
|  | 696 | if (bp->tx_ring) { | 
|  | 697 | dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES, | 
|  | 698 | bp->tx_ring, bp->tx_ring_dma); | 
|  | 699 | bp->tx_ring = NULL; | 
|  | 700 | } | 
|  | 701 | if (bp->rx_buffers) { | 
|  | 702 | dma_free_coherent(&bp->pdev->dev, | 
|  | 703 | RX_RING_SIZE * RX_BUFFER_SIZE, | 
|  | 704 | bp->rx_buffers, bp->rx_buffers_dma); | 
|  | 705 | bp->rx_buffers = NULL; | 
|  | 706 | } | 
|  | 707 | } | 
|  | 708 |  | 
|  | 709 | static int macb_alloc_consistent(struct macb *bp) | 
|  | 710 | { | 
|  | 711 | int size; | 
|  | 712 |  | 
|  | 713 | size = TX_RING_SIZE * sizeof(struct ring_info); | 
|  | 714 | bp->tx_skb = kmalloc(size, GFP_KERNEL); | 
|  | 715 | if (!bp->tx_skb) | 
|  | 716 | goto out_err; | 
|  | 717 |  | 
|  | 718 | size = RX_RING_BYTES; | 
|  | 719 | bp->rx_ring = dma_alloc_coherent(&bp->pdev->dev, size, | 
|  | 720 | &bp->rx_ring_dma, GFP_KERNEL); | 
|  | 721 | if (!bp->rx_ring) | 
|  | 722 | goto out_err; | 
|  | 723 | dev_dbg(&bp->pdev->dev, | 
|  | 724 | "Allocated RX ring of %d bytes at %08lx (mapped %p)\n", | 
|  | 725 | size, (unsigned long)bp->rx_ring_dma, bp->rx_ring); | 
|  | 726 |  | 
|  | 727 | size = TX_RING_BYTES; | 
|  | 728 | bp->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size, | 
|  | 729 | &bp->tx_ring_dma, GFP_KERNEL); | 
|  | 730 | if (!bp->tx_ring) | 
|  | 731 | goto out_err; | 
|  | 732 | dev_dbg(&bp->pdev->dev, | 
|  | 733 | "Allocated TX ring of %d bytes at %08lx (mapped %p)\n", | 
|  | 734 | size, (unsigned long)bp->tx_ring_dma, bp->tx_ring); | 
|  | 735 |  | 
|  | 736 | size = RX_RING_SIZE * RX_BUFFER_SIZE; | 
|  | 737 | bp->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size, | 
|  | 738 | &bp->rx_buffers_dma, GFP_KERNEL); | 
|  | 739 | if (!bp->rx_buffers) | 
|  | 740 | goto out_err; | 
|  | 741 | dev_dbg(&bp->pdev->dev, | 
|  | 742 | "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n", | 
|  | 743 | size, (unsigned long)bp->rx_buffers_dma, bp->rx_buffers); | 
|  | 744 |  | 
|  | 745 | return 0; | 
|  | 746 |  | 
|  | 747 | out_err: | 
|  | 748 | macb_free_consistent(bp); | 
|  | 749 | return -ENOMEM; | 
|  | 750 | } | 
|  | 751 |  | 
|  | 752 | static void macb_init_rings(struct macb *bp) | 
|  | 753 | { | 
|  | 754 | int i; | 
|  | 755 | dma_addr_t addr; | 
|  | 756 |  | 
|  | 757 | addr = bp->rx_buffers_dma; | 
|  | 758 | for (i = 0; i < RX_RING_SIZE; i++) { | 
|  | 759 | bp->rx_ring[i].addr = addr; | 
|  | 760 | bp->rx_ring[i].ctrl = 0; | 
|  | 761 | addr += RX_BUFFER_SIZE; | 
|  | 762 | } | 
|  | 763 | bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP); | 
|  | 764 |  | 
|  | 765 | for (i = 0; i < TX_RING_SIZE; i++) { | 
|  | 766 | bp->tx_ring[i].addr = 0; | 
|  | 767 | bp->tx_ring[i].ctrl = MACB_BIT(TX_USED); | 
|  | 768 | } | 
|  | 769 | bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP); | 
|  | 770 |  | 
|  | 771 | bp->rx_tail = bp->tx_head = bp->tx_tail = 0; | 
|  | 772 | } | 
|  | 773 |  | 
|  | 774 | static void macb_reset_hw(struct macb *bp) | 
|  | 775 | { | 
|  | 776 | /* Make sure we have the write buffer for ourselves */ | 
|  | 777 | wmb(); | 
|  | 778 |  | 
|  | 779 | /* | 
|  | 780 | * Disable RX and TX (XXX: Should we halt the transmission | 
|  | 781 | * more gracefully?) | 
|  | 782 | */ | 
|  | 783 | macb_writel(bp, NCR, 0); | 
|  | 784 |  | 
|  | 785 | /* Clear the stats registers (XXX: Update stats first?) */ | 
|  | 786 | macb_writel(bp, NCR, MACB_BIT(CLRSTAT)); | 
|  | 787 |  | 
|  | 788 | /* Clear all status flags */ | 
|  | 789 | macb_writel(bp, TSR, ~0UL); | 
|  | 790 | macb_writel(bp, RSR, ~0UL); | 
|  | 791 |  | 
|  | 792 | /* Disable all interrupts */ | 
|  | 793 | macb_writel(bp, IDR, ~0UL); | 
|  | 794 | macb_readl(bp, ISR); | 
|  | 795 | } | 
|  | 796 |  | 
|  | 797 | static void macb_init_hw(struct macb *bp) | 
|  | 798 | { | 
|  | 799 | u32 config; | 
|  | 800 |  | 
|  | 801 | macb_reset_hw(bp); | 
|  | 802 | __macb_set_hwaddr(bp); | 
|  | 803 |  | 
|  | 804 | config = macb_readl(bp, NCFGR) & MACB_BF(CLK, -1L); | 
|  | 805 | config |= MACB_BIT(PAE);		/* PAuse Enable */ | 
|  | 806 | config |= MACB_BIT(DRFCS);		/* Discard Rx FCS */ | 
|  | 807 | if (bp->dev->flags & IFF_PROMISC) | 
|  | 808 | config |= MACB_BIT(CAF);	/* Copy All Frames */ | 
|  | 809 | if (!(bp->dev->flags & IFF_BROADCAST)) | 
|  | 810 | config |= MACB_BIT(NBC);	/* No BroadCast */ | 
|  | 811 | macb_writel(bp, NCFGR, config); | 
|  | 812 |  | 
|  | 813 | /* Initialize TX and RX buffers */ | 
|  | 814 | macb_writel(bp, RBQP, bp->rx_ring_dma); | 
|  | 815 | macb_writel(bp, TBQP, bp->tx_ring_dma); | 
|  | 816 |  | 
|  | 817 | /* Enable TX and RX */ | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 818 | macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE)); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 819 |  | 
|  | 820 | /* Enable interrupts */ | 
|  | 821 | macb_writel(bp, IER, (MACB_BIT(RCOMP) | 
|  | 822 | | MACB_BIT(RXUBR) | 
|  | 823 | | MACB_BIT(ISR_TUND) | 
|  | 824 | | MACB_BIT(ISR_RLE) | 
|  | 825 | | MACB_BIT(TXERR) | 
|  | 826 | | MACB_BIT(TCOMP) | 
|  | 827 | | MACB_BIT(ISR_ROVR) | 
|  | 828 | | MACB_BIT(HRESP))); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 829 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 830 | } | 
|  | 831 |  | 
| Patrice Vilchez | 446ebd0 | 2007-07-12 19:07:25 +0200 | [diff] [blame] | 832 | /* | 
|  | 833 | * The hash address register is 64 bits long and takes up two | 
|  | 834 | * locations in the memory map.  The least significant bits are stored | 
|  | 835 | * in EMAC_HSL and the most significant bits in EMAC_HSH. | 
|  | 836 | * | 
|  | 837 | * The unicast hash enable and the multicast hash enable bits in the | 
|  | 838 | * network configuration register enable the reception of hash matched | 
|  | 839 | * frames. The destination address is reduced to a 6 bit index into | 
|  | 840 | * the 64 bit hash register using the following hash function.  The | 
|  | 841 | * hash function is an exclusive or of every sixth bit of the | 
|  | 842 | * destination address. | 
|  | 843 | * | 
|  | 844 | * hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47] | 
|  | 845 | * hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46] | 
|  | 846 | * hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45] | 
|  | 847 | * hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44] | 
|  | 848 | * hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43] | 
|  | 849 | * hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42] | 
|  | 850 | * | 
|  | 851 | * da[0] represents the least significant bit of the first byte | 
|  | 852 | * received, that is, the multicast/unicast indicator, and da[47] | 
|  | 853 | * represents the most significant bit of the last byte received.  If | 
|  | 854 | * the hash index, hi[n], points to a bit that is set in the hash | 
|  | 855 | * register then the frame will be matched according to whether the | 
|  | 856 | * frame is multicast or unicast.  A multicast match will be signalled | 
|  | 857 | * if the multicast hash enable bit is set, da[0] is 1 and the hash | 
|  | 858 | * index points to a bit set in the hash register.  A unicast match | 
|  | 859 | * will be signalled if the unicast hash enable bit is set, da[0] is 0 | 
|  | 860 | * and the hash index points to a bit set in the hash register.  To | 
|  | 861 | * receive all multicast frames, the hash register should be set with | 
|  | 862 | * all ones and the multicast hash enable bit should be set in the | 
|  | 863 | * network configuration register. | 
|  | 864 | */ | 
|  | 865 |  | 
|  | 866 | static inline int hash_bit_value(int bitnr, __u8 *addr) | 
|  | 867 | { | 
|  | 868 | if (addr[bitnr / 8] & (1 << (bitnr % 8))) | 
|  | 869 | return 1; | 
|  | 870 | return 0; | 
|  | 871 | } | 
|  | 872 |  | 
|  | 873 | /* | 
|  | 874 | * Return the hash index value for the specified address. | 
|  | 875 | */ | 
|  | 876 | static int hash_get_index(__u8 *addr) | 
|  | 877 | { | 
|  | 878 | int i, j, bitval; | 
|  | 879 | int hash_index = 0; | 
|  | 880 |  | 
|  | 881 | for (j = 0; j < 6; j++) { | 
|  | 882 | for (i = 0, bitval = 0; i < 8; i++) | 
|  | 883 | bitval ^= hash_bit_value(i*6 + j, addr); | 
|  | 884 |  | 
|  | 885 | hash_index |= (bitval << j); | 
|  | 886 | } | 
|  | 887 |  | 
|  | 888 | return hash_index; | 
|  | 889 | } | 
|  | 890 |  | 
|  | 891 | /* | 
|  | 892 | * Add multicast addresses to the internal multicast-hash table. | 
|  | 893 | */ | 
|  | 894 | static void macb_sethashtable(struct net_device *dev) | 
|  | 895 | { | 
|  | 896 | struct dev_mc_list *curr; | 
|  | 897 | unsigned long mc_filter[2]; | 
|  | 898 | unsigned int i, bitnr; | 
|  | 899 | struct macb *bp = netdev_priv(dev); | 
|  | 900 |  | 
|  | 901 | mc_filter[0] = mc_filter[1] = 0; | 
|  | 902 |  | 
|  | 903 | curr = dev->mc_list; | 
|  | 904 | for (i = 0; i < dev->mc_count; i++, curr = curr->next) { | 
|  | 905 | if (!curr) break;	/* unexpected end of list */ | 
|  | 906 |  | 
|  | 907 | bitnr = hash_get_index(curr->dmi_addr); | 
|  | 908 | mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); | 
|  | 909 | } | 
|  | 910 |  | 
|  | 911 | macb_writel(bp, HRB, mc_filter[0]); | 
|  | 912 | macb_writel(bp, HRT, mc_filter[1]); | 
|  | 913 | } | 
|  | 914 |  | 
|  | 915 | /* | 
|  | 916 | * Enable/Disable promiscuous and multicast modes. | 
|  | 917 | */ | 
|  | 918 | static void macb_set_rx_mode(struct net_device *dev) | 
|  | 919 | { | 
|  | 920 | unsigned long cfg; | 
|  | 921 | struct macb *bp = netdev_priv(dev); | 
|  | 922 |  | 
|  | 923 | cfg = macb_readl(bp, NCFGR); | 
|  | 924 |  | 
|  | 925 | if (dev->flags & IFF_PROMISC) | 
|  | 926 | /* Enable promiscuous mode */ | 
|  | 927 | cfg |= MACB_BIT(CAF); | 
|  | 928 | else if (dev->flags & (~IFF_PROMISC)) | 
|  | 929 | /* Disable promiscuous mode */ | 
|  | 930 | cfg &= ~MACB_BIT(CAF); | 
|  | 931 |  | 
|  | 932 | if (dev->flags & IFF_ALLMULTI) { | 
|  | 933 | /* Enable all multicast mode */ | 
|  | 934 | macb_writel(bp, HRB, -1); | 
|  | 935 | macb_writel(bp, HRT, -1); | 
|  | 936 | cfg |= MACB_BIT(NCFGR_MTI); | 
|  | 937 | } else if (dev->mc_count > 0) { | 
|  | 938 | /* Enable specific multicasts */ | 
|  | 939 | macb_sethashtable(dev); | 
|  | 940 | cfg |= MACB_BIT(NCFGR_MTI); | 
|  | 941 | } else if (dev->flags & (~IFF_ALLMULTI)) { | 
|  | 942 | /* Disable all multicast mode */ | 
|  | 943 | macb_writel(bp, HRB, 0); | 
|  | 944 | macb_writel(bp, HRT, 0); | 
|  | 945 | cfg &= ~MACB_BIT(NCFGR_MTI); | 
|  | 946 | } | 
|  | 947 |  | 
|  | 948 | macb_writel(bp, NCFGR, cfg); | 
|  | 949 | } | 
|  | 950 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 951 | static int macb_open(struct net_device *dev) | 
|  | 952 | { | 
|  | 953 | struct macb *bp = netdev_priv(dev); | 
|  | 954 | int err; | 
|  | 955 |  | 
|  | 956 | dev_dbg(&bp->pdev->dev, "open\n"); | 
|  | 957 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 958 | /* if the phy is not yet register, retry later*/ | 
|  | 959 | if (!bp->phy_dev) | 
|  | 960 | return -EAGAIN; | 
|  | 961 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 962 | if (!is_valid_ether_addr(dev->dev_addr)) | 
|  | 963 | return -EADDRNOTAVAIL; | 
|  | 964 |  | 
|  | 965 | err = macb_alloc_consistent(bp); | 
|  | 966 | if (err) { | 
|  | 967 | printk(KERN_ERR | 
|  | 968 | "%s: Unable to allocate DMA memory (error %d)\n", | 
|  | 969 | dev->name, err); | 
|  | 970 | return err; | 
|  | 971 | } | 
|  | 972 |  | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 973 | napi_enable(&bp->napi); | 
|  | 974 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 975 | macb_init_rings(bp); | 
|  | 976 | macb_init_hw(bp); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 977 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 978 | /* schedule a link state check */ | 
|  | 979 | phy_start(bp->phy_dev); | 
|  | 980 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 981 | netif_start_queue(dev); | 
|  | 982 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 983 | return 0; | 
|  | 984 | } | 
|  | 985 |  | 
|  | 986 | static int macb_close(struct net_device *dev) | 
|  | 987 | { | 
|  | 988 | struct macb *bp = netdev_priv(dev); | 
|  | 989 | unsigned long flags; | 
|  | 990 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 991 | netif_stop_queue(dev); | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 992 | napi_disable(&bp->napi); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 993 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 994 | if (bp->phy_dev) | 
|  | 995 | phy_stop(bp->phy_dev); | 
|  | 996 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 997 | spin_lock_irqsave(&bp->lock, flags); | 
|  | 998 | macb_reset_hw(bp); | 
|  | 999 | netif_carrier_off(dev); | 
|  | 1000 | spin_unlock_irqrestore(&bp->lock, flags); | 
|  | 1001 |  | 
|  | 1002 | macb_free_consistent(bp); | 
|  | 1003 |  | 
|  | 1004 | return 0; | 
|  | 1005 | } | 
|  | 1006 |  | 
|  | 1007 | static struct net_device_stats *macb_get_stats(struct net_device *dev) | 
|  | 1008 | { | 
|  | 1009 | struct macb *bp = netdev_priv(dev); | 
|  | 1010 | struct net_device_stats *nstat = &bp->stats; | 
|  | 1011 | struct macb_stats *hwstat = &bp->hw_stats; | 
|  | 1012 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1013 | /* read stats from hardware */ | 
|  | 1014 | macb_update_stats(bp); | 
|  | 1015 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1016 | /* Convert HW stats into netdevice stats */ | 
|  | 1017 | nstat->rx_errors = (hwstat->rx_fcs_errors + | 
|  | 1018 | hwstat->rx_align_errors + | 
|  | 1019 | hwstat->rx_resource_errors + | 
|  | 1020 | hwstat->rx_overruns + | 
|  | 1021 | hwstat->rx_oversize_pkts + | 
|  | 1022 | hwstat->rx_jabbers + | 
|  | 1023 | hwstat->rx_undersize_pkts + | 
|  | 1024 | hwstat->sqe_test_errors + | 
|  | 1025 | hwstat->rx_length_mismatch); | 
|  | 1026 | nstat->tx_errors = (hwstat->tx_late_cols + | 
|  | 1027 | hwstat->tx_excessive_cols + | 
|  | 1028 | hwstat->tx_underruns + | 
|  | 1029 | hwstat->tx_carrier_errors); | 
|  | 1030 | nstat->collisions = (hwstat->tx_single_cols + | 
|  | 1031 | hwstat->tx_multiple_cols + | 
|  | 1032 | hwstat->tx_excessive_cols); | 
|  | 1033 | nstat->rx_length_errors = (hwstat->rx_oversize_pkts + | 
|  | 1034 | hwstat->rx_jabbers + | 
|  | 1035 | hwstat->rx_undersize_pkts + | 
|  | 1036 | hwstat->rx_length_mismatch); | 
|  | 1037 | nstat->rx_over_errors = hwstat->rx_resource_errors; | 
|  | 1038 | nstat->rx_crc_errors = hwstat->rx_fcs_errors; | 
|  | 1039 | nstat->rx_frame_errors = hwstat->rx_align_errors; | 
|  | 1040 | nstat->rx_fifo_errors = hwstat->rx_overruns; | 
|  | 1041 | /* XXX: What does "missed" mean? */ | 
|  | 1042 | nstat->tx_aborted_errors = hwstat->tx_excessive_cols; | 
|  | 1043 | nstat->tx_carrier_errors = hwstat->tx_carrier_errors; | 
|  | 1044 | nstat->tx_fifo_errors = hwstat->tx_underruns; | 
|  | 1045 | /* Don't know about heartbeat or window errors... */ | 
|  | 1046 |  | 
|  | 1047 | return nstat; | 
|  | 1048 | } | 
|  | 1049 |  | 
|  | 1050 | static int macb_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 
|  | 1051 | { | 
|  | 1052 | struct macb *bp = netdev_priv(dev); | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1053 | struct phy_device *phydev = bp->phy_dev; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1054 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1055 | if (!phydev) | 
|  | 1056 | return -ENODEV; | 
|  | 1057 |  | 
|  | 1058 | return phy_ethtool_gset(phydev, cmd); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1059 | } | 
|  | 1060 |  | 
|  | 1061 | static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 
|  | 1062 | { | 
|  | 1063 | struct macb *bp = netdev_priv(dev); | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1064 | struct phy_device *phydev = bp->phy_dev; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1065 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1066 | if (!phydev) | 
|  | 1067 | return -ENODEV; | 
|  | 1068 |  | 
|  | 1069 | return phy_ethtool_sset(phydev, cmd); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1070 | } | 
|  | 1071 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1072 | static void macb_get_drvinfo(struct net_device *dev, | 
|  | 1073 | struct ethtool_drvinfo *info) | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1074 | { | 
|  | 1075 | struct macb *bp = netdev_priv(dev); | 
|  | 1076 |  | 
|  | 1077 | strcpy(info->driver, bp->pdev->dev.driver->name); | 
|  | 1078 | strcpy(info->version, "$Revision: 1.14 $"); | 
| Kay Sievers | db1d7bf | 2009-01-26 21:12:58 -0800 | [diff] [blame] | 1079 | strcpy(info->bus_info, dev_name(&bp->pdev->dev)); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1080 | } | 
|  | 1081 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1082 | static struct ethtool_ops macb_ethtool_ops = { | 
|  | 1083 | .get_settings		= macb_get_settings, | 
|  | 1084 | .set_settings		= macb_set_settings, | 
|  | 1085 | .get_drvinfo		= macb_get_drvinfo, | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1086 | .get_link		= ethtool_op_get_link, | 
|  | 1087 | }; | 
|  | 1088 |  | 
|  | 1089 | static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | 
|  | 1090 | { | 
|  | 1091 | struct macb *bp = netdev_priv(dev); | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1092 | struct phy_device *phydev = bp->phy_dev; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1093 |  | 
|  | 1094 | if (!netif_running(dev)) | 
|  | 1095 | return -EINVAL; | 
|  | 1096 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1097 | if (!phydev) | 
|  | 1098 | return -ENODEV; | 
|  | 1099 |  | 
|  | 1100 | return phy_mii_ioctl(phydev, if_mii(rq), cmd); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1101 | } | 
|  | 1102 |  | 
| Haavard Skinnemoen | 06c3fd6 | 2008-01-31 13:10:22 +0100 | [diff] [blame] | 1103 | static int __init macb_probe(struct platform_device *pdev) | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1104 | { | 
|  | 1105 | struct eth_platform_data *pdata; | 
|  | 1106 | struct resource *regs; | 
|  | 1107 | struct net_device *dev; | 
|  | 1108 | struct macb *bp; | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1109 | struct phy_device *phydev; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1110 | unsigned long pclk_hz; | 
|  | 1111 | u32 config; | 
|  | 1112 | int err = -ENXIO; | 
|  | 1113 |  | 
|  | 1114 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 
|  | 1115 | if (!regs) { | 
|  | 1116 | dev_err(&pdev->dev, "no mmio resource defined\n"); | 
|  | 1117 | goto err_out; | 
|  | 1118 | } | 
|  | 1119 |  | 
|  | 1120 | err = -ENOMEM; | 
|  | 1121 | dev = alloc_etherdev(sizeof(*bp)); | 
|  | 1122 | if (!dev) { | 
|  | 1123 | dev_err(&pdev->dev, "etherdev alloc failed, aborting.\n"); | 
|  | 1124 | goto err_out; | 
|  | 1125 | } | 
|  | 1126 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1127 | SET_NETDEV_DEV(dev, &pdev->dev); | 
|  | 1128 |  | 
|  | 1129 | /* TODO: Actually, we have some interesting features... */ | 
|  | 1130 | dev->features |= 0; | 
|  | 1131 |  | 
|  | 1132 | bp = netdev_priv(dev); | 
|  | 1133 | bp->pdev = pdev; | 
|  | 1134 | bp->dev = dev; | 
|  | 1135 |  | 
|  | 1136 | spin_lock_init(&bp->lock); | 
|  | 1137 |  | 
| Andrew Victor | 0cc8674 | 2007-02-07 16:40:44 +0100 | [diff] [blame] | 1138 | #if defined(CONFIG_ARCH_AT91) | 
|  | 1139 | bp->pclk = clk_get(&pdev->dev, "macb_clk"); | 
|  | 1140 | if (IS_ERR(bp->pclk)) { | 
|  | 1141 | dev_err(&pdev->dev, "failed to get macb_clk\n"); | 
|  | 1142 | goto err_out_free_dev; | 
|  | 1143 | } | 
|  | 1144 | clk_enable(bp->pclk); | 
|  | 1145 | #else | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1146 | bp->pclk = clk_get(&pdev->dev, "pclk"); | 
|  | 1147 | if (IS_ERR(bp->pclk)) { | 
|  | 1148 | dev_err(&pdev->dev, "failed to get pclk\n"); | 
|  | 1149 | goto err_out_free_dev; | 
|  | 1150 | } | 
|  | 1151 | bp->hclk = clk_get(&pdev->dev, "hclk"); | 
|  | 1152 | if (IS_ERR(bp->hclk)) { | 
|  | 1153 | dev_err(&pdev->dev, "failed to get hclk\n"); | 
|  | 1154 | goto err_out_put_pclk; | 
|  | 1155 | } | 
|  | 1156 |  | 
|  | 1157 | clk_enable(bp->pclk); | 
|  | 1158 | clk_enable(bp->hclk); | 
| Andrew Victor | 0cc8674 | 2007-02-07 16:40:44 +0100 | [diff] [blame] | 1159 | #endif | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1160 |  | 
|  | 1161 | bp->regs = ioremap(regs->start, regs->end - regs->start + 1); | 
|  | 1162 | if (!bp->regs) { | 
|  | 1163 | dev_err(&pdev->dev, "failed to map registers, aborting.\n"); | 
|  | 1164 | err = -ENOMEM; | 
|  | 1165 | goto err_out_disable_clocks; | 
|  | 1166 | } | 
|  | 1167 |  | 
|  | 1168 | dev->irq = platform_get_irq(pdev, 0); | 
| Thomas Gleixner | 38515e9 | 2007-02-14 00:33:16 -0800 | [diff] [blame] | 1169 | err = request_irq(dev->irq, macb_interrupt, IRQF_SAMPLE_RANDOM, | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1170 | dev->name, dev); | 
|  | 1171 | if (err) { | 
|  | 1172 | printk(KERN_ERR | 
|  | 1173 | "%s: Unable to request IRQ %d (error %d)\n", | 
|  | 1174 | dev->name, dev->irq, err); | 
|  | 1175 | goto err_out_iounmap; | 
|  | 1176 | } | 
|  | 1177 |  | 
|  | 1178 | dev->open = macb_open; | 
|  | 1179 | dev->stop = macb_close; | 
|  | 1180 | dev->hard_start_xmit = macb_start_xmit; | 
|  | 1181 | dev->get_stats = macb_get_stats; | 
| Patrice Vilchez | 446ebd0 | 2007-07-12 19:07:25 +0200 | [diff] [blame] | 1182 | dev->set_multicast_list = macb_set_rx_mode; | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1183 | dev->do_ioctl = macb_ioctl; | 
| Stephen Hemminger | bea3348 | 2007-10-03 16:41:36 -0700 | [diff] [blame] | 1184 | netif_napi_add(dev, &bp->napi, macb_poll, 64); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1185 | dev->ethtool_ops = &macb_ethtool_ops; | 
|  | 1186 |  | 
|  | 1187 | dev->base_addr = regs->start; | 
|  | 1188 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1189 | /* Set MII management clock divider */ | 
|  | 1190 | pclk_hz = clk_get_rate(bp->pclk); | 
|  | 1191 | if (pclk_hz <= 20000000) | 
|  | 1192 | config = MACB_BF(CLK, MACB_CLK_DIV8); | 
|  | 1193 | else if (pclk_hz <= 40000000) | 
|  | 1194 | config = MACB_BF(CLK, MACB_CLK_DIV16); | 
|  | 1195 | else if (pclk_hz <= 80000000) | 
|  | 1196 | config = MACB_BF(CLK, MACB_CLK_DIV32); | 
|  | 1197 | else | 
|  | 1198 | config = MACB_BF(CLK, MACB_CLK_DIV64); | 
|  | 1199 | macb_writel(bp, NCFGR, config); | 
|  | 1200 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1201 | macb_get_hwaddr(bp); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1202 | pdata = pdev->dev.platform_data; | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1203 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1204 | if (pdata && pdata->is_rmii) | 
| Andrew Victor | 0cc8674 | 2007-02-07 16:40:44 +0100 | [diff] [blame] | 1205 | #if defined(CONFIG_ARCH_AT91) | 
|  | 1206 | macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) ); | 
|  | 1207 | #else | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1208 | macb_writel(bp, USRIO, 0); | 
| Andrew Victor | 0cc8674 | 2007-02-07 16:40:44 +0100 | [diff] [blame] | 1209 | #endif | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1210 | else | 
| Andrew Victor | 0cc8674 | 2007-02-07 16:40:44 +0100 | [diff] [blame] | 1211 | #if defined(CONFIG_ARCH_AT91) | 
|  | 1212 | macb_writel(bp, USRIO, MACB_BIT(CLKEN)); | 
|  | 1213 | #else | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1214 | macb_writel(bp, USRIO, MACB_BIT(MII)); | 
| Andrew Victor | 0cc8674 | 2007-02-07 16:40:44 +0100 | [diff] [blame] | 1215 | #endif | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1216 |  | 
|  | 1217 | bp->tx_pending = DEF_TX_RING_PENDING; | 
|  | 1218 |  | 
|  | 1219 | err = register_netdev(dev); | 
|  | 1220 | if (err) { | 
|  | 1221 | dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); | 
|  | 1222 | goto err_out_free_irq; | 
|  | 1223 | } | 
|  | 1224 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1225 | if (macb_mii_init(bp) != 0) { | 
|  | 1226 | goto err_out_unregister_netdev; | 
|  | 1227 | } | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1228 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1229 | platform_set_drvdata(pdev, dev); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1230 |  | 
| Johannes Berg | e174961 | 2008-10-27 15:59:26 -0700 | [diff] [blame] | 1231 | printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d (%pM)\n", | 
|  | 1232 | dev->name, dev->base_addr, dev->irq, dev->dev_addr); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1233 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1234 | phydev = bp->phy_dev; | 
|  | 1235 | printk(KERN_INFO "%s: attached PHY driver [%s] " | 
| Kay Sievers | db1d7bf | 2009-01-26 21:12:58 -0800 | [diff] [blame] | 1236 | "(mii_bus:phy_addr=%s, irq=%d)\n", dev->name, | 
|  | 1237 | phydev->drv->name, dev_name(&phydev->dev), phydev->irq); | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1238 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1239 | return 0; | 
|  | 1240 |  | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1241 | err_out_unregister_netdev: | 
|  | 1242 | unregister_netdev(dev); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1243 | err_out_free_irq: | 
|  | 1244 | free_irq(dev->irq, dev); | 
|  | 1245 | err_out_iounmap: | 
|  | 1246 | iounmap(bp->regs); | 
|  | 1247 | err_out_disable_clocks: | 
| Andrew Victor | 0cc8674 | 2007-02-07 16:40:44 +0100 | [diff] [blame] | 1248 | #ifndef CONFIG_ARCH_AT91 | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1249 | clk_disable(bp->hclk); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1250 | clk_put(bp->hclk); | 
| Andrew Victor | 0cc8674 | 2007-02-07 16:40:44 +0100 | [diff] [blame] | 1251 | #endif | 
|  | 1252 | clk_disable(bp->pclk); | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1253 | #ifndef CONFIG_ARCH_AT91 | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1254 | err_out_put_pclk: | 
| frederic RODO | 6c36a70 | 2007-07-12 19:07:24 +0200 | [diff] [blame] | 1255 | #endif | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1256 | clk_put(bp->pclk); | 
|  | 1257 | err_out_free_dev: | 
|  | 1258 | free_netdev(dev); | 
|  | 1259 | err_out: | 
|  | 1260 | platform_set_drvdata(pdev, NULL); | 
|  | 1261 | return err; | 
|  | 1262 | } | 
|  | 1263 |  | 
| Haavard Skinnemoen | 06c3fd6 | 2008-01-31 13:10:22 +0100 | [diff] [blame] | 1264 | static int __exit macb_remove(struct platform_device *pdev) | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1265 | { | 
|  | 1266 | struct net_device *dev; | 
|  | 1267 | struct macb *bp; | 
|  | 1268 |  | 
|  | 1269 | dev = platform_get_drvdata(pdev); | 
|  | 1270 |  | 
|  | 1271 | if (dev) { | 
|  | 1272 | bp = netdev_priv(dev); | 
| Atsushi Nemoto | 84b7901 | 2008-04-10 23:30:07 +0900 | [diff] [blame] | 1273 | if (bp->phy_dev) | 
|  | 1274 | phy_disconnect(bp->phy_dev); | 
| Lennert Buytenhek | 298cf9b | 2008-10-08 16:29:57 -0700 | [diff] [blame] | 1275 | mdiobus_unregister(bp->mii_bus); | 
|  | 1276 | kfree(bp->mii_bus->irq); | 
|  | 1277 | mdiobus_free(bp->mii_bus); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1278 | unregister_netdev(dev); | 
|  | 1279 | free_irq(dev->irq, dev); | 
|  | 1280 | iounmap(bp->regs); | 
| Andrew Victor | 0cc8674 | 2007-02-07 16:40:44 +0100 | [diff] [blame] | 1281 | #ifndef CONFIG_ARCH_AT91 | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1282 | clk_disable(bp->hclk); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1283 | clk_put(bp->hclk); | 
| Andrew Victor | 0cc8674 | 2007-02-07 16:40:44 +0100 | [diff] [blame] | 1284 | #endif | 
|  | 1285 | clk_disable(bp->pclk); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1286 | clk_put(bp->pclk); | 
|  | 1287 | free_netdev(dev); | 
|  | 1288 | platform_set_drvdata(pdev, NULL); | 
|  | 1289 | } | 
|  | 1290 |  | 
|  | 1291 | return 0; | 
|  | 1292 | } | 
|  | 1293 |  | 
| Haavard Skinnemoen | c1f598f | 2008-03-04 13:39:29 +0100 | [diff] [blame] | 1294 | #ifdef CONFIG_PM | 
|  | 1295 | static int macb_suspend(struct platform_device *pdev, pm_message_t state) | 
|  | 1296 | { | 
|  | 1297 | struct net_device *netdev = platform_get_drvdata(pdev); | 
|  | 1298 | struct macb *bp = netdev_priv(netdev); | 
|  | 1299 |  | 
|  | 1300 | netif_device_detach(netdev); | 
|  | 1301 |  | 
|  | 1302 | #ifndef CONFIG_ARCH_AT91 | 
|  | 1303 | clk_disable(bp->hclk); | 
|  | 1304 | #endif | 
|  | 1305 | clk_disable(bp->pclk); | 
|  | 1306 |  | 
|  | 1307 | return 0; | 
|  | 1308 | } | 
|  | 1309 |  | 
|  | 1310 | static int macb_resume(struct platform_device *pdev) | 
|  | 1311 | { | 
|  | 1312 | struct net_device *netdev = platform_get_drvdata(pdev); | 
|  | 1313 | struct macb *bp = netdev_priv(netdev); | 
|  | 1314 |  | 
|  | 1315 | clk_enable(bp->pclk); | 
|  | 1316 | #ifndef CONFIG_ARCH_AT91 | 
|  | 1317 | clk_enable(bp->hclk); | 
|  | 1318 | #endif | 
|  | 1319 |  | 
|  | 1320 | netif_device_attach(netdev); | 
|  | 1321 |  | 
|  | 1322 | return 0; | 
|  | 1323 | } | 
|  | 1324 | #else | 
|  | 1325 | #define macb_suspend	NULL | 
|  | 1326 | #define macb_resume	NULL | 
|  | 1327 | #endif | 
|  | 1328 |  | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1329 | static struct platform_driver macb_driver = { | 
| Haavard Skinnemoen | 06c3fd6 | 2008-01-31 13:10:22 +0100 | [diff] [blame] | 1330 | .remove		= __exit_p(macb_remove), | 
| Haavard Skinnemoen | c1f598f | 2008-03-04 13:39:29 +0100 | [diff] [blame] | 1331 | .suspend	= macb_suspend, | 
|  | 1332 | .resume		= macb_resume, | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1333 | .driver		= { | 
|  | 1334 | .name		= "macb", | 
| Kay Sievers | 72abb46 | 2008-04-18 13:50:44 -0700 | [diff] [blame] | 1335 | .owner	= THIS_MODULE, | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1336 | }, | 
|  | 1337 | }; | 
|  | 1338 |  | 
|  | 1339 | static int __init macb_init(void) | 
|  | 1340 | { | 
| Haavard Skinnemoen | 06c3fd6 | 2008-01-31 13:10:22 +0100 | [diff] [blame] | 1341 | return platform_driver_probe(&macb_driver, macb_probe); | 
| Haavard Skinnemoen | 89e5785 | 2006-11-09 14:51:17 +0100 | [diff] [blame] | 1342 | } | 
|  | 1343 |  | 
|  | 1344 | static void __exit macb_exit(void) | 
|  | 1345 | { | 
|  | 1346 | platform_driver_unregister(&macb_driver); | 
|  | 1347 | } | 
|  | 1348 |  | 
|  | 1349 | module_init(macb_init); | 
|  | 1350 | module_exit(macb_exit); | 
|  | 1351 |  | 
|  | 1352 | MODULE_LICENSE("GPL"); | 
|  | 1353 | MODULE_DESCRIPTION("Atmel MACB Ethernet driver"); | 
|  | 1354 | MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>"); | 
| Kay Sievers | 72abb46 | 2008-04-18 13:50:44 -0700 | [diff] [blame] | 1355 | MODULE_ALIAS("platform:macb"); |