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