diff options
Diffstat (limited to 'drivers/net/fs_enet')
| -rw-r--r-- | drivers/net/fs_enet/Kconfig | 34 | ||||
| -rw-r--r-- | drivers/net/fs_enet/Makefile | 14 | ||||
| -rw-r--r-- | drivers/net/fs_enet/fec.h | 42 | ||||
| -rw-r--r-- | drivers/net/fs_enet/fs_enet-main.c | 1196 | ||||
| -rw-r--r-- | drivers/net/fs_enet/fs_enet.h | 244 | ||||
| -rw-r--r-- | drivers/net/fs_enet/mac-fcc.c | 584 | ||||
| -rw-r--r-- | drivers/net/fs_enet/mac-fec.c | 498 | ||||
| -rw-r--r-- | drivers/net/fs_enet/mac-scc.c | 484 | ||||
| -rw-r--r-- | drivers/net/fs_enet/mii-bitbang.c | 246 | ||||
| -rw-r--r-- | drivers/net/fs_enet/mii-fec.c | 251 |
10 files changed, 3593 insertions, 0 deletions
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig new file mode 100644 index 00000000000..fc073b5a38c --- /dev/null +++ b/drivers/net/fs_enet/Kconfig | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | config FS_ENET | ||
| 2 | tristate "Freescale Ethernet Driver" | ||
| 3 | depends on CPM1 || CPM2 || PPC_MPC512x | ||
| 4 | select MII | ||
| 5 | select PHYLIB | ||
| 6 | |||
| 7 | config FS_ENET_MPC5121_FEC | ||
| 8 | def_bool y if (FS_ENET && PPC_MPC512x) | ||
| 9 | select FS_ENET_HAS_FEC | ||
| 10 | |||
| 11 | config FS_ENET_HAS_SCC | ||
| 12 | bool "Chip has an SCC usable for ethernet" | ||
| 13 | depends on FS_ENET && (CPM1 || CPM2) | ||
| 14 | default y | ||
| 15 | |||
| 16 | config FS_ENET_HAS_FCC | ||
| 17 | bool "Chip has an FCC usable for ethernet" | ||
| 18 | depends on FS_ENET && CPM2 | ||
| 19 | default y | ||
| 20 | |||
| 21 | config FS_ENET_HAS_FEC | ||
| 22 | bool "Chip has an FEC usable for ethernet" | ||
| 23 | depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC) | ||
| 24 | select FS_ENET_MDIO_FEC | ||
| 25 | default y | ||
| 26 | |||
| 27 | config FS_ENET_MDIO_FEC | ||
| 28 | tristate "MDIO driver for FEC" | ||
| 29 | depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC) | ||
| 30 | |||
| 31 | config FS_ENET_MDIO_FCC | ||
| 32 | tristate "MDIO driver for FCC" | ||
| 33 | depends on FS_ENET && CPM2 | ||
| 34 | select MDIO_BITBANG | ||
diff --git a/drivers/net/fs_enet/Makefile b/drivers/net/fs_enet/Makefile new file mode 100644 index 00000000000..d4a305ee345 --- /dev/null +++ b/drivers/net/fs_enet/Makefile | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the Freescale Ethernet controllers | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_FS_ENET) += fs_enet.o | ||
| 6 | |||
| 7 | fs_enet-$(CONFIG_FS_ENET_HAS_SCC) += mac-scc.o | ||
| 8 | fs_enet-$(CONFIG_FS_ENET_HAS_FEC) += mac-fec.o | ||
| 9 | fs_enet-$(CONFIG_FS_ENET_HAS_FCC) += mac-fcc.o | ||
| 10 | |||
| 11 | obj-$(CONFIG_FS_ENET_MDIO_FEC) += mii-fec.o | ||
| 12 | obj-$(CONFIG_FS_ENET_MDIO_FCC) += mii-bitbang.o | ||
| 13 | |||
| 14 | fs_enet-objs := fs_enet-main.o $(fs_enet-m) | ||
diff --git a/drivers/net/fs_enet/fec.h b/drivers/net/fs_enet/fec.h new file mode 100644 index 00000000000..e980527e2b9 --- /dev/null +++ b/drivers/net/fs_enet/fec.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | #ifndef FS_ENET_FEC_H | ||
| 2 | #define FS_ENET_FEC_H | ||
| 3 | |||
| 4 | /* CRC polynomium used by the FEC for the multicast group filtering */ | ||
| 5 | #define FEC_CRC_POLY 0x04C11DB7 | ||
| 6 | |||
| 7 | #define FEC_MAX_MULTICAST_ADDRS 64 | ||
| 8 | |||
| 9 | /* Interrupt events/masks. | ||
| 10 | */ | ||
| 11 | #define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */ | ||
| 12 | #define FEC_ENET_BABR 0x40000000U /* Babbling receiver */ | ||
| 13 | #define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */ | ||
| 14 | #define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */ | ||
| 15 | #define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */ | ||
| 16 | #define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */ | ||
| 17 | #define FEC_ENET_RXF 0x02000000U /* Full frame received */ | ||
| 18 | #define FEC_ENET_RXB 0x01000000U /* A buffer was received */ | ||
| 19 | #define FEC_ENET_MII 0x00800000U /* MII interrupt */ | ||
| 20 | #define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */ | ||
| 21 | |||
| 22 | #define FEC_ECNTRL_PINMUX 0x00000004 | ||
| 23 | #define FEC_ECNTRL_ETHER_EN 0x00000002 | ||
| 24 | #define FEC_ECNTRL_RESET 0x00000001 | ||
| 25 | |||
| 26 | #define FEC_RCNTRL_BC_REJ 0x00000010 | ||
| 27 | #define FEC_RCNTRL_PROM 0x00000008 | ||
| 28 | #define FEC_RCNTRL_MII_MODE 0x00000004 | ||
| 29 | #define FEC_RCNTRL_DRT 0x00000002 | ||
| 30 | #define FEC_RCNTRL_LOOP 0x00000001 | ||
| 31 | |||
| 32 | #define FEC_TCNTRL_FDEN 0x00000004 | ||
| 33 | #define FEC_TCNTRL_HBC 0x00000002 | ||
| 34 | #define FEC_TCNTRL_GTS 0x00000001 | ||
| 35 | |||
| 36 | |||
| 37 | |||
| 38 | /* | ||
| 39 | * Delay to wait for FEC reset command to complete (in us) | ||
| 40 | */ | ||
| 41 | #define FEC_RESET_DELAY 50 | ||
| 42 | #endif | ||
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c new file mode 100644 index 00000000000..329ef231a09 --- /dev/null +++ b/drivers/net/fs_enet/fs_enet-main.c | |||
| @@ -0,0 +1,1196 @@ | |||
| 1 | /* | ||
| 2 | * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 Intracom S.A. | ||
| 5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
| 6 | * | ||
| 7 | * 2005 (c) MontaVista Software, Inc. | ||
| 8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
| 9 | * | ||
| 10 | * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com> | ||
| 11 | * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se> | ||
| 12 | * | ||
| 13 | * This file is licensed under the terms of the GNU General Public License | ||
| 14 | * version 2. This program is licensed "as is" without any warranty of any | ||
| 15 | * kind, whether express or implied. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/kernel.h> | ||
| 20 | #include <linux/types.h> | ||
| 21 | #include <linux/string.h> | ||
| 22 | #include <linux/ptrace.h> | ||
| 23 | #include <linux/errno.h> | ||
| 24 | #include <linux/ioport.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | #include <linux/interrupt.h> | ||
| 27 | #include <linux/init.h> | ||
| 28 | #include <linux/delay.h> | ||
| 29 | #include <linux/netdevice.h> | ||
| 30 | #include <linux/etherdevice.h> | ||
| 31 | #include <linux/skbuff.h> | ||
| 32 | #include <linux/spinlock.h> | ||
| 33 | #include <linux/mii.h> | ||
| 34 | #include <linux/ethtool.h> | ||
| 35 | #include <linux/bitops.h> | ||
| 36 | #include <linux/fs.h> | ||
| 37 | #include <linux/platform_device.h> | ||
| 38 | #include <linux/phy.h> | ||
| 39 | #include <linux/of.h> | ||
| 40 | #include <linux/of_mdio.h> | ||
| 41 | #include <linux/of_platform.h> | ||
| 42 | #include <linux/of_gpio.h> | ||
| 43 | #include <linux/of_net.h> | ||
| 44 | |||
| 45 | #include <linux/vmalloc.h> | ||
| 46 | #include <asm/pgtable.h> | ||
| 47 | #include <asm/irq.h> | ||
| 48 | #include <asm/uaccess.h> | ||
| 49 | |||
| 50 | #include "fs_enet.h" | ||
| 51 | |||
| 52 | /*************************************************/ | ||
| 53 | |||
| 54 | MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>"); | ||
| 55 | MODULE_DESCRIPTION("Freescale Ethernet Driver"); | ||
| 56 | MODULE_LICENSE("GPL"); | ||
| 57 | MODULE_VERSION(DRV_MODULE_VERSION); | ||
| 58 | |||
| 59 | static int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ | ||
| 60 | module_param(fs_enet_debug, int, 0); | ||
| 61 | MODULE_PARM_DESC(fs_enet_debug, | ||
| 62 | "Freescale bitmapped debugging message enable value"); | ||
| 63 | |||
| 64 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
| 65 | static void fs_enet_netpoll(struct net_device *dev); | ||
| 66 | #endif | ||
| 67 | |||
| 68 | static void fs_set_multicast_list(struct net_device *dev) | ||
| 69 | { | ||
| 70 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 71 | |||
| 72 | (*fep->ops->set_multicast_list)(dev); | ||
| 73 | } | ||
| 74 | |||
| 75 | static void skb_align(struct sk_buff *skb, int align) | ||
| 76 | { | ||
| 77 | int off = ((unsigned long)skb->data) & (align - 1); | ||
| 78 | |||
| 79 | if (off) | ||
| 80 | skb_reserve(skb, align - off); | ||
| 81 | } | ||
| 82 | |||
| 83 | /* NAPI receive function */ | ||
| 84 | static int fs_enet_rx_napi(struct napi_struct *napi, int budget) | ||
| 85 | { | ||
| 86 | struct fs_enet_private *fep = container_of(napi, struct fs_enet_private, napi); | ||
| 87 | struct net_device *dev = fep->ndev; | ||
| 88 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 89 | cbd_t __iomem *bdp; | ||
| 90 | struct sk_buff *skb, *skbn, *skbt; | ||
| 91 | int received = 0; | ||
| 92 | u16 pkt_len, sc; | ||
| 93 | int curidx; | ||
| 94 | |||
| 95 | /* | ||
| 96 | * First, grab all of the stats for the incoming packet. | ||
| 97 | * These get messed up if we get called due to a busy condition. | ||
| 98 | */ | ||
| 99 | bdp = fep->cur_rx; | ||
| 100 | |||
| 101 | /* clear RX status bits for napi*/ | ||
| 102 | (*fep->ops->napi_clear_rx_event)(dev); | ||
| 103 | |||
| 104 | while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { | ||
| 105 | curidx = bdp - fep->rx_bd_base; | ||
| 106 | |||
| 107 | /* | ||
| 108 | * Since we have allocated space to hold a complete frame, | ||
| 109 | * the last indicator should be set. | ||
| 110 | */ | ||
| 111 | if ((sc & BD_ENET_RX_LAST) == 0) | ||
| 112 | dev_warn(fep->dev, "rcv is not +last\n"); | ||
| 113 | |||
| 114 | /* | ||
| 115 | * Check for errors. | ||
| 116 | */ | ||
| 117 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | | ||
| 118 | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { | ||
| 119 | fep->stats.rx_errors++; | ||
| 120 | /* Frame too long or too short. */ | ||
| 121 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) | ||
| 122 | fep->stats.rx_length_errors++; | ||
| 123 | /* Frame alignment */ | ||
| 124 | if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) | ||
| 125 | fep->stats.rx_frame_errors++; | ||
| 126 | /* CRC Error */ | ||
| 127 | if (sc & BD_ENET_RX_CR) | ||
| 128 | fep->stats.rx_crc_errors++; | ||
| 129 | /* FIFO overrun */ | ||
| 130 | if (sc & BD_ENET_RX_OV) | ||
| 131 | fep->stats.rx_crc_errors++; | ||
| 132 | |||
| 133 | skb = fep->rx_skbuff[curidx]; | ||
| 134 | |||
| 135 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), | ||
| 136 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
| 137 | DMA_FROM_DEVICE); | ||
| 138 | |||
| 139 | skbn = skb; | ||
| 140 | |||
| 141 | } else { | ||
| 142 | skb = fep->rx_skbuff[curidx]; | ||
| 143 | |||
| 144 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), | ||
| 145 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
| 146 | DMA_FROM_DEVICE); | ||
| 147 | |||
| 148 | /* | ||
| 149 | * Process the incoming frame. | ||
| 150 | */ | ||
| 151 | fep->stats.rx_packets++; | ||
| 152 | pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ | ||
| 153 | fep->stats.rx_bytes += pkt_len + 4; | ||
| 154 | |||
| 155 | if (pkt_len <= fpi->rx_copybreak) { | ||
| 156 | /* +2 to make IP header L1 cache aligned */ | ||
| 157 | skbn = dev_alloc_skb(pkt_len + 2); | ||
| 158 | if (skbn != NULL) { | ||
| 159 | skb_reserve(skbn, 2); /* align IP header */ | ||
| 160 | skb_copy_from_linear_data(skb, | ||
| 161 | skbn->data, pkt_len); | ||
| 162 | /* swap */ | ||
| 163 | skbt = skb; | ||
| 164 | skb = skbn; | ||
| 165 | skbn = skbt; | ||
| 166 | } | ||
| 167 | } else { | ||
| 168 | skbn = dev_alloc_skb(ENET_RX_FRSIZE); | ||
| 169 | |||
| 170 | if (skbn) | ||
| 171 | skb_align(skbn, ENET_RX_ALIGN); | ||
| 172 | } | ||
| 173 | |||
| 174 | if (skbn != NULL) { | ||
| 175 | skb_put(skb, pkt_len); /* Make room */ | ||
| 176 | skb->protocol = eth_type_trans(skb, dev); | ||
| 177 | received++; | ||
| 178 | netif_receive_skb(skb); | ||
| 179 | } else { | ||
| 180 | dev_warn(fep->dev, | ||
| 181 | "Memory squeeze, dropping packet.\n"); | ||
| 182 | fep->stats.rx_dropped++; | ||
| 183 | skbn = skb; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 187 | fep->rx_skbuff[curidx] = skbn; | ||
| 188 | CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, | ||
| 189 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
| 190 | DMA_FROM_DEVICE)); | ||
| 191 | CBDW_DATLEN(bdp, 0); | ||
| 192 | CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); | ||
| 193 | |||
| 194 | /* | ||
| 195 | * Update BD pointer to next entry. | ||
| 196 | */ | ||
| 197 | if ((sc & BD_ENET_RX_WRAP) == 0) | ||
| 198 | bdp++; | ||
| 199 | else | ||
| 200 | bdp = fep->rx_bd_base; | ||
| 201 | |||
| 202 | (*fep->ops->rx_bd_done)(dev); | ||
| 203 | |||
| 204 | if (received >= budget) | ||
| 205 | break; | ||
| 206 | } | ||
| 207 | |||
| 208 | fep->cur_rx = bdp; | ||
| 209 | |||
| 210 | if (received < budget) { | ||
| 211 | /* done */ | ||
| 212 | napi_complete(napi); | ||
| 213 | (*fep->ops->napi_enable_rx)(dev); | ||
| 214 | } | ||
| 215 | return received; | ||
| 216 | } | ||
| 217 | |||
| 218 | /* non NAPI receive function */ | ||
| 219 | static int fs_enet_rx_non_napi(struct net_device *dev) | ||
| 220 | { | ||
| 221 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 222 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 223 | cbd_t __iomem *bdp; | ||
| 224 | struct sk_buff *skb, *skbn, *skbt; | ||
| 225 | int received = 0; | ||
| 226 | u16 pkt_len, sc; | ||
| 227 | int curidx; | ||
| 228 | /* | ||
| 229 | * First, grab all of the stats for the incoming packet. | ||
| 230 | * These get messed up if we get called due to a busy condition. | ||
| 231 | */ | ||
| 232 | bdp = fep->cur_rx; | ||
| 233 | |||
| 234 | while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { | ||
| 235 | |||
| 236 | curidx = bdp - fep->rx_bd_base; | ||
| 237 | |||
| 238 | /* | ||
| 239 | * Since we have allocated space to hold a complete frame, | ||
| 240 | * the last indicator should be set. | ||
| 241 | */ | ||
| 242 | if ((sc & BD_ENET_RX_LAST) == 0) | ||
| 243 | dev_warn(fep->dev, "rcv is not +last\n"); | ||
| 244 | |||
| 245 | /* | ||
| 246 | * Check for errors. | ||
| 247 | */ | ||
| 248 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | | ||
| 249 | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { | ||
| 250 | fep->stats.rx_errors++; | ||
| 251 | /* Frame too long or too short. */ | ||
| 252 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) | ||
| 253 | fep->stats.rx_length_errors++; | ||
| 254 | /* Frame alignment */ | ||
| 255 | if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) | ||
| 256 | fep->stats.rx_frame_errors++; | ||
| 257 | /* CRC Error */ | ||
| 258 | if (sc & BD_ENET_RX_CR) | ||
| 259 | fep->stats.rx_crc_errors++; | ||
| 260 | /* FIFO overrun */ | ||
| 261 | if (sc & BD_ENET_RX_OV) | ||
| 262 | fep->stats.rx_crc_errors++; | ||
| 263 | |||
| 264 | skb = fep->rx_skbuff[curidx]; | ||
| 265 | |||
| 266 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), | ||
| 267 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
| 268 | DMA_FROM_DEVICE); | ||
| 269 | |||
| 270 | skbn = skb; | ||
| 271 | |||
| 272 | } else { | ||
| 273 | |||
| 274 | skb = fep->rx_skbuff[curidx]; | ||
| 275 | |||
| 276 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), | ||
| 277 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
| 278 | DMA_FROM_DEVICE); | ||
| 279 | |||
| 280 | /* | ||
| 281 | * Process the incoming frame. | ||
| 282 | */ | ||
| 283 | fep->stats.rx_packets++; | ||
| 284 | pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ | ||
| 285 | fep->stats.rx_bytes += pkt_len + 4; | ||
| 286 | |||
| 287 | if (pkt_len <= fpi->rx_copybreak) { | ||
| 288 | /* +2 to make IP header L1 cache aligned */ | ||
| 289 | skbn = dev_alloc_skb(pkt_len + 2); | ||
| 290 | if (skbn != NULL) { | ||
| 291 | skb_reserve(skbn, 2); /* align IP header */ | ||
| 292 | skb_copy_from_linear_data(skb, | ||
| 293 | skbn->data, pkt_len); | ||
| 294 | /* swap */ | ||
| 295 | skbt = skb; | ||
| 296 | skb = skbn; | ||
| 297 | skbn = skbt; | ||
| 298 | } | ||
| 299 | } else { | ||
| 300 | skbn = dev_alloc_skb(ENET_RX_FRSIZE); | ||
| 301 | |||
| 302 | if (skbn) | ||
| 303 | skb_align(skbn, ENET_RX_ALIGN); | ||
| 304 | } | ||
| 305 | |||
| 306 | if (skbn != NULL) { | ||
| 307 | skb_put(skb, pkt_len); /* Make room */ | ||
| 308 | skb->protocol = eth_type_trans(skb, dev); | ||
| 309 | received++; | ||
| 310 | netif_rx(skb); | ||
| 311 | } else { | ||
| 312 | dev_warn(fep->dev, | ||
| 313 | "Memory squeeze, dropping packet.\n"); | ||
| 314 | fep->stats.rx_dropped++; | ||
| 315 | skbn = skb; | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | fep->rx_skbuff[curidx] = skbn; | ||
| 320 | CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, | ||
| 321 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
| 322 | DMA_FROM_DEVICE)); | ||
| 323 | CBDW_DATLEN(bdp, 0); | ||
| 324 | CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); | ||
| 325 | |||
| 326 | /* | ||
| 327 | * Update BD pointer to next entry. | ||
| 328 | */ | ||
| 329 | if ((sc & BD_ENET_RX_WRAP) == 0) | ||
| 330 | bdp++; | ||
| 331 | else | ||
| 332 | bdp = fep->rx_bd_base; | ||
| 333 | |||
| 334 | (*fep->ops->rx_bd_done)(dev); | ||
| 335 | } | ||
| 336 | |||
| 337 | fep->cur_rx = bdp; | ||
| 338 | |||
| 339 | return 0; | ||
| 340 | } | ||
| 341 | |||
| 342 | static void fs_enet_tx(struct net_device *dev) | ||
| 343 | { | ||
| 344 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 345 | cbd_t __iomem *bdp; | ||
| 346 | struct sk_buff *skb; | ||
| 347 | int dirtyidx, do_wake, do_restart; | ||
| 348 | u16 sc; | ||
| 349 | |||
| 350 | spin_lock(&fep->tx_lock); | ||
| 351 | bdp = fep->dirty_tx; | ||
| 352 | |||
| 353 | do_wake = do_restart = 0; | ||
| 354 | while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) { | ||
| 355 | dirtyidx = bdp - fep->tx_bd_base; | ||
| 356 | |||
| 357 | if (fep->tx_free == fep->tx_ring) | ||
| 358 | break; | ||
| 359 | |||
| 360 | skb = fep->tx_skbuff[dirtyidx]; | ||
| 361 | |||
| 362 | /* | ||
| 363 | * Check for errors. | ||
| 364 | */ | ||
| 365 | if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | | ||
| 366 | BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { | ||
| 367 | |||
| 368 | if (sc & BD_ENET_TX_HB) /* No heartbeat */ | ||
| 369 | fep->stats.tx_heartbeat_errors++; | ||
| 370 | if (sc & BD_ENET_TX_LC) /* Late collision */ | ||
| 371 | fep->stats.tx_window_errors++; | ||
| 372 | if (sc & BD_ENET_TX_RL) /* Retrans limit */ | ||
| 373 | fep->stats.tx_aborted_errors++; | ||
| 374 | if (sc & BD_ENET_TX_UN) /* Underrun */ | ||
| 375 | fep->stats.tx_fifo_errors++; | ||
| 376 | if (sc & BD_ENET_TX_CSL) /* Carrier lost */ | ||
| 377 | fep->stats.tx_carrier_errors++; | ||
| 378 | |||
| 379 | if (sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { | ||
| 380 | fep->stats.tx_errors++; | ||
| 381 | do_restart = 1; | ||
| 382 | } | ||
| 383 | } else | ||
| 384 | fep->stats.tx_packets++; | ||
| 385 | |||
| 386 | if (sc & BD_ENET_TX_READY) { | ||
| 387 | dev_warn(fep->dev, | ||
| 388 | "HEY! Enet xmit interrupt and TX_READY.\n"); | ||
| 389 | } | ||
| 390 | |||
| 391 | /* | ||
| 392 | * Deferred means some collisions occurred during transmit, | ||
| 393 | * but we eventually sent the packet OK. | ||
| 394 | */ | ||
| 395 | if (sc & BD_ENET_TX_DEF) | ||
| 396 | fep->stats.collisions++; | ||
| 397 | |||
| 398 | /* unmap */ | ||
| 399 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), | ||
| 400 | skb->len, DMA_TO_DEVICE); | ||
| 401 | |||
| 402 | /* | ||
| 403 | * Free the sk buffer associated with this last transmit. | ||
| 404 | */ | ||
| 405 | dev_kfree_skb_irq(skb); | ||
| 406 | fep->tx_skbuff[dirtyidx] = NULL; | ||
| 407 | |||
| 408 | /* | ||
| 409 | * Update pointer to next buffer descriptor to be transmitted. | ||
| 410 | */ | ||
| 411 | if ((sc & BD_ENET_TX_WRAP) == 0) | ||
| 412 | bdp++; | ||
| 413 | else | ||
| 414 | bdp = fep->tx_bd_base; | ||
| 415 | |||
| 416 | /* | ||
| 417 | * Since we have freed up a buffer, the ring is no longer | ||
| 418 | * full. | ||
| 419 | */ | ||
| 420 | if (!fep->tx_free++) | ||
| 421 | do_wake = 1; | ||
| 422 | } | ||
| 423 | |||
| 424 | fep->dirty_tx = bdp; | ||
| 425 | |||
| 426 | if (do_restart) | ||
| 427 | (*fep->ops->tx_restart)(dev); | ||
| 428 | |||
| 429 | spin_unlock(&fep->tx_lock); | ||
| 430 | |||
| 431 | if (do_wake) | ||
| 432 | netif_wake_queue(dev); | ||
| 433 | } | ||
| 434 | |||
| 435 | /* | ||
| 436 | * The interrupt handler. | ||
| 437 | * This is called from the MPC core interrupt. | ||
| 438 | */ | ||
| 439 | static irqreturn_t | ||
| 440 | fs_enet_interrupt(int irq, void *dev_id) | ||
| 441 | { | ||
| 442 | struct net_device *dev = dev_id; | ||
| 443 | struct fs_enet_private *fep; | ||
| 444 | const struct fs_platform_info *fpi; | ||
| 445 | u32 int_events; | ||
| 446 | u32 int_clr_events; | ||
| 447 | int nr, napi_ok; | ||
| 448 | int handled; | ||
| 449 | |||
| 450 | fep = netdev_priv(dev); | ||
| 451 | fpi = fep->fpi; | ||
| 452 | |||
| 453 | nr = 0; | ||
| 454 | while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) { | ||
| 455 | nr++; | ||
| 456 | |||
| 457 | int_clr_events = int_events; | ||
| 458 | if (fpi->use_napi) | ||
| 459 | int_clr_events &= ~fep->ev_napi_rx; | ||
| 460 | |||
| 461 | (*fep->ops->clear_int_events)(dev, int_clr_events); | ||
| 462 | |||
| 463 | if (int_events & fep->ev_err) | ||
| 464 | (*fep->ops->ev_error)(dev, int_events); | ||
| 465 | |||
| 466 | if (int_events & fep->ev_rx) { | ||
| 467 | if (!fpi->use_napi) | ||
| 468 | fs_enet_rx_non_napi(dev); | ||
| 469 | else { | ||
| 470 | napi_ok = napi_schedule_prep(&fep->napi); | ||
| 471 | |||
| 472 | (*fep->ops->napi_disable_rx)(dev); | ||
| 473 | (*fep->ops->clear_int_events)(dev, fep->ev_napi_rx); | ||
| 474 | |||
| 475 | /* NOTE: it is possible for FCCs in NAPI mode */ | ||
| 476 | /* to submit a spurious interrupt while in poll */ | ||
| 477 | if (napi_ok) | ||
| 478 | __napi_schedule(&fep->napi); | ||
| 479 | } | ||
| 480 | } | ||
| 481 | |||
| 482 | if (int_events & fep->ev_tx) | ||
| 483 | fs_enet_tx(dev); | ||
| 484 | } | ||
| 485 | |||
| 486 | handled = nr > 0; | ||
| 487 | return IRQ_RETVAL(handled); | ||
| 488 | } | ||
| 489 | |||
| 490 | void fs_init_bds(struct net_device *dev) | ||
| 491 | { | ||
| 492 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 493 | cbd_t __iomem *bdp; | ||
| 494 | struct sk_buff *skb; | ||
| 495 | int i; | ||
| 496 | |||
| 497 | fs_cleanup_bds(dev); | ||
| 498 | |||
| 499 | fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; | ||
| 500 | fep->tx_free = fep->tx_ring; | ||
| 501 | fep->cur_rx = fep->rx_bd_base; | ||
| 502 | |||
| 503 | /* | ||
| 504 | * Initialize the receive buffer descriptors. | ||
| 505 | */ | ||
| 506 | for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { | ||
| 507 | skb = dev_alloc_skb(ENET_RX_FRSIZE); | ||
| 508 | if (skb == NULL) { | ||
| 509 | dev_warn(fep->dev, | ||
| 510 | "Memory squeeze, unable to allocate skb\n"); | ||
| 511 | break; | ||
| 512 | } | ||
| 513 | skb_align(skb, ENET_RX_ALIGN); | ||
| 514 | fep->rx_skbuff[i] = skb; | ||
| 515 | CBDW_BUFADDR(bdp, | ||
| 516 | dma_map_single(fep->dev, skb->data, | ||
| 517 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
| 518 | DMA_FROM_DEVICE)); | ||
| 519 | CBDW_DATLEN(bdp, 0); /* zero */ | ||
| 520 | CBDW_SC(bdp, BD_ENET_RX_EMPTY | | ||
| 521 | ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP)); | ||
| 522 | } | ||
| 523 | /* | ||
| 524 | * if we failed, fillup remainder | ||
| 525 | */ | ||
| 526 | for (; i < fep->rx_ring; i++, bdp++) { | ||
| 527 | fep->rx_skbuff[i] = NULL; | ||
| 528 | CBDW_SC(bdp, (i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP); | ||
| 529 | } | ||
| 530 | |||
| 531 | /* | ||
| 532 | * ...and the same for transmit. | ||
| 533 | */ | ||
| 534 | for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { | ||
| 535 | fep->tx_skbuff[i] = NULL; | ||
| 536 | CBDW_BUFADDR(bdp, 0); | ||
| 537 | CBDW_DATLEN(bdp, 0); | ||
| 538 | CBDW_SC(bdp, (i < fep->tx_ring - 1) ? 0 : BD_SC_WRAP); | ||
| 539 | } | ||
| 540 | } | ||
| 541 | |||
| 542 | void fs_cleanup_bds(struct net_device *dev) | ||
| 543 | { | ||
| 544 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 545 | struct sk_buff *skb; | ||
| 546 | cbd_t __iomem *bdp; | ||
| 547 | int i; | ||
| 548 | |||
| 549 | /* | ||
| 550 | * Reset SKB transmit buffers. | ||
| 551 | */ | ||
| 552 | for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { | ||
| 553 | if ((skb = fep->tx_skbuff[i]) == NULL) | ||
| 554 | continue; | ||
| 555 | |||
| 556 | /* unmap */ | ||
| 557 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), | ||
| 558 | skb->len, DMA_TO_DEVICE); | ||
| 559 | |||
| 560 | fep->tx_skbuff[i] = NULL; | ||
| 561 | dev_kfree_skb(skb); | ||
| 562 | } | ||
| 563 | |||
| 564 | /* | ||
| 565 | * Reset SKB receive buffers | ||
| 566 | */ | ||
| 567 | for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { | ||
| 568 | if ((skb = fep->rx_skbuff[i]) == NULL) | ||
| 569 | continue; | ||
| 570 | |||
| 571 | /* unmap */ | ||
| 572 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), | ||
| 573 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
| 574 | DMA_FROM_DEVICE); | ||
| 575 | |||
| 576 | fep->rx_skbuff[i] = NULL; | ||
| 577 | |||
| 578 | dev_kfree_skb(skb); | ||
| 579 | } | ||
| 580 | } | ||
| 581 | |||
| 582 | /**********************************************************************************/ | ||
| 583 | |||
| 584 | #ifdef CONFIG_FS_ENET_MPC5121_FEC | ||
| 585 | /* | ||
| 586 | * MPC5121 FEC requeries 4-byte alignment for TX data buffer! | ||
| 587 | */ | ||
| 588 | static struct sk_buff *tx_skb_align_workaround(struct net_device *dev, | ||
| 589 | struct sk_buff *skb) | ||
| 590 | { | ||
| 591 | struct sk_buff *new_skb; | ||
| 592 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 593 | |||
| 594 | /* Alloc new skb */ | ||
| 595 | new_skb = dev_alloc_skb(skb->len + 4); | ||
| 596 | if (!new_skb) { | ||
| 597 | if (net_ratelimit()) { | ||
| 598 | dev_warn(fep->dev, | ||
| 599 | "Memory squeeze, dropping tx packet.\n"); | ||
| 600 | } | ||
| 601 | return NULL; | ||
| 602 | } | ||
| 603 | |||
| 604 | /* Make sure new skb is properly aligned */ | ||
| 605 | skb_align(new_skb, 4); | ||
| 606 | |||
| 607 | /* Copy data to new skb ... */ | ||
| 608 | skb_copy_from_linear_data(skb, new_skb->data, skb->len); | ||
| 609 | skb_put(new_skb, skb->len); | ||
| 610 | |||
| 611 | /* ... and free an old one */ | ||
| 612 | dev_kfree_skb_any(skb); | ||
| 613 | |||
| 614 | return new_skb; | ||
| 615 | } | ||
| 616 | #endif | ||
| 617 | |||
| 618 | static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
| 619 | { | ||
| 620 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 621 | cbd_t __iomem *bdp; | ||
| 622 | int curidx; | ||
| 623 | u16 sc; | ||
| 624 | unsigned long flags; | ||
| 625 | |||
| 626 | #ifdef CONFIG_FS_ENET_MPC5121_FEC | ||
| 627 | if (((unsigned long)skb->data) & 0x3) { | ||
| 628 | skb = tx_skb_align_workaround(dev, skb); | ||
| 629 | if (!skb) { | ||
| 630 | /* | ||
| 631 | * We have lost packet due to memory allocation error | ||
| 632 | * in tx_skb_align_workaround(). Hopefully original | ||
| 633 | * skb is still valid, so try transmit it later. | ||
| 634 | */ | ||
| 635 | return NETDEV_TX_BUSY; | ||
| 636 | } | ||
| 637 | } | ||
| 638 | #endif | ||
| 639 | spin_lock_irqsave(&fep->tx_lock, flags); | ||
| 640 | |||
| 641 | /* | ||
| 642 | * Fill in a Tx ring entry | ||
| 643 | */ | ||
| 644 | bdp = fep->cur_tx; | ||
| 645 | |||
| 646 | if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { | ||
| 647 | netif_stop_queue(dev); | ||
| 648 | spin_unlock_irqrestore(&fep->tx_lock, flags); | ||
| 649 | |||
| 650 | /* | ||
| 651 | * Ooops. All transmit buffers are full. Bail out. | ||
| 652 | * This should not happen, since the tx queue should be stopped. | ||
| 653 | */ | ||
| 654 | dev_warn(fep->dev, "tx queue full!.\n"); | ||
| 655 | return NETDEV_TX_BUSY; | ||
| 656 | } | ||
| 657 | |||
| 658 | curidx = bdp - fep->tx_bd_base; | ||
| 659 | /* | ||
| 660 | * Clear all of the status flags. | ||
| 661 | */ | ||
| 662 | CBDC_SC(bdp, BD_ENET_TX_STATS); | ||
| 663 | |||
| 664 | /* | ||
| 665 | * Save skb pointer. | ||
| 666 | */ | ||
| 667 | fep->tx_skbuff[curidx] = skb; | ||
| 668 | |||
| 669 | fep->stats.tx_bytes += skb->len; | ||
| 670 | |||
| 671 | /* | ||
| 672 | * Push the data cache so the CPM does not get stale memory data. | ||
| 673 | */ | ||
| 674 | CBDW_BUFADDR(bdp, dma_map_single(fep->dev, | ||
| 675 | skb->data, skb->len, DMA_TO_DEVICE)); | ||
| 676 | CBDW_DATLEN(bdp, skb->len); | ||
| 677 | |||
| 678 | /* | ||
| 679 | * If this was the last BD in the ring, start at the beginning again. | ||
| 680 | */ | ||
| 681 | if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) | ||
| 682 | fep->cur_tx++; | ||
| 683 | else | ||
| 684 | fep->cur_tx = fep->tx_bd_base; | ||
| 685 | |||
| 686 | if (!--fep->tx_free) | ||
| 687 | netif_stop_queue(dev); | ||
| 688 | |||
| 689 | /* Trigger transmission start */ | ||
| 690 | sc = BD_ENET_TX_READY | BD_ENET_TX_INTR | | ||
| 691 | BD_ENET_TX_LAST | BD_ENET_TX_TC; | ||
| 692 | |||
| 693 | /* note that while FEC does not have this bit | ||
| 694 | * it marks it as available for software use | ||
| 695 | * yay for hw reuse :) */ | ||
| 696 | if (skb->len <= 60) | ||
| 697 | sc |= BD_ENET_TX_PAD; | ||
| 698 | CBDS_SC(bdp, sc); | ||
| 699 | |||
| 700 | skb_tx_timestamp(skb); | ||
| 701 | |||
| 702 | (*fep->ops->tx_kickstart)(dev); | ||
| 703 | |||
| 704 | spin_unlock_irqrestore(&fep->tx_lock, flags); | ||
| 705 | |||
| 706 | return NETDEV_TX_OK; | ||
| 707 | } | ||
| 708 | |||
| 709 | static void fs_timeout(struct net_device *dev) | ||
| 710 | { | ||
| 711 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 712 | unsigned long flags; | ||
| 713 | int wake = 0; | ||
| 714 | |||
| 715 | fep->stats.tx_errors++; | ||
| 716 | |||
| 717 | spin_lock_irqsave(&fep->lock, flags); | ||
| 718 | |||
| 719 | if (dev->flags & IFF_UP) { | ||
| 720 | phy_stop(fep->phydev); | ||
| 721 | (*fep->ops->stop)(dev); | ||
| 722 | (*fep->ops->restart)(dev); | ||
| 723 | phy_start(fep->phydev); | ||
| 724 | } | ||
| 725 | |||
| 726 | phy_start(fep->phydev); | ||
| 727 | wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); | ||
| 728 | spin_unlock_irqrestore(&fep->lock, flags); | ||
| 729 | |||
| 730 | if (wake) | ||
| 731 | netif_wake_queue(dev); | ||
| 732 | } | ||
| 733 | |||
| 734 | /*----------------------------------------------------------------------------- | ||
| 735 | * generic link-change handler - should be sufficient for most cases | ||
| 736 | *-----------------------------------------------------------------------------*/ | ||
| 737 | static void generic_adjust_link(struct net_device *dev) | ||
| 738 | { | ||
| 739 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 740 | struct phy_device *phydev = fep->phydev; | ||
| 741 | int new_state = 0; | ||
| 742 | |||
| 743 | if (phydev->link) { | ||
| 744 | /* adjust to duplex mode */ | ||
| 745 | if (phydev->duplex != fep->oldduplex) { | ||
| 746 | new_state = 1; | ||
| 747 | fep->oldduplex = phydev->duplex; | ||
| 748 | } | ||
| 749 | |||
| 750 | if (phydev->speed != fep->oldspeed) { | ||
| 751 | new_state = 1; | ||
| 752 | fep->oldspeed = phydev->speed; | ||
| 753 | } | ||
| 754 | |||
| 755 | if (!fep->oldlink) { | ||
| 756 | new_state = 1; | ||
| 757 | fep->oldlink = 1; | ||
| 758 | } | ||
| 759 | |||
| 760 | if (new_state) | ||
| 761 | fep->ops->restart(dev); | ||
| 762 | } else if (fep->oldlink) { | ||
| 763 | new_state = 1; | ||
| 764 | fep->oldlink = 0; | ||
| 765 | fep->oldspeed = 0; | ||
| 766 | fep->oldduplex = -1; | ||
| 767 | } | ||
| 768 | |||
| 769 | if (new_state && netif_msg_link(fep)) | ||
| 770 | phy_print_status(phydev); | ||
| 771 | } | ||
| 772 | |||
| 773 | |||
| 774 | static void fs_adjust_link(struct net_device *dev) | ||
| 775 | { | ||
| 776 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 777 | unsigned long flags; | ||
| 778 | |||
| 779 | spin_lock_irqsave(&fep->lock, flags); | ||
| 780 | |||
| 781 | if(fep->ops->adjust_link) | ||
| 782 | fep->ops->adjust_link(dev); | ||
| 783 | else | ||
| 784 | generic_adjust_link(dev); | ||
| 785 | |||
| 786 | spin_unlock_irqrestore(&fep->lock, flags); | ||
| 787 | } | ||
| 788 | |||
| 789 | static int fs_init_phy(struct net_device *dev) | ||
| 790 | { | ||
| 791 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 792 | struct phy_device *phydev; | ||
| 793 | |||
| 794 | fep->oldlink = 0; | ||
| 795 | fep->oldspeed = 0; | ||
| 796 | fep->oldduplex = -1; | ||
| 797 | |||
| 798 | phydev = of_phy_connect(dev, fep->fpi->phy_node, &fs_adjust_link, 0, | ||
| 799 | PHY_INTERFACE_MODE_MII); | ||
| 800 | if (!phydev) { | ||
| 801 | phydev = of_phy_connect_fixed_link(dev, &fs_adjust_link, | ||
| 802 | PHY_INTERFACE_MODE_MII); | ||
| 803 | } | ||
| 804 | if (!phydev) { | ||
| 805 | dev_err(&dev->dev, "Could not attach to PHY\n"); | ||
| 806 | return -ENODEV; | ||
| 807 | } | ||
| 808 | |||
| 809 | fep->phydev = phydev; | ||
| 810 | |||
| 811 | return 0; | ||
| 812 | } | ||
| 813 | |||
| 814 | static int fs_enet_open(struct net_device *dev) | ||
| 815 | { | ||
| 816 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 817 | int r; | ||
| 818 | int err; | ||
| 819 | |||
| 820 | /* to initialize the fep->cur_rx,... */ | ||
| 821 | /* not doing this, will cause a crash in fs_enet_rx_napi */ | ||
| 822 | fs_init_bds(fep->ndev); | ||
| 823 | |||
| 824 | if (fep->fpi->use_napi) | ||
| 825 | napi_enable(&fep->napi); | ||
| 826 | |||
| 827 | /* Install our interrupt handler. */ | ||
| 828 | r = request_irq(fep->interrupt, fs_enet_interrupt, IRQF_SHARED, | ||
| 829 | "fs_enet-mac", dev); | ||
| 830 | if (r != 0) { | ||
| 831 | dev_err(fep->dev, "Could not allocate FS_ENET IRQ!"); | ||
| 832 | if (fep->fpi->use_napi) | ||
| 833 | napi_disable(&fep->napi); | ||
| 834 | return -EINVAL; | ||
| 835 | } | ||
| 836 | |||
| 837 | err = fs_init_phy(dev); | ||
| 838 | if (err) { | ||
| 839 | free_irq(fep->interrupt, dev); | ||
| 840 | if (fep->fpi->use_napi) | ||
| 841 | napi_disable(&fep->napi); | ||
| 842 | return err; | ||
| 843 | } | ||
| 844 | phy_start(fep->phydev); | ||
| 845 | |||
| 846 | netif_start_queue(dev); | ||
| 847 | |||
| 848 | return 0; | ||
| 849 | } | ||
| 850 | |||
| 851 | static int fs_enet_close(struct net_device *dev) | ||
| 852 | { | ||
| 853 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 854 | unsigned long flags; | ||
| 855 | |||
| 856 | netif_stop_queue(dev); | ||
| 857 | netif_carrier_off(dev); | ||
| 858 | if (fep->fpi->use_napi) | ||
| 859 | napi_disable(&fep->napi); | ||
| 860 | phy_stop(fep->phydev); | ||
| 861 | |||
| 862 | spin_lock_irqsave(&fep->lock, flags); | ||
| 863 | spin_lock(&fep->tx_lock); | ||
| 864 | (*fep->ops->stop)(dev); | ||
| 865 | spin_unlock(&fep->tx_lock); | ||
| 866 | spin_unlock_irqrestore(&fep->lock, flags); | ||
| 867 | |||
| 868 | /* release any irqs */ | ||
| 869 | phy_disconnect(fep->phydev); | ||
| 870 | fep->phydev = NULL; | ||
| 871 | free_irq(fep->interrupt, dev); | ||
| 872 | |||
| 873 | return 0; | ||
| 874 | } | ||
| 875 | |||
| 876 | static struct net_device_stats *fs_enet_get_stats(struct net_device *dev) | ||
| 877 | { | ||
| 878 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 879 | return &fep->stats; | ||
| 880 | } | ||
| 881 | |||
| 882 | /*************************************************************************/ | ||
| 883 | |||
| 884 | static void fs_get_drvinfo(struct net_device *dev, | ||
| 885 | struct ethtool_drvinfo *info) | ||
| 886 | { | ||
| 887 | strcpy(info->driver, DRV_MODULE_NAME); | ||
| 888 | strcpy(info->version, DRV_MODULE_VERSION); | ||
| 889 | } | ||
| 890 | |||
| 891 | static int fs_get_regs_len(struct net_device *dev) | ||
| 892 | { | ||
| 893 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 894 | |||
| 895 | return (*fep->ops->get_regs_len)(dev); | ||
| 896 | } | ||
| 897 | |||
| 898 | static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs, | ||
| 899 | void *p) | ||
| 900 | { | ||
| 901 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 902 | unsigned long flags; | ||
| 903 | int r, len; | ||
| 904 | |||
| 905 | len = regs->len; | ||
| 906 | |||
| 907 | spin_lock_irqsave(&fep->lock, flags); | ||
| 908 | r = (*fep->ops->get_regs)(dev, p, &len); | ||
| 909 | spin_unlock_irqrestore(&fep->lock, flags); | ||
| 910 | |||
| 911 | if (r == 0) | ||
| 912 | regs->version = 0; | ||
| 913 | } | ||
| 914 | |||
| 915 | static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
| 916 | { | ||
| 917 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 918 | |||
| 919 | if (!fep->phydev) | ||
| 920 | return -ENODEV; | ||
| 921 | |||
| 922 | return phy_ethtool_gset(fep->phydev, cmd); | ||
| 923 | } | ||
| 924 | |||
| 925 | static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
| 926 | { | ||
| 927 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 928 | |||
| 929 | if (!fep->phydev) | ||
| 930 | return -ENODEV; | ||
| 931 | |||
| 932 | return phy_ethtool_sset(fep->phydev, cmd); | ||
| 933 | } | ||
| 934 | |||
| 935 | static int fs_nway_reset(struct net_device *dev) | ||
| 936 | { | ||
| 937 | return 0; | ||
| 938 | } | ||
| 939 | |||
| 940 | static u32 fs_get_msglevel(struct net_device *dev) | ||
| 941 | { | ||
| 942 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 943 | return fep->msg_enable; | ||
| 944 | } | ||
| 945 | |||
| 946 | static void fs_set_msglevel(struct net_device *dev, u32 value) | ||
| 947 | { | ||
| 948 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 949 | fep->msg_enable = value; | ||
| 950 | } | ||
| 951 | |||
| 952 | static const struct ethtool_ops fs_ethtool_ops = { | ||
| 953 | .get_drvinfo = fs_get_drvinfo, | ||
| 954 | .get_regs_len = fs_get_regs_len, | ||
| 955 | .get_settings = fs_get_settings, | ||
| 956 | .set_settings = fs_set_settings, | ||
| 957 | .nway_reset = fs_nway_reset, | ||
| 958 | .get_link = ethtool_op_get_link, | ||
| 959 | .get_msglevel = fs_get_msglevel, | ||
| 960 | .set_msglevel = fs_set_msglevel, | ||
| 961 | .get_regs = fs_get_regs, | ||
| 962 | }; | ||
| 963 | |||
| 964 | static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | ||
| 965 | { | ||
| 966 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 967 | |||
| 968 | if (!netif_running(dev)) | ||
| 969 | return -EINVAL; | ||
| 970 | |||
| 971 | return phy_mii_ioctl(fep->phydev, rq, cmd); | ||
| 972 | } | ||
| 973 | |||
| 974 | extern int fs_mii_connect(struct net_device *dev); | ||
| 975 | extern void fs_mii_disconnect(struct net_device *dev); | ||
| 976 | |||
| 977 | /**************************************************************************************/ | ||
| 978 | |||
| 979 | #ifdef CONFIG_FS_ENET_HAS_FEC | ||
| 980 | #define IS_FEC(match) ((match)->data == &fs_fec_ops) | ||
| 981 | #else | ||
| 982 | #define IS_FEC(match) 0 | ||
| 983 | #endif | ||
| 984 | |||
| 985 | static const struct net_device_ops fs_enet_netdev_ops = { | ||
| 986 | .ndo_open = fs_enet_open, | ||
| 987 | .ndo_stop = fs_enet_close, | ||
| 988 | .ndo_get_stats = fs_enet_get_stats, | ||
| 989 | .ndo_start_xmit = fs_enet_start_xmit, | ||
| 990 | .ndo_tx_timeout = fs_timeout, | ||
| 991 | .ndo_set_multicast_list = fs_set_multicast_list, | ||
| 992 | .ndo_do_ioctl = fs_ioctl, | ||
| 993 | .ndo_validate_addr = eth_validate_addr, | ||
| 994 | .ndo_set_mac_address = eth_mac_addr, | ||
| 995 | .ndo_change_mtu = eth_change_mtu, | ||
| 996 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
| 997 | .ndo_poll_controller = fs_enet_netpoll, | ||
| 998 | #endif | ||
| 999 | }; | ||
| 1000 | |||
| 1001 | static struct of_device_id fs_enet_match[]; | ||
| 1002 | static int __devinit fs_enet_probe(struct platform_device *ofdev) | ||
| 1003 | { | ||
| 1004 | const struct of_device_id *match; | ||
| 1005 | struct net_device *ndev; | ||
| 1006 | struct fs_enet_private *fep; | ||
| 1007 | struct fs_platform_info *fpi; | ||
| 1008 | const u32 *data; | ||
| 1009 | const u8 *mac_addr; | ||
| 1010 | int privsize, len, ret = -ENODEV; | ||
| 1011 | |||
| 1012 | match = of_match_device(fs_enet_match, &ofdev->dev); | ||
| 1013 | if (!match) | ||
| 1014 | return -EINVAL; | ||
| 1015 | |||
| 1016 | fpi = kzalloc(sizeof(*fpi), GFP_KERNEL); | ||
| 1017 | if (!fpi) | ||
| 1018 | return -ENOMEM; | ||
| 1019 | |||
| 1020 | if (!IS_FEC(match)) { | ||
| 1021 | data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len); | ||
| 1022 | if (!data || len != 4) | ||
| 1023 | goto out_free_fpi; | ||
| 1024 | |||
| 1025 | fpi->cp_command = *data; | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | fpi->rx_ring = 32; | ||
| 1029 | fpi->tx_ring = 32; | ||
| 1030 | fpi->rx_copybreak = 240; | ||
| 1031 | fpi->use_napi = 1; | ||
| 1032 | fpi->napi_weight = 17; | ||
| 1033 | fpi->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0); | ||
| 1034 | if ((!fpi->phy_node) && (!of_get_property(ofdev->dev.of_node, "fixed-link", | ||
| 1035 | NULL))) | ||
| 1036 | goto out_free_fpi; | ||
| 1037 | |||
| 1038 | privsize = sizeof(*fep) + | ||
| 1039 | sizeof(struct sk_buff **) * | ||
| 1040 | (fpi->rx_ring + fpi->tx_ring); | ||
| 1041 | |||
| 1042 | ndev = alloc_etherdev(privsize); | ||
| 1043 | if (!ndev) { | ||
| 1044 | ret = -ENOMEM; | ||
| 1045 | goto out_put; | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | SET_NETDEV_DEV(ndev, &ofdev->dev); | ||
| 1049 | dev_set_drvdata(&ofdev->dev, ndev); | ||
| 1050 | |||
| 1051 | fep = netdev_priv(ndev); | ||
| 1052 | fep->dev = &ofdev->dev; | ||
| 1053 | fep->ndev = ndev; | ||
| 1054 | fep->fpi = fpi; | ||
| 1055 | fep->ops = match->data; | ||
| 1056 | |||
| 1057 | ret = fep->ops->setup_data(ndev); | ||
| 1058 | if (ret) | ||
| 1059 | goto out_free_dev; | ||
| 1060 | |||
| 1061 | fep->rx_skbuff = (struct sk_buff **)&fep[1]; | ||
| 1062 | fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; | ||
| 1063 | |||
| 1064 | spin_lock_init(&fep->lock); | ||
| 1065 | spin_lock_init(&fep->tx_lock); | ||
| 1066 | |||
| 1067 | mac_addr = of_get_mac_address(ofdev->dev.of_node); | ||
| 1068 | if (mac_addr) | ||
| 1069 | memcpy(ndev->dev_addr, mac_addr, 6); | ||
| 1070 | |||
| 1071 | ret = fep->ops->allocate_bd(ndev); | ||
| 1072 | if (ret) | ||
| 1073 | goto out_cleanup_data; | ||
| 1074 | |||
| 1075 | fep->rx_bd_base = fep->ring_base; | ||
| 1076 | fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring; | ||
| 1077 | |||
| 1078 | fep->tx_ring = fpi->tx_ring; | ||
| 1079 | fep->rx_ring = fpi->rx_ring; | ||
| 1080 | |||
| 1081 | ndev->netdev_ops = &fs_enet_netdev_ops; | ||
| 1082 | ndev->watchdog_timeo = 2 * HZ; | ||
| 1083 | if (fpi->use_napi) | ||
| 1084 | netif_napi_add(ndev, &fep->napi, fs_enet_rx_napi, | ||
| 1085 | fpi->napi_weight); | ||
| 1086 | |||
| 1087 | ndev->ethtool_ops = &fs_ethtool_ops; | ||
| 1088 | |||
| 1089 | init_timer(&fep->phy_timer_list); | ||
| 1090 | |||
| 1091 | netif_carrier_off(ndev); | ||
| 1092 | |||
| 1093 | ret = register_netdev(ndev); | ||
| 1094 | if (ret) | ||
| 1095 | goto out_free_bd; | ||
| 1096 | |||
| 1097 | pr_info("%s: fs_enet: %pM\n", ndev->name, ndev->dev_addr); | ||
| 1098 | |||
| 1099 | return 0; | ||
| 1100 | |||
| 1101 | out_free_bd: | ||
| 1102 | fep->ops->free_bd(ndev); | ||
| 1103 | out_cleanup_data: | ||
| 1104 | fep->ops->cleanup_data(ndev); | ||
| 1105 | out_free_dev: | ||
| 1106 | free_netdev(ndev); | ||
| 1107 | dev_set_drvdata(&ofdev->dev, NULL); | ||
| 1108 | out_put: | ||
| 1109 | of_node_put(fpi->phy_node); | ||
| 1110 | out_free_fpi: | ||
| 1111 | kfree(fpi); | ||
| 1112 | return ret; | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | static int fs_enet_remove(struct platform_device *ofdev) | ||
| 1116 | { | ||
| 1117 | struct net_device *ndev = dev_get_drvdata(&ofdev->dev); | ||
| 1118 | struct fs_enet_private *fep = netdev_priv(ndev); | ||
| 1119 | |||
| 1120 | unregister_netdev(ndev); | ||
| 1121 | |||
| 1122 | fep->ops->free_bd(ndev); | ||
| 1123 | fep->ops->cleanup_data(ndev); | ||
| 1124 | dev_set_drvdata(fep->dev, NULL); | ||
| 1125 | of_node_put(fep->fpi->phy_node); | ||
| 1126 | free_netdev(ndev); | ||
| 1127 | return 0; | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | static struct of_device_id fs_enet_match[] = { | ||
| 1131 | #ifdef CONFIG_FS_ENET_HAS_SCC | ||
| 1132 | { | ||
| 1133 | .compatible = "fsl,cpm1-scc-enet", | ||
| 1134 | .data = (void *)&fs_scc_ops, | ||
| 1135 | }, | ||
| 1136 | { | ||
| 1137 | .compatible = "fsl,cpm2-scc-enet", | ||
| 1138 | .data = (void *)&fs_scc_ops, | ||
| 1139 | }, | ||
| 1140 | #endif | ||
| 1141 | #ifdef CONFIG_FS_ENET_HAS_FCC | ||
| 1142 | { | ||
| 1143 | .compatible = "fsl,cpm2-fcc-enet", | ||
| 1144 | .data = (void *)&fs_fcc_ops, | ||
| 1145 | }, | ||
| 1146 | #endif | ||
| 1147 | #ifdef CONFIG_FS_ENET_HAS_FEC | ||
| 1148 | #ifdef CONFIG_FS_ENET_MPC5121_FEC | ||
| 1149 | { | ||
| 1150 | .compatible = "fsl,mpc5121-fec", | ||
| 1151 | .data = (void *)&fs_fec_ops, | ||
| 1152 | }, | ||
| 1153 | #else | ||
| 1154 | { | ||
| 1155 | .compatible = "fsl,pq1-fec-enet", | ||
| 1156 | .data = (void *)&fs_fec_ops, | ||
| 1157 | }, | ||
| 1158 | #endif | ||
| 1159 | #endif | ||
| 1160 | {} | ||
| 1161 | }; | ||
| 1162 | MODULE_DEVICE_TABLE(of, fs_enet_match); | ||
| 1163 | |||
| 1164 | static struct platform_driver fs_enet_driver = { | ||
| 1165 | .driver = { | ||
| 1166 | .owner = THIS_MODULE, | ||
| 1167 | .name = "fs_enet", | ||
| 1168 | .of_match_table = fs_enet_match, | ||
| 1169 | }, | ||
| 1170 | .probe = fs_enet_probe, | ||
| 1171 | .remove = fs_enet_remove, | ||
| 1172 | }; | ||
| 1173 | |||
| 1174 | static int __init fs_init(void) | ||
| 1175 | { | ||
| 1176 | return platform_driver_register(&fs_enet_driver); | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | static void __exit fs_cleanup(void) | ||
| 1180 | { | ||
| 1181 | platform_driver_unregister(&fs_enet_driver); | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
| 1185 | static void fs_enet_netpoll(struct net_device *dev) | ||
| 1186 | { | ||
| 1187 | disable_irq(dev->irq); | ||
| 1188 | fs_enet_interrupt(dev->irq, dev); | ||
| 1189 | enable_irq(dev->irq); | ||
| 1190 | } | ||
| 1191 | #endif | ||
| 1192 | |||
| 1193 | /**************************************************************************************/ | ||
| 1194 | |||
| 1195 | module_init(fs_init); | ||
| 1196 | module_exit(fs_cleanup); | ||
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h new file mode 100644 index 00000000000..1ece4b1a689 --- /dev/null +++ b/drivers/net/fs_enet/fs_enet.h | |||
| @@ -0,0 +1,244 @@ | |||
| 1 | #ifndef FS_ENET_H | ||
| 2 | #define FS_ENET_H | ||
| 3 | |||
| 4 | #include <linux/mii.h> | ||
| 5 | #include <linux/netdevice.h> | ||
| 6 | #include <linux/types.h> | ||
| 7 | #include <linux/list.h> | ||
| 8 | #include <linux/phy.h> | ||
| 9 | #include <linux/dma-mapping.h> | ||
| 10 | |||
| 11 | #include <linux/fs_enet_pd.h> | ||
| 12 | #include <asm/fs_pd.h> | ||
| 13 | |||
| 14 | #ifdef CONFIG_CPM1 | ||
| 15 | #include <asm/cpm1.h> | ||
| 16 | #endif | ||
| 17 | |||
| 18 | #if defined(CONFIG_FS_ENET_HAS_FEC) | ||
| 19 | #include <asm/cpm.h> | ||
| 20 | |||
| 21 | #if defined(CONFIG_FS_ENET_MPC5121_FEC) | ||
| 22 | /* MPC5121 FEC has different register layout */ | ||
| 23 | struct fec { | ||
| 24 | u32 fec_reserved0; | ||
| 25 | u32 fec_ievent; /* Interrupt event reg */ | ||
| 26 | u32 fec_imask; /* Interrupt mask reg */ | ||
| 27 | u32 fec_reserved1; | ||
| 28 | u32 fec_r_des_active; /* Receive descriptor reg */ | ||
| 29 | u32 fec_x_des_active; /* Transmit descriptor reg */ | ||
| 30 | u32 fec_reserved2[3]; | ||
| 31 | u32 fec_ecntrl; /* Ethernet control reg */ | ||
| 32 | u32 fec_reserved3[6]; | ||
| 33 | u32 fec_mii_data; /* MII manage frame reg */ | ||
| 34 | u32 fec_mii_speed; /* MII speed control reg */ | ||
| 35 | u32 fec_reserved4[7]; | ||
| 36 | u32 fec_mib_ctrlstat; /* MIB control/status reg */ | ||
| 37 | u32 fec_reserved5[7]; | ||
| 38 | u32 fec_r_cntrl; /* Receive control reg */ | ||
| 39 | u32 fec_reserved6[15]; | ||
| 40 | u32 fec_x_cntrl; /* Transmit Control reg */ | ||
| 41 | u32 fec_reserved7[7]; | ||
| 42 | u32 fec_addr_low; /* Low 32bits MAC address */ | ||
| 43 | u32 fec_addr_high; /* High 16bits MAC address */ | ||
| 44 | u32 fec_opd; /* Opcode + Pause duration */ | ||
| 45 | u32 fec_reserved8[10]; | ||
| 46 | u32 fec_hash_table_high; /* High 32bits hash table */ | ||
| 47 | u32 fec_hash_table_low; /* Low 32bits hash table */ | ||
| 48 | u32 fec_grp_hash_table_high; /* High 32bits hash table */ | ||
| 49 | u32 fec_grp_hash_table_low; /* Low 32bits hash table */ | ||
| 50 | u32 fec_reserved9[7]; | ||
| 51 | u32 fec_x_wmrk; /* FIFO transmit water mark */ | ||
| 52 | u32 fec_reserved10; | ||
| 53 | u32 fec_r_bound; /* FIFO receive bound reg */ | ||
| 54 | u32 fec_r_fstart; /* FIFO receive start reg */ | ||
| 55 | u32 fec_reserved11[11]; | ||
| 56 | u32 fec_r_des_start; /* Receive descriptor ring */ | ||
| 57 | u32 fec_x_des_start; /* Transmit descriptor ring */ | ||
| 58 | u32 fec_r_buff_size; /* Maximum receive buff size */ | ||
| 59 | u32 fec_reserved12[26]; | ||
| 60 | u32 fec_dma_control; /* DMA Endian and other ctrl */ | ||
| 61 | }; | ||
| 62 | #endif | ||
| 63 | |||
| 64 | struct fec_info { | ||
| 65 | struct fec __iomem *fecp; | ||
| 66 | u32 mii_speed; | ||
| 67 | }; | ||
| 68 | #endif | ||
| 69 | |||
| 70 | #ifdef CONFIG_CPM2 | ||
| 71 | #include <asm/cpm2.h> | ||
| 72 | #endif | ||
| 73 | |||
| 74 | /* hw driver ops */ | ||
| 75 | struct fs_ops { | ||
| 76 | int (*setup_data)(struct net_device *dev); | ||
| 77 | int (*allocate_bd)(struct net_device *dev); | ||
| 78 | void (*free_bd)(struct net_device *dev); | ||
| 79 | void (*cleanup_data)(struct net_device *dev); | ||
| 80 | void (*set_multicast_list)(struct net_device *dev); | ||
| 81 | void (*adjust_link)(struct net_device *dev); | ||
| 82 | void (*restart)(struct net_device *dev); | ||
| 83 | void (*stop)(struct net_device *dev); | ||
| 84 | void (*napi_clear_rx_event)(struct net_device *dev); | ||
| 85 | void (*napi_enable_rx)(struct net_device *dev); | ||
| 86 | void (*napi_disable_rx)(struct net_device *dev); | ||
| 87 | void (*rx_bd_done)(struct net_device *dev); | ||
| 88 | void (*tx_kickstart)(struct net_device *dev); | ||
| 89 | u32 (*get_int_events)(struct net_device *dev); | ||
| 90 | void (*clear_int_events)(struct net_device *dev, u32 int_events); | ||
| 91 | void (*ev_error)(struct net_device *dev, u32 int_events); | ||
| 92 | int (*get_regs)(struct net_device *dev, void *p, int *sizep); | ||
| 93 | int (*get_regs_len)(struct net_device *dev); | ||
| 94 | void (*tx_restart)(struct net_device *dev); | ||
| 95 | }; | ||
| 96 | |||
| 97 | struct phy_info { | ||
| 98 | unsigned int id; | ||
| 99 | const char *name; | ||
| 100 | void (*startup) (struct net_device * dev); | ||
| 101 | void (*shutdown) (struct net_device * dev); | ||
| 102 | void (*ack_int) (struct net_device * dev); | ||
| 103 | }; | ||
| 104 | |||
| 105 | /* The FEC stores dest/src/type, data, and checksum for receive packets. | ||
| 106 | */ | ||
| 107 | #define MAX_MTU 1508 /* Allow fullsized pppoe packets over VLAN */ | ||
| 108 | #define MIN_MTU 46 /* this is data size */ | ||
| 109 | #define CRC_LEN 4 | ||
| 110 | |||
| 111 | #define PKT_MAXBUF_SIZE (MAX_MTU+ETH_HLEN+CRC_LEN) | ||
| 112 | #define PKT_MINBUF_SIZE (MIN_MTU+ETH_HLEN+CRC_LEN) | ||
| 113 | |||
| 114 | /* Must be a multiple of 32 (to cover both FEC & FCC) */ | ||
| 115 | #define PKT_MAXBLR_SIZE ((PKT_MAXBUF_SIZE + 31) & ~31) | ||
| 116 | /* This is needed so that invalidate_xxx wont invalidate too much */ | ||
| 117 | #define ENET_RX_ALIGN 16 | ||
| 118 | #define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE + ENET_RX_ALIGN - 1) | ||
| 119 | |||
| 120 | struct fs_enet_private { | ||
| 121 | struct napi_struct napi; | ||
| 122 | struct device *dev; /* pointer back to the device (must be initialized first) */ | ||
| 123 | struct net_device *ndev; | ||
| 124 | spinlock_t lock; /* during all ops except TX pckt processing */ | ||
| 125 | spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */ | ||
| 126 | struct fs_platform_info *fpi; | ||
| 127 | const struct fs_ops *ops; | ||
| 128 | int rx_ring, tx_ring; | ||
| 129 | dma_addr_t ring_mem_addr; | ||
| 130 | void __iomem *ring_base; | ||
| 131 | struct sk_buff **rx_skbuff; | ||
| 132 | struct sk_buff **tx_skbuff; | ||
| 133 | cbd_t __iomem *rx_bd_base; /* Address of Rx and Tx buffers. */ | ||
| 134 | cbd_t __iomem *tx_bd_base; | ||
| 135 | cbd_t __iomem *dirty_tx; /* ring entries to be free()ed. */ | ||
| 136 | cbd_t __iomem *cur_rx; | ||
| 137 | cbd_t __iomem *cur_tx; | ||
| 138 | int tx_free; | ||
| 139 | struct net_device_stats stats; | ||
| 140 | struct timer_list phy_timer_list; | ||
| 141 | const struct phy_info *phy; | ||
| 142 | u32 msg_enable; | ||
| 143 | struct mii_if_info mii_if; | ||
| 144 | unsigned int last_mii_status; | ||
| 145 | int interrupt; | ||
| 146 | |||
| 147 | struct phy_device *phydev; | ||
| 148 | int oldduplex, oldspeed, oldlink; /* current settings */ | ||
| 149 | |||
| 150 | /* event masks */ | ||
| 151 | u32 ev_napi_rx; /* mask of NAPI rx events */ | ||
| 152 | u32 ev_rx; /* rx event mask */ | ||
| 153 | u32 ev_tx; /* tx event mask */ | ||
| 154 | u32 ev_err; /* error event mask */ | ||
| 155 | |||
| 156 | u16 bd_rx_empty; /* mask of BD rx empty */ | ||
| 157 | u16 bd_rx_err; /* mask of BD rx errors */ | ||
| 158 | |||
| 159 | union { | ||
| 160 | struct { | ||
| 161 | int idx; /* FEC1 = 0, FEC2 = 1 */ | ||
| 162 | void __iomem *fecp; /* hw registers */ | ||
| 163 | u32 hthi, htlo; /* state for multicast */ | ||
| 164 | } fec; | ||
| 165 | |||
| 166 | struct { | ||
| 167 | int idx; /* FCC1-3 = 0-2 */ | ||
| 168 | void __iomem *fccp; /* hw registers */ | ||
| 169 | void __iomem *ep; /* parameter ram */ | ||
| 170 | void __iomem *fcccp; /* hw registers cont. */ | ||
| 171 | void __iomem *mem; /* FCC DPRAM */ | ||
| 172 | u32 gaddrh, gaddrl; /* group address */ | ||
| 173 | } fcc; | ||
| 174 | |||
| 175 | struct { | ||
| 176 | int idx; /* FEC1 = 0, FEC2 = 1 */ | ||
| 177 | void __iomem *sccp; /* hw registers */ | ||
| 178 | void __iomem *ep; /* parameter ram */ | ||
| 179 | u32 hthi, htlo; /* state for multicast */ | ||
| 180 | } scc; | ||
| 181 | |||
| 182 | }; | ||
| 183 | }; | ||
| 184 | |||
| 185 | /***************************************************************************/ | ||
| 186 | |||
| 187 | void fs_init_bds(struct net_device *dev); | ||
| 188 | void fs_cleanup_bds(struct net_device *dev); | ||
| 189 | |||
| 190 | /***************************************************************************/ | ||
| 191 | |||
| 192 | #define DRV_MODULE_NAME "fs_enet" | ||
| 193 | #define PFX DRV_MODULE_NAME ": " | ||
| 194 | #define DRV_MODULE_VERSION "1.0" | ||
| 195 | #define DRV_MODULE_RELDATE "Aug 8, 2005" | ||
| 196 | |||
| 197 | /***************************************************************************/ | ||
| 198 | |||
| 199 | int fs_enet_platform_init(void); | ||
| 200 | void fs_enet_platform_cleanup(void); | ||
| 201 | |||
| 202 | /***************************************************************************/ | ||
| 203 | /* buffer descriptor access macros */ | ||
| 204 | |||
| 205 | /* access macros */ | ||
| 206 | #if defined(CONFIG_CPM1) | ||
| 207 | /* for a a CPM1 __raw_xxx's are sufficient */ | ||
| 208 | #define __cbd_out32(addr, x) __raw_writel(x, addr) | ||
| 209 | #define __cbd_out16(addr, x) __raw_writew(x, addr) | ||
| 210 | #define __cbd_in32(addr) __raw_readl(addr) | ||
| 211 | #define __cbd_in16(addr) __raw_readw(addr) | ||
| 212 | #else | ||
| 213 | /* for others play it safe */ | ||
| 214 | #define __cbd_out32(addr, x) out_be32(addr, x) | ||
| 215 | #define __cbd_out16(addr, x) out_be16(addr, x) | ||
| 216 | #define __cbd_in32(addr) in_be32(addr) | ||
| 217 | #define __cbd_in16(addr) in_be16(addr) | ||
| 218 | #endif | ||
| 219 | |||
| 220 | /* write */ | ||
| 221 | #define CBDW_SC(_cbd, _sc) __cbd_out16(&(_cbd)->cbd_sc, (_sc)) | ||
| 222 | #define CBDW_DATLEN(_cbd, _datlen) __cbd_out16(&(_cbd)->cbd_datlen, (_datlen)) | ||
| 223 | #define CBDW_BUFADDR(_cbd, _bufaddr) __cbd_out32(&(_cbd)->cbd_bufaddr, (_bufaddr)) | ||
| 224 | |||
| 225 | /* read */ | ||
| 226 | #define CBDR_SC(_cbd) __cbd_in16(&(_cbd)->cbd_sc) | ||
| 227 | #define CBDR_DATLEN(_cbd) __cbd_in16(&(_cbd)->cbd_datlen) | ||
| 228 | #define CBDR_BUFADDR(_cbd) __cbd_in32(&(_cbd)->cbd_bufaddr) | ||
| 229 | |||
| 230 | /* set bits */ | ||
| 231 | #define CBDS_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) | (_sc)) | ||
| 232 | |||
| 233 | /* clear bits */ | ||
| 234 | #define CBDC_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) & ~(_sc)) | ||
| 235 | |||
| 236 | /*******************************************************************/ | ||
| 237 | |||
| 238 | extern const struct fs_ops fs_fec_ops; | ||
| 239 | extern const struct fs_ops fs_fcc_ops; | ||
| 240 | extern const struct fs_ops fs_scc_ops; | ||
| 241 | |||
| 242 | /*******************************************************************/ | ||
| 243 | |||
| 244 | #endif | ||
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c new file mode 100644 index 00000000000..7583a9572bc --- /dev/null +++ b/drivers/net/fs_enet/mac-fcc.c | |||
| @@ -0,0 +1,584 @@ | |||
| 1 | /* | ||
| 2 | * FCC driver for Motorola MPC82xx (PQ2). | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 Intracom S.A. | ||
| 5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
| 6 | * | ||
| 7 | * 2005 (c) MontaVista Software, Inc. | ||
| 8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
| 9 | * | ||
| 10 | * This file is licensed under the terms of the GNU General Public License | ||
| 11 | * version 2. This program is licensed "as is" without any warranty of any | ||
| 12 | * kind, whether express or implied. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/types.h> | ||
| 18 | #include <linux/string.h> | ||
| 19 | #include <linux/ptrace.h> | ||
| 20 | #include <linux/errno.h> | ||
| 21 | #include <linux/ioport.h> | ||
| 22 | #include <linux/interrupt.h> | ||
| 23 | #include <linux/init.h> | ||
| 24 | #include <linux/delay.h> | ||
| 25 | #include <linux/netdevice.h> | ||
| 26 | #include <linux/etherdevice.h> | ||
| 27 | #include <linux/skbuff.h> | ||
| 28 | #include <linux/spinlock.h> | ||
| 29 | #include <linux/mii.h> | ||
| 30 | #include <linux/ethtool.h> | ||
| 31 | #include <linux/bitops.h> | ||
| 32 | #include <linux/fs.h> | ||
| 33 | #include <linux/platform_device.h> | ||
| 34 | #include <linux/phy.h> | ||
| 35 | #include <linux/of_device.h> | ||
| 36 | #include <linux/gfp.h> | ||
| 37 | |||
| 38 | #include <asm/immap_cpm2.h> | ||
| 39 | #include <asm/mpc8260.h> | ||
| 40 | #include <asm/cpm2.h> | ||
| 41 | |||
| 42 | #include <asm/pgtable.h> | ||
| 43 | #include <asm/irq.h> | ||
| 44 | #include <asm/uaccess.h> | ||
| 45 | |||
| 46 | #include "fs_enet.h" | ||
| 47 | |||
| 48 | /*************************************************/ | ||
| 49 | |||
| 50 | /* FCC access macros */ | ||
| 51 | |||
| 52 | /* write, read, set bits, clear bits */ | ||
| 53 | #define W32(_p, _m, _v) out_be32(&(_p)->_m, (_v)) | ||
| 54 | #define R32(_p, _m) in_be32(&(_p)->_m) | ||
| 55 | #define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) | ||
| 56 | #define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) | ||
| 57 | |||
| 58 | #define W16(_p, _m, _v) out_be16(&(_p)->_m, (_v)) | ||
| 59 | #define R16(_p, _m) in_be16(&(_p)->_m) | ||
| 60 | #define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) | ||
| 61 | #define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) | ||
| 62 | |||
| 63 | #define W8(_p, _m, _v) out_8(&(_p)->_m, (_v)) | ||
| 64 | #define R8(_p, _m) in_8(&(_p)->_m) | ||
| 65 | #define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) | ||
| 66 | #define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) | ||
| 67 | |||
| 68 | /*************************************************/ | ||
| 69 | |||
| 70 | #define FCC_MAX_MULTICAST_ADDRS 64 | ||
| 71 | |||
| 72 | #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) | ||
| 73 | #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) | ||
| 74 | #define mk_mii_end 0 | ||
| 75 | |||
| 76 | #define MAX_CR_CMD_LOOPS 10000 | ||
| 77 | |||
| 78 | static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 op) | ||
| 79 | { | ||
| 80 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 81 | |||
| 82 | return cpm_command(fpi->cp_command, op); | ||
| 83 | } | ||
| 84 | |||
| 85 | static int do_pd_setup(struct fs_enet_private *fep) | ||
| 86 | { | ||
| 87 | struct platform_device *ofdev = to_platform_device(fep->dev); | ||
| 88 | struct fs_platform_info *fpi = fep->fpi; | ||
| 89 | int ret = -EINVAL; | ||
| 90 | |||
| 91 | fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); | ||
| 92 | if (fep->interrupt == NO_IRQ) | ||
| 93 | goto out; | ||
| 94 | |||
| 95 | fep->fcc.fccp = of_iomap(ofdev->dev.of_node, 0); | ||
| 96 | if (!fep->fcc.fccp) | ||
| 97 | goto out; | ||
| 98 | |||
| 99 | fep->fcc.ep = of_iomap(ofdev->dev.of_node, 1); | ||
| 100 | if (!fep->fcc.ep) | ||
| 101 | goto out_fccp; | ||
| 102 | |||
| 103 | fep->fcc.fcccp = of_iomap(ofdev->dev.of_node, 2); | ||
| 104 | if (!fep->fcc.fcccp) | ||
| 105 | goto out_ep; | ||
| 106 | |||
| 107 | fep->fcc.mem = (void __iomem *)cpm2_immr; | ||
| 108 | fpi->dpram_offset = cpm_dpalloc(128, 32); | ||
| 109 | if (IS_ERR_VALUE(fpi->dpram_offset)) { | ||
| 110 | ret = fpi->dpram_offset; | ||
| 111 | goto out_fcccp; | ||
| 112 | } | ||
| 113 | |||
| 114 | return 0; | ||
| 115 | |||
| 116 | out_fcccp: | ||
| 117 | iounmap(fep->fcc.fcccp); | ||
| 118 | out_ep: | ||
| 119 | iounmap(fep->fcc.ep); | ||
| 120 | out_fccp: | ||
| 121 | iounmap(fep->fcc.fccp); | ||
| 122 | out: | ||
| 123 | return ret; | ||
| 124 | } | ||
| 125 | |||
| 126 | #define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB) | ||
| 127 | #define FCC_RX_EVENT (FCC_ENET_RXF) | ||
| 128 | #define FCC_TX_EVENT (FCC_ENET_TXB) | ||
| 129 | #define FCC_ERR_EVENT_MSK (FCC_ENET_TXE) | ||
| 130 | |||
| 131 | static int setup_data(struct net_device *dev) | ||
| 132 | { | ||
| 133 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 134 | |||
| 135 | if (do_pd_setup(fep) != 0) | ||
| 136 | return -EINVAL; | ||
| 137 | |||
| 138 | fep->ev_napi_rx = FCC_NAPI_RX_EVENT_MSK; | ||
| 139 | fep->ev_rx = FCC_RX_EVENT; | ||
| 140 | fep->ev_tx = FCC_TX_EVENT; | ||
| 141 | fep->ev_err = FCC_ERR_EVENT_MSK; | ||
| 142 | |||
| 143 | return 0; | ||
| 144 | } | ||
| 145 | |||
| 146 | static int allocate_bd(struct net_device *dev) | ||
| 147 | { | ||
| 148 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 149 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 150 | |||
| 151 | fep->ring_base = (void __iomem __force *)dma_alloc_coherent(fep->dev, | ||
| 152 | (fpi->tx_ring + fpi->rx_ring) * | ||
| 153 | sizeof(cbd_t), &fep->ring_mem_addr, | ||
| 154 | GFP_KERNEL); | ||
| 155 | if (fep->ring_base == NULL) | ||
| 156 | return -ENOMEM; | ||
| 157 | |||
| 158 | return 0; | ||
| 159 | } | ||
| 160 | |||
| 161 | static void free_bd(struct net_device *dev) | ||
| 162 | { | ||
| 163 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 164 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 165 | |||
| 166 | if (fep->ring_base) | ||
| 167 | dma_free_coherent(fep->dev, | ||
| 168 | (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), | ||
| 169 | (void __force *)fep->ring_base, fep->ring_mem_addr); | ||
| 170 | } | ||
| 171 | |||
| 172 | static void cleanup_data(struct net_device *dev) | ||
| 173 | { | ||
| 174 | /* nothing */ | ||
| 175 | } | ||
| 176 | |||
| 177 | static void set_promiscuous_mode(struct net_device *dev) | ||
| 178 | { | ||
| 179 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 180 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
| 181 | |||
| 182 | S32(fccp, fcc_fpsmr, FCC_PSMR_PRO); | ||
| 183 | } | ||
| 184 | |||
| 185 | static void set_multicast_start(struct net_device *dev) | ||
| 186 | { | ||
| 187 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 188 | fcc_enet_t __iomem *ep = fep->fcc.ep; | ||
| 189 | |||
| 190 | W32(ep, fen_gaddrh, 0); | ||
| 191 | W32(ep, fen_gaddrl, 0); | ||
| 192 | } | ||
| 193 | |||
| 194 | static void set_multicast_one(struct net_device *dev, const u8 *mac) | ||
| 195 | { | ||
| 196 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 197 | fcc_enet_t __iomem *ep = fep->fcc.ep; | ||
| 198 | u16 taddrh, taddrm, taddrl; | ||
| 199 | |||
| 200 | taddrh = ((u16)mac[5] << 8) | mac[4]; | ||
| 201 | taddrm = ((u16)mac[3] << 8) | mac[2]; | ||
| 202 | taddrl = ((u16)mac[1] << 8) | mac[0]; | ||
| 203 | |||
| 204 | W16(ep, fen_taddrh, taddrh); | ||
| 205 | W16(ep, fen_taddrm, taddrm); | ||
| 206 | W16(ep, fen_taddrl, taddrl); | ||
| 207 | fcc_cr_cmd(fep, CPM_CR_SET_GADDR); | ||
| 208 | } | ||
| 209 | |||
| 210 | static void set_multicast_finish(struct net_device *dev) | ||
| 211 | { | ||
| 212 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 213 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
| 214 | fcc_enet_t __iomem *ep = fep->fcc.ep; | ||
| 215 | |||
| 216 | /* clear promiscuous always */ | ||
| 217 | C32(fccp, fcc_fpsmr, FCC_PSMR_PRO); | ||
| 218 | |||
| 219 | /* if all multi or too many multicasts; just enable all */ | ||
| 220 | if ((dev->flags & IFF_ALLMULTI) != 0 || | ||
| 221 | netdev_mc_count(dev) > FCC_MAX_MULTICAST_ADDRS) { | ||
| 222 | |||
| 223 | W32(ep, fen_gaddrh, 0xffffffff); | ||
| 224 | W32(ep, fen_gaddrl, 0xffffffff); | ||
| 225 | } | ||
| 226 | |||
| 227 | /* read back */ | ||
| 228 | fep->fcc.gaddrh = R32(ep, fen_gaddrh); | ||
| 229 | fep->fcc.gaddrl = R32(ep, fen_gaddrl); | ||
| 230 | } | ||
| 231 | |||
| 232 | static void set_multicast_list(struct net_device *dev) | ||
| 233 | { | ||
| 234 | struct netdev_hw_addr *ha; | ||
| 235 | |||
| 236 | if ((dev->flags & IFF_PROMISC) == 0) { | ||
| 237 | set_multicast_start(dev); | ||
| 238 | netdev_for_each_mc_addr(ha, dev) | ||
| 239 | set_multicast_one(dev, ha->addr); | ||
| 240 | set_multicast_finish(dev); | ||
| 241 | } else | ||
| 242 | set_promiscuous_mode(dev); | ||
| 243 | } | ||
| 244 | |||
| 245 | static void restart(struct net_device *dev) | ||
| 246 | { | ||
| 247 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 248 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 249 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
| 250 | fcc_c_t __iomem *fcccp = fep->fcc.fcccp; | ||
| 251 | fcc_enet_t __iomem *ep = fep->fcc.ep; | ||
| 252 | dma_addr_t rx_bd_base_phys, tx_bd_base_phys; | ||
| 253 | u16 paddrh, paddrm, paddrl; | ||
| 254 | const unsigned char *mac; | ||
| 255 | int i; | ||
| 256 | |||
| 257 | C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); | ||
| 258 | |||
| 259 | /* clear everything (slow & steady does it) */ | ||
| 260 | for (i = 0; i < sizeof(*ep); i++) | ||
| 261 | out_8((u8 __iomem *)ep + i, 0); | ||
| 262 | |||
| 263 | /* get physical address */ | ||
| 264 | rx_bd_base_phys = fep->ring_mem_addr; | ||
| 265 | tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; | ||
| 266 | |||
| 267 | /* point to bds */ | ||
| 268 | W32(ep, fen_genfcc.fcc_rbase, rx_bd_base_phys); | ||
| 269 | W32(ep, fen_genfcc.fcc_tbase, tx_bd_base_phys); | ||
| 270 | |||
| 271 | /* Set maximum bytes per receive buffer. | ||
| 272 | * It must be a multiple of 32. | ||
| 273 | */ | ||
| 274 | W16(ep, fen_genfcc.fcc_mrblr, PKT_MAXBLR_SIZE); | ||
| 275 | |||
| 276 | W32(ep, fen_genfcc.fcc_rstate, (CPMFCR_GBL | CPMFCR_EB) << 24); | ||
| 277 | W32(ep, fen_genfcc.fcc_tstate, (CPMFCR_GBL | CPMFCR_EB) << 24); | ||
| 278 | |||
| 279 | /* Allocate space in the reserved FCC area of DPRAM for the | ||
| 280 | * internal buffers. No one uses this space (yet), so we | ||
| 281 | * can do this. Later, we will add resource management for | ||
| 282 | * this area. | ||
| 283 | */ | ||
| 284 | |||
| 285 | W16(ep, fen_genfcc.fcc_riptr, fpi->dpram_offset); | ||
| 286 | W16(ep, fen_genfcc.fcc_tiptr, fpi->dpram_offset + 32); | ||
| 287 | |||
| 288 | W16(ep, fen_padptr, fpi->dpram_offset + 64); | ||
| 289 | |||
| 290 | /* fill with special symbol... */ | ||
| 291 | memset_io(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32); | ||
| 292 | |||
| 293 | W32(ep, fen_genfcc.fcc_rbptr, 0); | ||
| 294 | W32(ep, fen_genfcc.fcc_tbptr, 0); | ||
| 295 | W32(ep, fen_genfcc.fcc_rcrc, 0); | ||
| 296 | W32(ep, fen_genfcc.fcc_tcrc, 0); | ||
| 297 | W16(ep, fen_genfcc.fcc_res1, 0); | ||
| 298 | W32(ep, fen_genfcc.fcc_res2, 0); | ||
| 299 | |||
| 300 | /* no CAM */ | ||
| 301 | W32(ep, fen_camptr, 0); | ||
| 302 | |||
| 303 | /* Set CRC preset and mask */ | ||
| 304 | W32(ep, fen_cmask, 0xdebb20e3); | ||
| 305 | W32(ep, fen_cpres, 0xffffffff); | ||
| 306 | |||
| 307 | W32(ep, fen_crcec, 0); /* CRC Error counter */ | ||
| 308 | W32(ep, fen_alec, 0); /* alignment error counter */ | ||
| 309 | W32(ep, fen_disfc, 0); /* discard frame counter */ | ||
| 310 | W16(ep, fen_retlim, 15); /* Retry limit threshold */ | ||
| 311 | W16(ep, fen_pper, 0); /* Normal persistence */ | ||
| 312 | |||
| 313 | /* set group address */ | ||
| 314 | W32(ep, fen_gaddrh, fep->fcc.gaddrh); | ||
| 315 | W32(ep, fen_gaddrl, fep->fcc.gaddrh); | ||
| 316 | |||
| 317 | /* Clear hash filter tables */ | ||
| 318 | W32(ep, fen_iaddrh, 0); | ||
| 319 | W32(ep, fen_iaddrl, 0); | ||
| 320 | |||
| 321 | /* Clear the Out-of-sequence TxBD */ | ||
| 322 | W16(ep, fen_tfcstat, 0); | ||
| 323 | W16(ep, fen_tfclen, 0); | ||
| 324 | W32(ep, fen_tfcptr, 0); | ||
| 325 | |||
| 326 | W16(ep, fen_mflr, PKT_MAXBUF_SIZE); /* maximum frame length register */ | ||
| 327 | W16(ep, fen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ | ||
| 328 | |||
| 329 | /* set address */ | ||
| 330 | mac = dev->dev_addr; | ||
| 331 | paddrh = ((u16)mac[5] << 8) | mac[4]; | ||
| 332 | paddrm = ((u16)mac[3] << 8) | mac[2]; | ||
| 333 | paddrl = ((u16)mac[1] << 8) | mac[0]; | ||
| 334 | |||
| 335 | W16(ep, fen_paddrh, paddrh); | ||
| 336 | W16(ep, fen_paddrm, paddrm); | ||
| 337 | W16(ep, fen_paddrl, paddrl); | ||
| 338 | |||
| 339 | W16(ep, fen_taddrh, 0); | ||
| 340 | W16(ep, fen_taddrm, 0); | ||
| 341 | W16(ep, fen_taddrl, 0); | ||
| 342 | |||
| 343 | W16(ep, fen_maxd1, 1520); /* maximum DMA1 length */ | ||
| 344 | W16(ep, fen_maxd2, 1520); /* maximum DMA2 length */ | ||
| 345 | |||
| 346 | /* Clear stat counters, in case we ever enable RMON */ | ||
| 347 | W32(ep, fen_octc, 0); | ||
| 348 | W32(ep, fen_colc, 0); | ||
| 349 | W32(ep, fen_broc, 0); | ||
| 350 | W32(ep, fen_mulc, 0); | ||
| 351 | W32(ep, fen_uspc, 0); | ||
| 352 | W32(ep, fen_frgc, 0); | ||
| 353 | W32(ep, fen_ospc, 0); | ||
| 354 | W32(ep, fen_jbrc, 0); | ||
| 355 | W32(ep, fen_p64c, 0); | ||
| 356 | W32(ep, fen_p65c, 0); | ||
| 357 | W32(ep, fen_p128c, 0); | ||
| 358 | W32(ep, fen_p256c, 0); | ||
| 359 | W32(ep, fen_p512c, 0); | ||
| 360 | W32(ep, fen_p1024c, 0); | ||
| 361 | |||
| 362 | W16(ep, fen_rfthr, 0); /* Suggested by manual */ | ||
| 363 | W16(ep, fen_rfcnt, 0); | ||
| 364 | W16(ep, fen_cftype, 0); | ||
| 365 | |||
| 366 | fs_init_bds(dev); | ||
| 367 | |||
| 368 | /* adjust to speed (for RMII mode) */ | ||
| 369 | if (fpi->use_rmii) { | ||
| 370 | if (fep->phydev->speed == 100) | ||
| 371 | C8(fcccp, fcc_gfemr, 0x20); | ||
| 372 | else | ||
| 373 | S8(fcccp, fcc_gfemr, 0x20); | ||
| 374 | } | ||
| 375 | |||
| 376 | fcc_cr_cmd(fep, CPM_CR_INIT_TRX); | ||
| 377 | |||
| 378 | /* clear events */ | ||
| 379 | W16(fccp, fcc_fcce, 0xffff); | ||
| 380 | |||
| 381 | /* Enable interrupts we wish to service */ | ||
| 382 | W16(fccp, fcc_fccm, FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB); | ||
| 383 | |||
| 384 | /* Set GFMR to enable Ethernet operating mode */ | ||
| 385 | W32(fccp, fcc_gfmr, FCC_GFMR_TCI | FCC_GFMR_MODE_ENET); | ||
| 386 | |||
| 387 | /* set sync/delimiters */ | ||
| 388 | W16(fccp, fcc_fdsr, 0xd555); | ||
| 389 | |||
| 390 | W32(fccp, fcc_fpsmr, FCC_PSMR_ENCRC); | ||
| 391 | |||
| 392 | if (fpi->use_rmii) | ||
| 393 | S32(fccp, fcc_fpsmr, FCC_PSMR_RMII); | ||
| 394 | |||
| 395 | /* adjust to duplex mode */ | ||
| 396 | if (fep->phydev->duplex) | ||
| 397 | S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); | ||
| 398 | else | ||
| 399 | C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); | ||
| 400 | |||
| 401 | /* Restore multicast and promiscuous settings */ | ||
| 402 | set_multicast_list(dev); | ||
| 403 | |||
| 404 | S32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); | ||
| 405 | } | ||
| 406 | |||
| 407 | static void stop(struct net_device *dev) | ||
| 408 | { | ||
| 409 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 410 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
| 411 | |||
| 412 | /* stop ethernet */ | ||
| 413 | C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); | ||
| 414 | |||
| 415 | /* clear events */ | ||
| 416 | W16(fccp, fcc_fcce, 0xffff); | ||
| 417 | |||
| 418 | /* clear interrupt mask */ | ||
| 419 | W16(fccp, fcc_fccm, 0); | ||
| 420 | |||
| 421 | fs_cleanup_bds(dev); | ||
| 422 | } | ||
| 423 | |||
| 424 | static void napi_clear_rx_event(struct net_device *dev) | ||
| 425 | { | ||
| 426 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 427 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
| 428 | |||
| 429 | W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK); | ||
| 430 | } | ||
| 431 | |||
| 432 | static void napi_enable_rx(struct net_device *dev) | ||
| 433 | { | ||
| 434 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 435 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
| 436 | |||
| 437 | S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); | ||
| 438 | } | ||
| 439 | |||
| 440 | static void napi_disable_rx(struct net_device *dev) | ||
| 441 | { | ||
| 442 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 443 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
| 444 | |||
| 445 | C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); | ||
| 446 | } | ||
| 447 | |||
| 448 | static void rx_bd_done(struct net_device *dev) | ||
| 449 | { | ||
| 450 | /* nothing */ | ||
| 451 | } | ||
| 452 | |||
| 453 | static void tx_kickstart(struct net_device *dev) | ||
| 454 | { | ||
| 455 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 456 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
| 457 | |||
| 458 | S16(fccp, fcc_ftodr, 0x8000); | ||
| 459 | } | ||
| 460 | |||
| 461 | static u32 get_int_events(struct net_device *dev) | ||
| 462 | { | ||
| 463 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 464 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
| 465 | |||
| 466 | return (u32)R16(fccp, fcc_fcce); | ||
| 467 | } | ||
| 468 | |||
| 469 | static void clear_int_events(struct net_device *dev, u32 int_events) | ||
| 470 | { | ||
| 471 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 472 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
| 473 | |||
| 474 | W16(fccp, fcc_fcce, int_events & 0xffff); | ||
| 475 | } | ||
| 476 | |||
| 477 | static void ev_error(struct net_device *dev, u32 int_events) | ||
| 478 | { | ||
| 479 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 480 | |||
| 481 | dev_warn(fep->dev, "FS_ENET ERROR(s) 0x%x\n", int_events); | ||
| 482 | } | ||
| 483 | |||
| 484 | static int get_regs(struct net_device *dev, void *p, int *sizep) | ||
| 485 | { | ||
| 486 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 487 | |||
| 488 | if (*sizep < sizeof(fcc_t) + sizeof(fcc_enet_t) + 1) | ||
| 489 | return -EINVAL; | ||
| 490 | |||
| 491 | memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t)); | ||
| 492 | p = (char *)p + sizeof(fcc_t); | ||
| 493 | |||
| 494 | memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t)); | ||
| 495 | p = (char *)p + sizeof(fcc_enet_t); | ||
| 496 | |||
| 497 | memcpy_fromio(p, fep->fcc.fcccp, 1); | ||
| 498 | return 0; | ||
| 499 | } | ||
| 500 | |||
| 501 | static int get_regs_len(struct net_device *dev) | ||
| 502 | { | ||
| 503 | return sizeof(fcc_t) + sizeof(fcc_enet_t) + 1; | ||
| 504 | } | ||
| 505 | |||
| 506 | /* Some transmit errors cause the transmitter to shut | ||
| 507 | * down. We now issue a restart transmit. | ||
| 508 | * Also, to workaround 8260 device erratum CPM37, we must | ||
| 509 | * disable and then re-enable the transmitterfollowing a | ||
| 510 | * Late Collision, Underrun, or Retry Limit error. | ||
| 511 | * In addition, tbptr may point beyond BDs beyond still marked | ||
| 512 | * as ready due to internal pipelining, so we need to look back | ||
| 513 | * through the BDs and adjust tbptr to point to the last BD | ||
| 514 | * marked as ready. This may result in some buffers being | ||
| 515 | * retransmitted. | ||
| 516 | */ | ||
| 517 | static void tx_restart(struct net_device *dev) | ||
| 518 | { | ||
| 519 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 520 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
| 521 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 522 | fcc_enet_t __iomem *ep = fep->fcc.ep; | ||
| 523 | cbd_t __iomem *curr_tbptr; | ||
| 524 | cbd_t __iomem *recheck_bd; | ||
| 525 | cbd_t __iomem *prev_bd; | ||
| 526 | cbd_t __iomem *last_tx_bd; | ||
| 527 | |||
| 528 | last_tx_bd = fep->tx_bd_base + (fpi->tx_ring * sizeof(cbd_t)); | ||
| 529 | |||
| 530 | /* get the current bd held in TBPTR and scan back from this point */ | ||
| 531 | recheck_bd = curr_tbptr = (cbd_t __iomem *) | ||
| 532 | ((R32(ep, fen_genfcc.fcc_tbptr) - fep->ring_mem_addr) + | ||
| 533 | fep->ring_base); | ||
| 534 | |||
| 535 | prev_bd = (recheck_bd == fep->tx_bd_base) ? last_tx_bd : recheck_bd - 1; | ||
| 536 | |||
| 537 | /* Move through the bds in reverse, look for the earliest buffer | ||
| 538 | * that is not ready. Adjust TBPTR to the following buffer */ | ||
| 539 | while ((CBDR_SC(prev_bd) & BD_ENET_TX_READY) != 0) { | ||
| 540 | /* Go back one buffer */ | ||
| 541 | recheck_bd = prev_bd; | ||
| 542 | |||
| 543 | /* update the previous buffer */ | ||
| 544 | prev_bd = (prev_bd == fep->tx_bd_base) ? last_tx_bd : prev_bd - 1; | ||
| 545 | |||
| 546 | /* We should never see all bds marked as ready, check anyway */ | ||
| 547 | if (recheck_bd == curr_tbptr) | ||
| 548 | break; | ||
| 549 | } | ||
| 550 | /* Now update the TBPTR and dirty flag to the current buffer */ | ||
| 551 | W32(ep, fen_genfcc.fcc_tbptr, | ||
| 552 | (uint) (((void *)recheck_bd - fep->ring_base) + | ||
| 553 | fep->ring_mem_addr)); | ||
| 554 | fep->dirty_tx = recheck_bd; | ||
| 555 | |||
| 556 | C32(fccp, fcc_gfmr, FCC_GFMR_ENT); | ||
| 557 | udelay(10); | ||
| 558 | S32(fccp, fcc_gfmr, FCC_GFMR_ENT); | ||
| 559 | |||
| 560 | fcc_cr_cmd(fep, CPM_CR_RESTART_TX); | ||
| 561 | } | ||
| 562 | |||
| 563 | /*************************************************************************/ | ||
| 564 | |||
| 565 | const struct fs_ops fs_fcc_ops = { | ||
| 566 | .setup_data = setup_data, | ||
| 567 | .cleanup_data = cleanup_data, | ||
| 568 | .set_multicast_list = set_multicast_list, | ||
| 569 | .restart = restart, | ||
| 570 | .stop = stop, | ||
| 571 | .napi_clear_rx_event = napi_clear_rx_event, | ||
| 572 | .napi_enable_rx = napi_enable_rx, | ||
| 573 | .napi_disable_rx = napi_disable_rx, | ||
| 574 | .rx_bd_done = rx_bd_done, | ||
| 575 | .tx_kickstart = tx_kickstart, | ||
| 576 | .get_int_events = get_int_events, | ||
| 577 | .clear_int_events = clear_int_events, | ||
| 578 | .ev_error = ev_error, | ||
| 579 | .get_regs = get_regs, | ||
| 580 | .get_regs_len = get_regs_len, | ||
| 581 | .tx_restart = tx_restart, | ||
| 582 | .allocate_bd = allocate_bd, | ||
| 583 | .free_bd = free_bd, | ||
| 584 | }; | ||
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c new file mode 100644 index 00000000000..b9fbc83d64a --- /dev/null +++ b/drivers/net/fs_enet/mac-fec.c | |||
| @@ -0,0 +1,498 @@ | |||
| 1 | /* | ||
| 2 | * Freescale Ethernet controllers | ||
| 3 | * | ||
| 4 | * Copyright (c) 2005 Intracom S.A. | ||
| 5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
| 6 | * | ||
| 7 | * 2005 (c) MontaVista Software, Inc. | ||
| 8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
| 9 | * | ||
| 10 | * This file is licensed under the terms of the GNU General Public License | ||
| 11 | * version 2. This program is licensed "as is" without any warranty of any | ||
| 12 | * kind, whether express or implied. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/types.h> | ||
| 18 | #include <linux/string.h> | ||
| 19 | #include <linux/ptrace.h> | ||
| 20 | #include <linux/errno.h> | ||
| 21 | #include <linux/ioport.h> | ||
| 22 | #include <linux/interrupt.h> | ||
| 23 | #include <linux/init.h> | ||
| 24 | #include <linux/delay.h> | ||
| 25 | #include <linux/netdevice.h> | ||
| 26 | #include <linux/etherdevice.h> | ||
| 27 | #include <linux/skbuff.h> | ||
| 28 | #include <linux/spinlock.h> | ||
| 29 | #include <linux/mii.h> | ||
| 30 | #include <linux/ethtool.h> | ||
| 31 | #include <linux/bitops.h> | ||
| 32 | #include <linux/fs.h> | ||
| 33 | #include <linux/platform_device.h> | ||
| 34 | #include <linux/of_device.h> | ||
| 35 | #include <linux/gfp.h> | ||
| 36 | |||
| 37 | #include <asm/irq.h> | ||
| 38 | #include <asm/uaccess.h> | ||
| 39 | |||
| 40 | #ifdef CONFIG_8xx | ||
| 41 | #include <asm/8xx_immap.h> | ||
| 42 | #include <asm/pgtable.h> | ||
| 43 | #include <asm/mpc8xx.h> | ||
| 44 | #include <asm/cpm1.h> | ||
| 45 | #endif | ||
| 46 | |||
| 47 | #include "fs_enet.h" | ||
| 48 | #include "fec.h" | ||
| 49 | |||
| 50 | /*************************************************/ | ||
| 51 | |||
| 52 | #if defined(CONFIG_CPM1) | ||
| 53 | /* for a CPM1 __raw_xxx's are sufficient */ | ||
| 54 | #define __fs_out32(addr, x) __raw_writel(x, addr) | ||
| 55 | #define __fs_out16(addr, x) __raw_writew(x, addr) | ||
| 56 | #define __fs_in32(addr) __raw_readl(addr) | ||
| 57 | #define __fs_in16(addr) __raw_readw(addr) | ||
| 58 | #else | ||
| 59 | /* for others play it safe */ | ||
| 60 | #define __fs_out32(addr, x) out_be32(addr, x) | ||
| 61 | #define __fs_out16(addr, x) out_be16(addr, x) | ||
| 62 | #define __fs_in32(addr) in_be32(addr) | ||
| 63 | #define __fs_in16(addr) in_be16(addr) | ||
| 64 | #endif | ||
| 65 | |||
| 66 | /* write */ | ||
| 67 | #define FW(_fecp, _reg, _v) __fs_out32(&(_fecp)->fec_ ## _reg, (_v)) | ||
| 68 | |||
| 69 | /* read */ | ||
| 70 | #define FR(_fecp, _reg) __fs_in32(&(_fecp)->fec_ ## _reg) | ||
| 71 | |||
| 72 | /* set bits */ | ||
| 73 | #define FS(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) | (_v)) | ||
| 74 | |||
| 75 | /* clear bits */ | ||
| 76 | #define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v)) | ||
| 77 | |||
| 78 | /* | ||
| 79 | * Delay to wait for FEC reset command to complete (in us) | ||
| 80 | */ | ||
| 81 | #define FEC_RESET_DELAY 50 | ||
| 82 | |||
| 83 | static int whack_reset(struct fec __iomem *fecp) | ||
| 84 | { | ||
| 85 | int i; | ||
| 86 | |||
| 87 | FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET); | ||
| 88 | for (i = 0; i < FEC_RESET_DELAY; i++) { | ||
| 89 | if ((FR(fecp, ecntrl) & FEC_ECNTRL_RESET) == 0) | ||
| 90 | return 0; /* OK */ | ||
| 91 | udelay(1); | ||
| 92 | } | ||
| 93 | |||
| 94 | return -1; | ||
| 95 | } | ||
| 96 | |||
| 97 | static int do_pd_setup(struct fs_enet_private *fep) | ||
| 98 | { | ||
| 99 | struct platform_device *ofdev = to_platform_device(fep->dev); | ||
| 100 | |||
| 101 | fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); | ||
| 102 | if (fep->interrupt == NO_IRQ) | ||
| 103 | return -EINVAL; | ||
| 104 | |||
| 105 | fep->fec.fecp = of_iomap(ofdev->dev.of_node, 0); | ||
| 106 | if (!fep->fcc.fccp) | ||
| 107 | return -EINVAL; | ||
| 108 | |||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | #define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB) | ||
| 113 | #define FEC_RX_EVENT (FEC_ENET_RXF) | ||
| 114 | #define FEC_TX_EVENT (FEC_ENET_TXF) | ||
| 115 | #define FEC_ERR_EVENT_MSK (FEC_ENET_HBERR | FEC_ENET_BABR | \ | ||
| 116 | FEC_ENET_BABT | FEC_ENET_EBERR) | ||
| 117 | |||
| 118 | static int setup_data(struct net_device *dev) | ||
| 119 | { | ||
| 120 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 121 | |||
| 122 | if (do_pd_setup(fep) != 0) | ||
| 123 | return -EINVAL; | ||
| 124 | |||
| 125 | fep->fec.hthi = 0; | ||
| 126 | fep->fec.htlo = 0; | ||
| 127 | |||
| 128 | fep->ev_napi_rx = FEC_NAPI_RX_EVENT_MSK; | ||
| 129 | fep->ev_rx = FEC_RX_EVENT; | ||
| 130 | fep->ev_tx = FEC_TX_EVENT; | ||
| 131 | fep->ev_err = FEC_ERR_EVENT_MSK; | ||
| 132 | |||
| 133 | return 0; | ||
| 134 | } | ||
| 135 | |||
| 136 | static int allocate_bd(struct net_device *dev) | ||
| 137 | { | ||
| 138 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 139 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 140 | |||
| 141 | fep->ring_base = (void __force __iomem *)dma_alloc_coherent(fep->dev, | ||
| 142 | (fpi->tx_ring + fpi->rx_ring) * | ||
| 143 | sizeof(cbd_t), &fep->ring_mem_addr, | ||
| 144 | GFP_KERNEL); | ||
| 145 | if (fep->ring_base == NULL) | ||
| 146 | return -ENOMEM; | ||
| 147 | |||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | static void free_bd(struct net_device *dev) | ||
| 152 | { | ||
| 153 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 154 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 155 | |||
| 156 | if(fep->ring_base) | ||
| 157 | dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) | ||
| 158 | * sizeof(cbd_t), | ||
| 159 | (void __force *)fep->ring_base, | ||
| 160 | fep->ring_mem_addr); | ||
| 161 | } | ||
| 162 | |||
| 163 | static void cleanup_data(struct net_device *dev) | ||
| 164 | { | ||
| 165 | /* nothing */ | ||
| 166 | } | ||
| 167 | |||
| 168 | static void set_promiscuous_mode(struct net_device *dev) | ||
| 169 | { | ||
| 170 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 171 | struct fec __iomem *fecp = fep->fec.fecp; | ||
| 172 | |||
| 173 | FS(fecp, r_cntrl, FEC_RCNTRL_PROM); | ||
| 174 | } | ||
| 175 | |||
| 176 | static void set_multicast_start(struct net_device *dev) | ||
| 177 | { | ||
| 178 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 179 | |||
| 180 | fep->fec.hthi = 0; | ||
| 181 | fep->fec.htlo = 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | static void set_multicast_one(struct net_device *dev, const u8 *mac) | ||
| 185 | { | ||
| 186 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 187 | int temp, hash_index, i, j; | ||
| 188 | u32 crc, csrVal; | ||
| 189 | u8 byte, msb; | ||
| 190 | |||
| 191 | crc = 0xffffffff; | ||
| 192 | for (i = 0; i < 6; i++) { | ||
| 193 | byte = mac[i]; | ||
| 194 | for (j = 0; j < 8; j++) { | ||
| 195 | msb = crc >> 31; | ||
| 196 | crc <<= 1; | ||
| 197 | if (msb ^ (byte & 0x1)) | ||
| 198 | crc ^= FEC_CRC_POLY; | ||
| 199 | byte >>= 1; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | temp = (crc & 0x3f) >> 1; | ||
| 204 | hash_index = ((temp & 0x01) << 4) | | ||
| 205 | ((temp & 0x02) << 2) | | ||
| 206 | ((temp & 0x04)) | | ||
| 207 | ((temp & 0x08) >> 2) | | ||
| 208 | ((temp & 0x10) >> 4); | ||
| 209 | csrVal = 1 << hash_index; | ||
| 210 | if (crc & 1) | ||
| 211 | fep->fec.hthi |= csrVal; | ||
| 212 | else | ||
| 213 | fep->fec.htlo |= csrVal; | ||
| 214 | } | ||
| 215 | |||
| 216 | static void set_multicast_finish(struct net_device *dev) | ||
| 217 | { | ||
| 218 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 219 | struct fec __iomem *fecp = fep->fec.fecp; | ||
| 220 | |||
| 221 | /* if all multi or too many multicasts; just enable all */ | ||
| 222 | if ((dev->flags & IFF_ALLMULTI) != 0 || | ||
| 223 | netdev_mc_count(dev) > FEC_MAX_MULTICAST_ADDRS) { | ||
| 224 | fep->fec.hthi = 0xffffffffU; | ||
| 225 | fep->fec.htlo = 0xffffffffU; | ||
| 226 | } | ||
| 227 | |||
| 228 | FC(fecp, r_cntrl, FEC_RCNTRL_PROM); | ||
| 229 | FW(fecp, grp_hash_table_high, fep->fec.hthi); | ||
| 230 | FW(fecp, grp_hash_table_low, fep->fec.htlo); | ||
| 231 | } | ||
| 232 | |||
| 233 | static void set_multicast_list(struct net_device *dev) | ||
| 234 | { | ||
| 235 | struct netdev_hw_addr *ha; | ||
| 236 | |||
| 237 | if ((dev->flags & IFF_PROMISC) == 0) { | ||
| 238 | set_multicast_start(dev); | ||
| 239 | netdev_for_each_mc_addr(ha, dev) | ||
| 240 | set_multicast_one(dev, ha->addr); | ||
| 241 | set_multicast_finish(dev); | ||
| 242 | } else | ||
| 243 | set_promiscuous_mode(dev); | ||
| 244 | } | ||
| 245 | |||
| 246 | static void restart(struct net_device *dev) | ||
| 247 | { | ||
| 248 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 249 | struct fec __iomem *fecp = fep->fec.fecp; | ||
| 250 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 251 | dma_addr_t rx_bd_base_phys, tx_bd_base_phys; | ||
| 252 | int r; | ||
| 253 | u32 addrhi, addrlo; | ||
| 254 | |||
| 255 | struct mii_bus* mii = fep->phydev->bus; | ||
| 256 | struct fec_info* fec_inf = mii->priv; | ||
| 257 | |||
| 258 | r = whack_reset(fep->fec.fecp); | ||
| 259 | if (r != 0) | ||
| 260 | dev_err(fep->dev, "FEC Reset FAILED!\n"); | ||
| 261 | /* | ||
| 262 | * Set station address. | ||
| 263 | */ | ||
| 264 | addrhi = ((u32) dev->dev_addr[0] << 24) | | ||
| 265 | ((u32) dev->dev_addr[1] << 16) | | ||
| 266 | ((u32) dev->dev_addr[2] << 8) | | ||
| 267 | (u32) dev->dev_addr[3]; | ||
| 268 | addrlo = ((u32) dev->dev_addr[4] << 24) | | ||
| 269 | ((u32) dev->dev_addr[5] << 16); | ||
| 270 | FW(fecp, addr_low, addrhi); | ||
| 271 | FW(fecp, addr_high, addrlo); | ||
| 272 | |||
| 273 | /* | ||
| 274 | * Reset all multicast. | ||
| 275 | */ | ||
| 276 | FW(fecp, grp_hash_table_high, fep->fec.hthi); | ||
| 277 | FW(fecp, grp_hash_table_low, fep->fec.htlo); | ||
| 278 | |||
| 279 | /* | ||
| 280 | * Set maximum receive buffer size. | ||
| 281 | */ | ||
| 282 | FW(fecp, r_buff_size, PKT_MAXBLR_SIZE); | ||
| 283 | #ifdef CONFIG_FS_ENET_MPC5121_FEC | ||
| 284 | FW(fecp, r_cntrl, PKT_MAXBUF_SIZE << 16); | ||
| 285 | #else | ||
| 286 | FW(fecp, r_hash, PKT_MAXBUF_SIZE); | ||
| 287 | #endif | ||
| 288 | |||
| 289 | /* get physical address */ | ||
| 290 | rx_bd_base_phys = fep->ring_mem_addr; | ||
| 291 | tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; | ||
| 292 | |||
| 293 | /* | ||
| 294 | * Set receive and transmit descriptor base. | ||
| 295 | */ | ||
| 296 | FW(fecp, r_des_start, rx_bd_base_phys); | ||
| 297 | FW(fecp, x_des_start, tx_bd_base_phys); | ||
| 298 | |||
| 299 | fs_init_bds(dev); | ||
| 300 | |||
| 301 | /* | ||
| 302 | * Enable big endian and don't care about SDMA FC. | ||
| 303 | */ | ||
| 304 | #ifdef CONFIG_FS_ENET_MPC5121_FEC | ||
| 305 | FS(fecp, dma_control, 0xC0000000); | ||
| 306 | #else | ||
| 307 | FW(fecp, fun_code, 0x78000000); | ||
| 308 | #endif | ||
| 309 | |||
| 310 | /* | ||
| 311 | * Set MII speed. | ||
| 312 | */ | ||
| 313 | FW(fecp, mii_speed, fec_inf->mii_speed); | ||
| 314 | |||
| 315 | /* | ||
| 316 | * Clear any outstanding interrupt. | ||
| 317 | */ | ||
| 318 | FW(fecp, ievent, 0xffc0); | ||
| 319 | #ifndef CONFIG_FS_ENET_MPC5121_FEC | ||
| 320 | FW(fecp, ivec, (virq_to_hw(fep->interrupt) / 2) << 29); | ||
| 321 | |||
| 322 | FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | ||
| 323 | #else | ||
| 324 | /* | ||
| 325 | * Only set MII mode - do not touch maximum frame length | ||
| 326 | * configured before. | ||
| 327 | */ | ||
| 328 | FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); | ||
| 329 | #endif | ||
| 330 | /* | ||
| 331 | * adjust to duplex mode | ||
| 332 | */ | ||
| 333 | if (fep->phydev->duplex) { | ||
| 334 | FC(fecp, r_cntrl, FEC_RCNTRL_DRT); | ||
| 335 | FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */ | ||
| 336 | } else { | ||
| 337 | FS(fecp, r_cntrl, FEC_RCNTRL_DRT); | ||
| 338 | FC(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD disable */ | ||
| 339 | } | ||
| 340 | |||
| 341 | /* | ||
| 342 | * Enable interrupts we wish to service. | ||
| 343 | */ | ||
| 344 | FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB | | ||
| 345 | FEC_ENET_RXF | FEC_ENET_RXB); | ||
| 346 | |||
| 347 | /* | ||
| 348 | * And last, enable the transmit and receive processing. | ||
| 349 | */ | ||
| 350 | FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | ||
| 351 | FW(fecp, r_des_active, 0x01000000); | ||
| 352 | } | ||
| 353 | |||
| 354 | static void stop(struct net_device *dev) | ||
| 355 | { | ||
| 356 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 357 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 358 | struct fec __iomem *fecp = fep->fec.fecp; | ||
| 359 | |||
| 360 | struct fec_info* feci= fep->phydev->bus->priv; | ||
| 361 | |||
| 362 | int i; | ||
| 363 | |||
| 364 | if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0) | ||
| 365 | return; /* already down */ | ||
| 366 | |||
| 367 | FW(fecp, x_cntrl, 0x01); /* Graceful transmit stop */ | ||
| 368 | for (i = 0; ((FR(fecp, ievent) & 0x10000000) == 0) && | ||
| 369 | i < FEC_RESET_DELAY; i++) | ||
| 370 | udelay(1); | ||
| 371 | |||
| 372 | if (i == FEC_RESET_DELAY) | ||
| 373 | dev_warn(fep->dev, "FEC timeout on graceful transmit stop\n"); | ||
| 374 | /* | ||
| 375 | * Disable FEC. Let only MII interrupts. | ||
| 376 | */ | ||
| 377 | FW(fecp, imask, 0); | ||
| 378 | FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN); | ||
| 379 | |||
| 380 | fs_cleanup_bds(dev); | ||
| 381 | |||
| 382 | /* shut down FEC1? that's where the mii bus is */ | ||
| 383 | if (fpi->has_phy) { | ||
| 384 | FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | ||
| 385 | FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | ||
| 386 | FW(fecp, ievent, FEC_ENET_MII); | ||
| 387 | FW(fecp, mii_speed, feci->mii_speed); | ||
| 388 | } | ||
| 389 | } | ||
| 390 | |||
| 391 | static void napi_clear_rx_event(struct net_device *dev) | ||
| 392 | { | ||
| 393 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 394 | struct fec __iomem *fecp = fep->fec.fecp; | ||
| 395 | |||
| 396 | FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK); | ||
| 397 | } | ||
| 398 | |||
| 399 | static void napi_enable_rx(struct net_device *dev) | ||
| 400 | { | ||
| 401 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 402 | struct fec __iomem *fecp = fep->fec.fecp; | ||
| 403 | |||
| 404 | FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK); | ||
| 405 | } | ||
| 406 | |||
| 407 | static void napi_disable_rx(struct net_device *dev) | ||
| 408 | { | ||
| 409 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 410 | struct fec __iomem *fecp = fep->fec.fecp; | ||
| 411 | |||
| 412 | FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK); | ||
| 413 | } | ||
| 414 | |||
| 415 | static void rx_bd_done(struct net_device *dev) | ||
| 416 | { | ||
| 417 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 418 | struct fec __iomem *fecp = fep->fec.fecp; | ||
| 419 | |||
| 420 | FW(fecp, r_des_active, 0x01000000); | ||
| 421 | } | ||
| 422 | |||
| 423 | static void tx_kickstart(struct net_device *dev) | ||
| 424 | { | ||
| 425 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 426 | struct fec __iomem *fecp = fep->fec.fecp; | ||
| 427 | |||
| 428 | FW(fecp, x_des_active, 0x01000000); | ||
| 429 | } | ||
| 430 | |||
| 431 | static u32 get_int_events(struct net_device *dev) | ||
| 432 | { | ||
| 433 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 434 | struct fec __iomem *fecp = fep->fec.fecp; | ||
| 435 | |||
| 436 | return FR(fecp, ievent) & FR(fecp, imask); | ||
| 437 | } | ||
| 438 | |||
| 439 | static void clear_int_events(struct net_device *dev, u32 int_events) | ||
| 440 | { | ||
| 441 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 442 | struct fec __iomem *fecp = fep->fec.fecp; | ||
| 443 | |||
| 444 | FW(fecp, ievent, int_events); | ||
| 445 | } | ||
| 446 | |||
| 447 | static void ev_error(struct net_device *dev, u32 int_events) | ||
| 448 | { | ||
| 449 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 450 | |||
| 451 | dev_warn(fep->dev, "FEC ERROR(s) 0x%x\n", int_events); | ||
| 452 | } | ||
| 453 | |||
| 454 | static int get_regs(struct net_device *dev, void *p, int *sizep) | ||
| 455 | { | ||
| 456 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 457 | |||
| 458 | if (*sizep < sizeof(struct fec)) | ||
| 459 | return -EINVAL; | ||
| 460 | |||
| 461 | memcpy_fromio(p, fep->fec.fecp, sizeof(struct fec)); | ||
| 462 | |||
| 463 | return 0; | ||
| 464 | } | ||
| 465 | |||
| 466 | static int get_regs_len(struct net_device *dev) | ||
| 467 | { | ||
| 468 | return sizeof(struct fec); | ||
| 469 | } | ||
| 470 | |||
| 471 | static void tx_restart(struct net_device *dev) | ||
| 472 | { | ||
| 473 | /* nothing */ | ||
| 474 | } | ||
| 475 | |||
| 476 | /*************************************************************************/ | ||
| 477 | |||
| 478 | const struct fs_ops fs_fec_ops = { | ||
| 479 | .setup_data = setup_data, | ||
| 480 | .cleanup_data = cleanup_data, | ||
| 481 | .set_multicast_list = set_multicast_list, | ||
| 482 | .restart = restart, | ||
| 483 | .stop = stop, | ||
| 484 | .napi_clear_rx_event = napi_clear_rx_event, | ||
| 485 | .napi_enable_rx = napi_enable_rx, | ||
| 486 | .napi_disable_rx = napi_disable_rx, | ||
| 487 | .rx_bd_done = rx_bd_done, | ||
| 488 | .tx_kickstart = tx_kickstart, | ||
| 489 | .get_int_events = get_int_events, | ||
| 490 | .clear_int_events = clear_int_events, | ||
| 491 | .ev_error = ev_error, | ||
| 492 | .get_regs = get_regs, | ||
| 493 | .get_regs_len = get_regs_len, | ||
| 494 | .tx_restart = tx_restart, | ||
| 495 | .allocate_bd = allocate_bd, | ||
| 496 | .free_bd = free_bd, | ||
| 497 | }; | ||
| 498 | |||
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c new file mode 100644 index 00000000000..22a02a76706 --- /dev/null +++ b/drivers/net/fs_enet/mac-scc.c | |||
| @@ -0,0 +1,484 @@ | |||
| 1 | /* | ||
| 2 | * Ethernet on Serial Communications Controller (SCC) driver for Motorola MPC8xx and MPC82xx. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 Intracom S.A. | ||
| 5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
| 6 | * | ||
| 7 | * 2005 (c) MontaVista Software, Inc. | ||
| 8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
| 9 | * | ||
| 10 | * This file is licensed under the terms of the GNU General Public License | ||
| 11 | * version 2. This program is licensed "as is" without any warranty of any | ||
| 12 | * kind, whether express or implied. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/types.h> | ||
| 18 | #include <linux/string.h> | ||
| 19 | #include <linux/ptrace.h> | ||
| 20 | #include <linux/errno.h> | ||
| 21 | #include <linux/ioport.h> | ||
| 22 | #include <linux/interrupt.h> | ||
| 23 | #include <linux/init.h> | ||
| 24 | #include <linux/delay.h> | ||
| 25 | #include <linux/netdevice.h> | ||
| 26 | #include <linux/etherdevice.h> | ||
| 27 | #include <linux/skbuff.h> | ||
| 28 | #include <linux/spinlock.h> | ||
| 29 | #include <linux/mii.h> | ||
| 30 | #include <linux/ethtool.h> | ||
| 31 | #include <linux/bitops.h> | ||
| 32 | #include <linux/fs.h> | ||
| 33 | #include <linux/platform_device.h> | ||
| 34 | #include <linux/of_platform.h> | ||
| 35 | |||
| 36 | #include <asm/irq.h> | ||
| 37 | #include <asm/uaccess.h> | ||
| 38 | |||
| 39 | #ifdef CONFIG_8xx | ||
| 40 | #include <asm/8xx_immap.h> | ||
| 41 | #include <asm/pgtable.h> | ||
| 42 | #include <asm/mpc8xx.h> | ||
| 43 | #include <asm/cpm1.h> | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #include "fs_enet.h" | ||
| 47 | |||
| 48 | /*************************************************/ | ||
| 49 | #if defined(CONFIG_CPM1) | ||
| 50 | /* for a 8xx __raw_xxx's are sufficient */ | ||
| 51 | #define __fs_out32(addr, x) __raw_writel(x, addr) | ||
| 52 | #define __fs_out16(addr, x) __raw_writew(x, addr) | ||
| 53 | #define __fs_out8(addr, x) __raw_writeb(x, addr) | ||
| 54 | #define __fs_in32(addr) __raw_readl(addr) | ||
| 55 | #define __fs_in16(addr) __raw_readw(addr) | ||
| 56 | #define __fs_in8(addr) __raw_readb(addr) | ||
| 57 | #else | ||
| 58 | /* for others play it safe */ | ||
| 59 | #define __fs_out32(addr, x) out_be32(addr, x) | ||
| 60 | #define __fs_out16(addr, x) out_be16(addr, x) | ||
| 61 | #define __fs_in32(addr) in_be32(addr) | ||
| 62 | #define __fs_in16(addr) in_be16(addr) | ||
| 63 | #define __fs_out8(addr, x) out_8(addr, x) | ||
| 64 | #define __fs_in8(addr) in_8(addr) | ||
| 65 | #endif | ||
| 66 | |||
| 67 | /* write, read, set bits, clear bits */ | ||
| 68 | #define W32(_p, _m, _v) __fs_out32(&(_p)->_m, (_v)) | ||
| 69 | #define R32(_p, _m) __fs_in32(&(_p)->_m) | ||
| 70 | #define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) | ||
| 71 | #define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) | ||
| 72 | |||
| 73 | #define W16(_p, _m, _v) __fs_out16(&(_p)->_m, (_v)) | ||
| 74 | #define R16(_p, _m) __fs_in16(&(_p)->_m) | ||
| 75 | #define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) | ||
| 76 | #define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) | ||
| 77 | |||
| 78 | #define W8(_p, _m, _v) __fs_out8(&(_p)->_m, (_v)) | ||
| 79 | #define R8(_p, _m) __fs_in8(&(_p)->_m) | ||
| 80 | #define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) | ||
| 81 | #define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) | ||
| 82 | |||
| 83 | #define SCC_MAX_MULTICAST_ADDRS 64 | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Delay to wait for SCC reset command to complete (in us) | ||
| 87 | */ | ||
| 88 | #define SCC_RESET_DELAY 50 | ||
| 89 | |||
| 90 | static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op) | ||
| 91 | { | ||
| 92 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 93 | |||
| 94 | return cpm_command(fpi->cp_command, op); | ||
| 95 | } | ||
| 96 | |||
| 97 | static int do_pd_setup(struct fs_enet_private *fep) | ||
| 98 | { | ||
| 99 | struct platform_device *ofdev = to_platform_device(fep->dev); | ||
| 100 | |||
| 101 | fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); | ||
| 102 | if (fep->interrupt == NO_IRQ) | ||
| 103 | return -EINVAL; | ||
| 104 | |||
| 105 | fep->scc.sccp = of_iomap(ofdev->dev.of_node, 0); | ||
| 106 | if (!fep->scc.sccp) | ||
| 107 | return -EINVAL; | ||
| 108 | |||
| 109 | fep->scc.ep = of_iomap(ofdev->dev.of_node, 1); | ||
| 110 | if (!fep->scc.ep) { | ||
| 111 | iounmap(fep->scc.sccp); | ||
| 112 | return -EINVAL; | ||
| 113 | } | ||
| 114 | |||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | #define SCC_NAPI_RX_EVENT_MSK (SCCE_ENET_RXF | SCCE_ENET_RXB) | ||
| 119 | #define SCC_RX_EVENT (SCCE_ENET_RXF) | ||
| 120 | #define SCC_TX_EVENT (SCCE_ENET_TXB) | ||
| 121 | #define SCC_ERR_EVENT_MSK (SCCE_ENET_TXE | SCCE_ENET_BSY) | ||
| 122 | |||
| 123 | static int setup_data(struct net_device *dev) | ||
| 124 | { | ||
| 125 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 126 | |||
| 127 | do_pd_setup(fep); | ||
| 128 | |||
| 129 | fep->scc.hthi = 0; | ||
| 130 | fep->scc.htlo = 0; | ||
| 131 | |||
| 132 | fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK; | ||
| 133 | fep->ev_rx = SCC_RX_EVENT; | ||
| 134 | fep->ev_tx = SCC_TX_EVENT | SCCE_ENET_TXE; | ||
| 135 | fep->ev_err = SCC_ERR_EVENT_MSK; | ||
| 136 | |||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | static int allocate_bd(struct net_device *dev) | ||
| 141 | { | ||
| 142 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 143 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 144 | |||
| 145 | fep->ring_mem_addr = cpm_dpalloc((fpi->tx_ring + fpi->rx_ring) * | ||
| 146 | sizeof(cbd_t), 8); | ||
| 147 | if (IS_ERR_VALUE(fep->ring_mem_addr)) | ||
| 148 | return -ENOMEM; | ||
| 149 | |||
| 150 | fep->ring_base = (void __iomem __force*) | ||
| 151 | cpm_dpram_addr(fep->ring_mem_addr); | ||
| 152 | |||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | |||
| 156 | static void free_bd(struct net_device *dev) | ||
| 157 | { | ||
| 158 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 159 | |||
| 160 | if (fep->ring_base) | ||
| 161 | cpm_dpfree(fep->ring_mem_addr); | ||
| 162 | } | ||
| 163 | |||
| 164 | static void cleanup_data(struct net_device *dev) | ||
| 165 | { | ||
| 166 | /* nothing */ | ||
| 167 | } | ||
| 168 | |||
| 169 | static void set_promiscuous_mode(struct net_device *dev) | ||
| 170 | { | ||
| 171 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 172 | scc_t __iomem *sccp = fep->scc.sccp; | ||
| 173 | |||
| 174 | S16(sccp, scc_psmr, SCC_PSMR_PRO); | ||
| 175 | } | ||
| 176 | |||
| 177 | static void set_multicast_start(struct net_device *dev) | ||
| 178 | { | ||
| 179 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 180 | scc_enet_t __iomem *ep = fep->scc.ep; | ||
| 181 | |||
| 182 | W16(ep, sen_gaddr1, 0); | ||
| 183 | W16(ep, sen_gaddr2, 0); | ||
| 184 | W16(ep, sen_gaddr3, 0); | ||
| 185 | W16(ep, sen_gaddr4, 0); | ||
| 186 | } | ||
| 187 | |||
| 188 | static void set_multicast_one(struct net_device *dev, const u8 * mac) | ||
| 189 | { | ||
| 190 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 191 | scc_enet_t __iomem *ep = fep->scc.ep; | ||
| 192 | u16 taddrh, taddrm, taddrl; | ||
| 193 | |||
| 194 | taddrh = ((u16) mac[5] << 8) | mac[4]; | ||
| 195 | taddrm = ((u16) mac[3] << 8) | mac[2]; | ||
| 196 | taddrl = ((u16) mac[1] << 8) | mac[0]; | ||
| 197 | |||
| 198 | W16(ep, sen_taddrh, taddrh); | ||
| 199 | W16(ep, sen_taddrm, taddrm); | ||
| 200 | W16(ep, sen_taddrl, taddrl); | ||
| 201 | scc_cr_cmd(fep, CPM_CR_SET_GADDR); | ||
| 202 | } | ||
| 203 | |||
| 204 | static void set_multicast_finish(struct net_device *dev) | ||
| 205 | { | ||
| 206 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 207 | scc_t __iomem *sccp = fep->scc.sccp; | ||
| 208 | scc_enet_t __iomem *ep = fep->scc.ep; | ||
| 209 | |||
| 210 | /* clear promiscuous always */ | ||
| 211 | C16(sccp, scc_psmr, SCC_PSMR_PRO); | ||
| 212 | |||
| 213 | /* if all multi or too many multicasts; just enable all */ | ||
| 214 | if ((dev->flags & IFF_ALLMULTI) != 0 || | ||
| 215 | netdev_mc_count(dev) > SCC_MAX_MULTICAST_ADDRS) { | ||
| 216 | |||
| 217 | W16(ep, sen_gaddr1, 0xffff); | ||
| 218 | W16(ep, sen_gaddr2, 0xffff); | ||
| 219 | W16(ep, sen_gaddr3, 0xffff); | ||
| 220 | W16(ep, sen_gaddr4, 0xffff); | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | static void set_multicast_list(struct net_device *dev) | ||
| 225 | { | ||
| 226 | struct netdev_hw_addr *ha; | ||
| 227 | |||
| 228 | if ((dev->flags & IFF_PROMISC) == 0) { | ||
| 229 | set_multicast_start(dev); | ||
| 230 | netdev_for_each_mc_addr(ha, dev) | ||
| 231 | set_multicast_one(dev, ha->addr); | ||
| 232 | set_multicast_finish(dev); | ||
| 233 | } else | ||
| 234 | set_promiscuous_mode(dev); | ||
| 235 | } | ||
| 236 | |||
| 237 | /* | ||
| 238 | * This function is called to start or restart the FEC during a link | ||
| 239 | * change. This only happens when switching between half and full | ||
| 240 | * duplex. | ||
| 241 | */ | ||
| 242 | static void restart(struct net_device *dev) | ||
| 243 | { | ||
| 244 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 245 | scc_t __iomem *sccp = fep->scc.sccp; | ||
| 246 | scc_enet_t __iomem *ep = fep->scc.ep; | ||
| 247 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 248 | u16 paddrh, paddrm, paddrl; | ||
| 249 | const unsigned char *mac; | ||
| 250 | int i; | ||
| 251 | |||
| 252 | C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
| 253 | |||
| 254 | /* clear everything (slow & steady does it) */ | ||
| 255 | for (i = 0; i < sizeof(*ep); i++) | ||
| 256 | __fs_out8((u8 __iomem *)ep + i, 0); | ||
| 257 | |||
| 258 | /* point to bds */ | ||
| 259 | W16(ep, sen_genscc.scc_rbase, fep->ring_mem_addr); | ||
| 260 | W16(ep, sen_genscc.scc_tbase, | ||
| 261 | fep->ring_mem_addr + sizeof(cbd_t) * fpi->rx_ring); | ||
| 262 | |||
| 263 | /* Initialize function code registers for big-endian. | ||
| 264 | */ | ||
| 265 | #ifndef CONFIG_NOT_COHERENT_CACHE | ||
| 266 | W8(ep, sen_genscc.scc_rfcr, SCC_EB | SCC_GBL); | ||
| 267 | W8(ep, sen_genscc.scc_tfcr, SCC_EB | SCC_GBL); | ||
| 268 | #else | ||
| 269 | W8(ep, sen_genscc.scc_rfcr, SCC_EB); | ||
| 270 | W8(ep, sen_genscc.scc_tfcr, SCC_EB); | ||
| 271 | #endif | ||
| 272 | |||
| 273 | /* Set maximum bytes per receive buffer. | ||
| 274 | * This appears to be an Ethernet frame size, not the buffer | ||
| 275 | * fragment size. It must be a multiple of four. | ||
| 276 | */ | ||
| 277 | W16(ep, sen_genscc.scc_mrblr, 0x5f0); | ||
| 278 | |||
| 279 | /* Set CRC preset and mask. | ||
| 280 | */ | ||
| 281 | W32(ep, sen_cpres, 0xffffffff); | ||
| 282 | W32(ep, sen_cmask, 0xdebb20e3); | ||
| 283 | |||
| 284 | W32(ep, sen_crcec, 0); /* CRC Error counter */ | ||
| 285 | W32(ep, sen_alec, 0); /* alignment error counter */ | ||
| 286 | W32(ep, sen_disfc, 0); /* discard frame counter */ | ||
| 287 | |||
| 288 | W16(ep, sen_pads, 0x8888); /* Tx short frame pad character */ | ||
| 289 | W16(ep, sen_retlim, 15); /* Retry limit threshold */ | ||
| 290 | |||
| 291 | W16(ep, sen_maxflr, 0x5ee); /* maximum frame length register */ | ||
| 292 | |||
| 293 | W16(ep, sen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ | ||
| 294 | |||
| 295 | W16(ep, sen_maxd1, 0x000005f0); /* maximum DMA1 length */ | ||
| 296 | W16(ep, sen_maxd2, 0x000005f0); /* maximum DMA2 length */ | ||
| 297 | |||
| 298 | /* Clear hash tables. | ||
| 299 | */ | ||
| 300 | W16(ep, sen_gaddr1, 0); | ||
| 301 | W16(ep, sen_gaddr2, 0); | ||
| 302 | W16(ep, sen_gaddr3, 0); | ||
| 303 | W16(ep, sen_gaddr4, 0); | ||
| 304 | W16(ep, sen_iaddr1, 0); | ||
| 305 | W16(ep, sen_iaddr2, 0); | ||
| 306 | W16(ep, sen_iaddr3, 0); | ||
| 307 | W16(ep, sen_iaddr4, 0); | ||
| 308 | |||
| 309 | /* set address | ||
| 310 | */ | ||
| 311 | mac = dev->dev_addr; | ||
| 312 | paddrh = ((u16) mac[5] << 8) | mac[4]; | ||
| 313 | paddrm = ((u16) mac[3] << 8) | mac[2]; | ||
| 314 | paddrl = ((u16) mac[1] << 8) | mac[0]; | ||
| 315 | |||
| 316 | W16(ep, sen_paddrh, paddrh); | ||
| 317 | W16(ep, sen_paddrm, paddrm); | ||
| 318 | W16(ep, sen_paddrl, paddrl); | ||
| 319 | |||
| 320 | W16(ep, sen_pper, 0); | ||
| 321 | W16(ep, sen_taddrl, 0); | ||
| 322 | W16(ep, sen_taddrm, 0); | ||
| 323 | W16(ep, sen_taddrh, 0); | ||
| 324 | |||
| 325 | fs_init_bds(dev); | ||
| 326 | |||
| 327 | scc_cr_cmd(fep, CPM_CR_INIT_TRX); | ||
| 328 | |||
| 329 | W16(sccp, scc_scce, 0xffff); | ||
| 330 | |||
| 331 | /* Enable interrupts we wish to service. | ||
| 332 | */ | ||
| 333 | W16(sccp, scc_sccm, SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); | ||
| 334 | |||
| 335 | /* Set GSMR_H to enable all normal operating modes. | ||
| 336 | * Set GSMR_L to enable Ethernet to MC68160. | ||
| 337 | */ | ||
| 338 | W32(sccp, scc_gsmrh, 0); | ||
| 339 | W32(sccp, scc_gsmrl, | ||
| 340 | SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | | ||
| 341 | SCC_GSMRL_MODE_ENET); | ||
| 342 | |||
| 343 | /* Set sync/delimiters. | ||
| 344 | */ | ||
| 345 | W16(sccp, scc_dsr, 0xd555); | ||
| 346 | |||
| 347 | /* Set processing mode. Use Ethernet CRC, catch broadcast, and | ||
| 348 | * start frame search 22 bit times after RENA. | ||
| 349 | */ | ||
| 350 | W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22); | ||
| 351 | |||
| 352 | /* Set full duplex mode if needed */ | ||
| 353 | if (fep->phydev->duplex) | ||
| 354 | S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE); | ||
| 355 | |||
| 356 | S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
| 357 | } | ||
| 358 | |||
| 359 | static void stop(struct net_device *dev) | ||
| 360 | { | ||
| 361 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 362 | scc_t __iomem *sccp = fep->scc.sccp; | ||
| 363 | int i; | ||
| 364 | |||
| 365 | for (i = 0; (R16(sccp, scc_sccm) == 0) && i < SCC_RESET_DELAY; i++) | ||
| 366 | udelay(1); | ||
| 367 | |||
| 368 | if (i == SCC_RESET_DELAY) | ||
| 369 | dev_warn(fep->dev, "SCC timeout on graceful transmit stop\n"); | ||
| 370 | |||
| 371 | W16(sccp, scc_sccm, 0); | ||
| 372 | C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
| 373 | |||
| 374 | fs_cleanup_bds(dev); | ||
| 375 | } | ||
| 376 | |||
| 377 | static void napi_clear_rx_event(struct net_device *dev) | ||
| 378 | { | ||
| 379 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 380 | scc_t __iomem *sccp = fep->scc.sccp; | ||
| 381 | |||
| 382 | W16(sccp, scc_scce, SCC_NAPI_RX_EVENT_MSK); | ||
| 383 | } | ||
| 384 | |||
| 385 | static void napi_enable_rx(struct net_device *dev) | ||
| 386 | { | ||
| 387 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 388 | scc_t __iomem *sccp = fep->scc.sccp; | ||
| 389 | |||
| 390 | S16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); | ||
| 391 | } | ||
| 392 | |||
| 393 | static void napi_disable_rx(struct net_device *dev) | ||
| 394 | { | ||
| 395 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 396 | scc_t __iomem *sccp = fep->scc.sccp; | ||
| 397 | |||
| 398 | C16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); | ||
| 399 | } | ||
| 400 | |||
| 401 | static void rx_bd_done(struct net_device *dev) | ||
| 402 | { | ||
| 403 | /* nothing */ | ||
| 404 | } | ||
| 405 | |||
| 406 | static void tx_kickstart(struct net_device *dev) | ||
| 407 | { | ||
| 408 | /* nothing */ | ||
| 409 | } | ||
| 410 | |||
| 411 | static u32 get_int_events(struct net_device *dev) | ||
| 412 | { | ||
| 413 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 414 | scc_t __iomem *sccp = fep->scc.sccp; | ||
| 415 | |||
| 416 | return (u32) R16(sccp, scc_scce); | ||
| 417 | } | ||
| 418 | |||
| 419 | static void clear_int_events(struct net_device *dev, u32 int_events) | ||
| 420 | { | ||
| 421 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 422 | scc_t __iomem *sccp = fep->scc.sccp; | ||
| 423 | |||
| 424 | W16(sccp, scc_scce, int_events & 0xffff); | ||
| 425 | } | ||
| 426 | |||
| 427 | static void ev_error(struct net_device *dev, u32 int_events) | ||
| 428 | { | ||
| 429 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 430 | |||
| 431 | dev_warn(fep->dev, "SCC ERROR(s) 0x%x\n", int_events); | ||
| 432 | } | ||
| 433 | |||
| 434 | static int get_regs(struct net_device *dev, void *p, int *sizep) | ||
| 435 | { | ||
| 436 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 437 | |||
| 438 | if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t __iomem *)) | ||
| 439 | return -EINVAL; | ||
| 440 | |||
| 441 | memcpy_fromio(p, fep->scc.sccp, sizeof(scc_t)); | ||
| 442 | p = (char *)p + sizeof(scc_t); | ||
| 443 | |||
| 444 | memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t __iomem *)); | ||
| 445 | |||
| 446 | return 0; | ||
| 447 | } | ||
| 448 | |||
| 449 | static int get_regs_len(struct net_device *dev) | ||
| 450 | { | ||
| 451 | return sizeof(scc_t) + sizeof(scc_enet_t __iomem *); | ||
| 452 | } | ||
| 453 | |||
| 454 | static void tx_restart(struct net_device *dev) | ||
| 455 | { | ||
| 456 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 457 | |||
| 458 | scc_cr_cmd(fep, CPM_CR_RESTART_TX); | ||
| 459 | } | ||
| 460 | |||
| 461 | |||
| 462 | |||
| 463 | /*************************************************************************/ | ||
| 464 | |||
| 465 | const struct fs_ops fs_scc_ops = { | ||
| 466 | .setup_data = setup_data, | ||
| 467 | .cleanup_data = cleanup_data, | ||
| 468 | .set_multicast_list = set_multicast_list, | ||
| 469 | .restart = restart, | ||
| 470 | .stop = stop, | ||
| 471 | .napi_clear_rx_event = napi_clear_rx_event, | ||
| 472 | .napi_enable_rx = napi_enable_rx, | ||
| 473 | .napi_disable_rx = napi_disable_rx, | ||
| 474 | .rx_bd_done = rx_bd_done, | ||
| 475 | .tx_kickstart = tx_kickstart, | ||
| 476 | .get_int_events = get_int_events, | ||
| 477 | .clear_int_events = clear_int_events, | ||
| 478 | .ev_error = ev_error, | ||
| 479 | .get_regs = get_regs, | ||
| 480 | .get_regs_len = get_regs_len, | ||
| 481 | .tx_restart = tx_restart, | ||
| 482 | .allocate_bd = allocate_bd, | ||
| 483 | .free_bd = free_bd, | ||
| 484 | }; | ||
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c new file mode 100644 index 00000000000..b09270b5d0a --- /dev/null +++ b/drivers/net/fs_enet/mii-bitbang.c | |||
| @@ -0,0 +1,246 @@ | |||
| 1 | /* | ||
| 2 | * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 Intracom S.A. | ||
| 5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
| 6 | * | ||
| 7 | * 2005 (c) MontaVista Software, Inc. | ||
| 8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
| 9 | * | ||
| 10 | * This file is licensed under the terms of the GNU General Public License | ||
| 11 | * version 2. This program is licensed "as is" without any warranty of any | ||
| 12 | * kind, whether express or implied. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/ioport.h> | ||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/netdevice.h> | ||
| 21 | #include <linux/etherdevice.h> | ||
| 22 | #include <linux/mii.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | #include <linux/mdio-bitbang.h> | ||
| 25 | #include <linux/of_mdio.h> | ||
| 26 | #include <linux/of_platform.h> | ||
| 27 | |||
| 28 | #include "fs_enet.h" | ||
| 29 | |||
| 30 | struct bb_info { | ||
| 31 | struct mdiobb_ctrl ctrl; | ||
| 32 | __be32 __iomem *dir; | ||
| 33 | __be32 __iomem *dat; | ||
| 34 | u32 mdio_msk; | ||
| 35 | u32 mdc_msk; | ||
| 36 | }; | ||
| 37 | |||
| 38 | /* FIXME: If any other users of GPIO crop up, then these will have to | ||
| 39 | * have some sort of global synchronization to avoid races with other | ||
| 40 | * pins on the same port. The ideal solution would probably be to | ||
| 41 | * bind the ports to a GPIO driver, and have this be a client of it. | ||
| 42 | */ | ||
| 43 | static inline void bb_set(u32 __iomem *p, u32 m) | ||
| 44 | { | ||
| 45 | out_be32(p, in_be32(p) | m); | ||
| 46 | } | ||
| 47 | |||
| 48 | static inline void bb_clr(u32 __iomem *p, u32 m) | ||
| 49 | { | ||
| 50 | out_be32(p, in_be32(p) & ~m); | ||
| 51 | } | ||
| 52 | |||
| 53 | static inline int bb_read(u32 __iomem *p, u32 m) | ||
| 54 | { | ||
| 55 | return (in_be32(p) & m) != 0; | ||
| 56 | } | ||
| 57 | |||
| 58 | static inline void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) | ||
| 59 | { | ||
| 60 | struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); | ||
| 61 | |||
| 62 | if (dir) | ||
| 63 | bb_set(bitbang->dir, bitbang->mdio_msk); | ||
| 64 | else | ||
| 65 | bb_clr(bitbang->dir, bitbang->mdio_msk); | ||
| 66 | |||
| 67 | /* Read back to flush the write. */ | ||
| 68 | in_be32(bitbang->dir); | ||
| 69 | } | ||
| 70 | |||
| 71 | static inline int mdio_read(struct mdiobb_ctrl *ctrl) | ||
| 72 | { | ||
| 73 | struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); | ||
| 74 | return bb_read(bitbang->dat, bitbang->mdio_msk); | ||
| 75 | } | ||
| 76 | |||
| 77 | static inline void mdio(struct mdiobb_ctrl *ctrl, int what) | ||
| 78 | { | ||
| 79 | struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); | ||
| 80 | |||
| 81 | if (what) | ||
| 82 | bb_set(bitbang->dat, bitbang->mdio_msk); | ||
| 83 | else | ||
| 84 | bb_clr(bitbang->dat, bitbang->mdio_msk); | ||
| 85 | |||
| 86 | /* Read back to flush the write. */ | ||
| 87 | in_be32(bitbang->dat); | ||
| 88 | } | ||
| 89 | |||
| 90 | static inline void mdc(struct mdiobb_ctrl *ctrl, int what) | ||
| 91 | { | ||
| 92 | struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); | ||
| 93 | |||
| 94 | if (what) | ||
| 95 | bb_set(bitbang->dat, bitbang->mdc_msk); | ||
| 96 | else | ||
| 97 | bb_clr(bitbang->dat, bitbang->mdc_msk); | ||
| 98 | |||
| 99 | /* Read back to flush the write. */ | ||
| 100 | in_be32(bitbang->dat); | ||
| 101 | } | ||
| 102 | |||
| 103 | static struct mdiobb_ops bb_ops = { | ||
| 104 | .owner = THIS_MODULE, | ||
| 105 | .set_mdc = mdc, | ||
| 106 | .set_mdio_dir = mdio_dir, | ||
| 107 | .set_mdio_data = mdio, | ||
| 108 | .get_mdio_data = mdio_read, | ||
| 109 | }; | ||
| 110 | |||
| 111 | static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, | ||
| 112 | struct device_node *np) | ||
| 113 | { | ||
| 114 | struct resource res; | ||
| 115 | const u32 *data; | ||
| 116 | int mdio_pin, mdc_pin, len; | ||
| 117 | struct bb_info *bitbang = bus->priv; | ||
| 118 | |||
| 119 | int ret = of_address_to_resource(np, 0, &res); | ||
| 120 | if (ret) | ||
| 121 | return ret; | ||
| 122 | |||
| 123 | if (resource_size(&res) <= 13) | ||
| 124 | return -ENODEV; | ||
| 125 | |||
| 126 | /* This should really encode the pin number as well, but all | ||
| 127 | * we get is an int, and the odds of multiple bitbang mdio buses | ||
| 128 | * is low enough that it's not worth going too crazy. | ||
| 129 | */ | ||
| 130 | snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); | ||
| 131 | |||
| 132 | data = of_get_property(np, "fsl,mdio-pin", &len); | ||
| 133 | if (!data || len != 4) | ||
| 134 | return -ENODEV; | ||
| 135 | mdio_pin = *data; | ||
| 136 | |||
| 137 | data = of_get_property(np, "fsl,mdc-pin", &len); | ||
| 138 | if (!data || len != 4) | ||
| 139 | return -ENODEV; | ||
| 140 | mdc_pin = *data; | ||
| 141 | |||
| 142 | bitbang->dir = ioremap(res.start, resource_size(&res)); | ||
| 143 | if (!bitbang->dir) | ||
| 144 | return -ENOMEM; | ||
| 145 | |||
| 146 | bitbang->dat = bitbang->dir + 4; | ||
| 147 | bitbang->mdio_msk = 1 << (31 - mdio_pin); | ||
| 148 | bitbang->mdc_msk = 1 << (31 - mdc_pin); | ||
| 149 | |||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev) | ||
| 154 | { | ||
| 155 | struct mii_bus *new_bus; | ||
| 156 | struct bb_info *bitbang; | ||
| 157 | int ret = -ENOMEM; | ||
| 158 | |||
| 159 | bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); | ||
| 160 | if (!bitbang) | ||
| 161 | goto out; | ||
| 162 | |||
| 163 | bitbang->ctrl.ops = &bb_ops; | ||
| 164 | |||
| 165 | new_bus = alloc_mdio_bitbang(&bitbang->ctrl); | ||
| 166 | if (!new_bus) | ||
| 167 | goto out_free_priv; | ||
| 168 | |||
| 169 | new_bus->name = "CPM2 Bitbanged MII", | ||
| 170 | |||
| 171 | ret = fs_mii_bitbang_init(new_bus, ofdev->dev.of_node); | ||
| 172 | if (ret) | ||
| 173 | goto out_free_bus; | ||
| 174 | |||
| 175 | new_bus->phy_mask = ~0; | ||
| 176 | new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); | ||
| 177 | if (!new_bus->irq) | ||
| 178 | goto out_unmap_regs; | ||
| 179 | |||
| 180 | new_bus->parent = &ofdev->dev; | ||
| 181 | dev_set_drvdata(&ofdev->dev, new_bus); | ||
| 182 | |||
| 183 | ret = of_mdiobus_register(new_bus, ofdev->dev.of_node); | ||
| 184 | if (ret) | ||
| 185 | goto out_free_irqs; | ||
| 186 | |||
| 187 | return 0; | ||
| 188 | |||
| 189 | out_free_irqs: | ||
| 190 | dev_set_drvdata(&ofdev->dev, NULL); | ||
| 191 | kfree(new_bus->irq); | ||
| 192 | out_unmap_regs: | ||
| 193 | iounmap(bitbang->dir); | ||
| 194 | out_free_bus: | ||
| 195 | free_mdio_bitbang(new_bus); | ||
| 196 | out_free_priv: | ||
| 197 | kfree(bitbang); | ||
| 198 | out: | ||
| 199 | return ret; | ||
| 200 | } | ||
| 201 | |||
| 202 | static int fs_enet_mdio_remove(struct platform_device *ofdev) | ||
| 203 | { | ||
| 204 | struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); | ||
| 205 | struct bb_info *bitbang = bus->priv; | ||
| 206 | |||
| 207 | mdiobus_unregister(bus); | ||
| 208 | dev_set_drvdata(&ofdev->dev, NULL); | ||
| 209 | kfree(bus->irq); | ||
| 210 | free_mdio_bitbang(bus); | ||
| 211 | iounmap(bitbang->dir); | ||
| 212 | kfree(bitbang); | ||
| 213 | |||
| 214 | return 0; | ||
| 215 | } | ||
| 216 | |||
| 217 | static struct of_device_id fs_enet_mdio_bb_match[] = { | ||
| 218 | { | ||
| 219 | .compatible = "fsl,cpm2-mdio-bitbang", | ||
| 220 | }, | ||
| 221 | {}, | ||
| 222 | }; | ||
| 223 | MODULE_DEVICE_TABLE(of, fs_enet_mdio_bb_match); | ||
| 224 | |||
| 225 | static struct platform_driver fs_enet_bb_mdio_driver = { | ||
| 226 | .driver = { | ||
| 227 | .name = "fsl-bb-mdio", | ||
| 228 | .owner = THIS_MODULE, | ||
| 229 | .of_match_table = fs_enet_mdio_bb_match, | ||
| 230 | }, | ||
| 231 | .probe = fs_enet_mdio_probe, | ||
| 232 | .remove = fs_enet_mdio_remove, | ||
| 233 | }; | ||
| 234 | |||
| 235 | static int fs_enet_mdio_bb_init(void) | ||
| 236 | { | ||
| 237 | return platform_driver_register(&fs_enet_bb_mdio_driver); | ||
| 238 | } | ||
| 239 | |||
| 240 | static void fs_enet_mdio_bb_exit(void) | ||
| 241 | { | ||
| 242 | platform_driver_unregister(&fs_enet_bb_mdio_driver); | ||
| 243 | } | ||
| 244 | |||
| 245 | module_init(fs_enet_mdio_bb_init); | ||
| 246 | module_exit(fs_enet_mdio_bb_exit); | ||
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c new file mode 100644 index 00000000000..e0e9d6c35d8 --- /dev/null +++ b/drivers/net/fs_enet/mii-fec.c | |||
| @@ -0,0 +1,251 @@ | |||
| 1 | /* | ||
| 2 | * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 Intracom S.A. | ||
| 5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
| 6 | * | ||
| 7 | * 2005 (c) MontaVista Software, Inc. | ||
| 8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
| 9 | * | ||
| 10 | * This file is licensed under the terms of the GNU General Public License | ||
| 11 | * version 2. This program is licensed "as is" without any warranty of any | ||
| 12 | * kind, whether express or implied. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/types.h> | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/string.h> | ||
| 19 | #include <linux/ptrace.h> | ||
| 20 | #include <linux/errno.h> | ||
| 21 | #include <linux/ioport.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/interrupt.h> | ||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/delay.h> | ||
| 26 | #include <linux/netdevice.h> | ||
| 27 | #include <linux/etherdevice.h> | ||
| 28 | #include <linux/skbuff.h> | ||
| 29 | #include <linux/spinlock.h> | ||
| 30 | #include <linux/mii.h> | ||
| 31 | #include <linux/ethtool.h> | ||
| 32 | #include <linux/bitops.h> | ||
| 33 | #include <linux/platform_device.h> | ||
| 34 | #include <linux/of_platform.h> | ||
| 35 | |||
| 36 | #include <asm/pgtable.h> | ||
| 37 | #include <asm/irq.h> | ||
| 38 | #include <asm/uaccess.h> | ||
| 39 | #include <asm/mpc5xxx.h> | ||
| 40 | |||
| 41 | #include "fs_enet.h" | ||
| 42 | #include "fec.h" | ||
| 43 | |||
| 44 | /* Make MII read/write commands for the FEC. | ||
| 45 | */ | ||
| 46 | #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) | ||
| 47 | #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) | ||
| 48 | #define mk_mii_end 0 | ||
| 49 | |||
| 50 | #define FEC_MII_LOOPS 10000 | ||
| 51 | |||
| 52 | static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) | ||
| 53 | { | ||
| 54 | struct fec_info* fec = bus->priv; | ||
| 55 | struct fec __iomem *fecp = fec->fecp; | ||
| 56 | int i, ret = -1; | ||
| 57 | |||
| 58 | BUG_ON((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0); | ||
| 59 | |||
| 60 | /* Add PHY address to register command. */ | ||
| 61 | out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_read(location)); | ||
| 62 | |||
| 63 | for (i = 0; i < FEC_MII_LOOPS; i++) | ||
| 64 | if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0) | ||
| 65 | break; | ||
| 66 | |||
| 67 | if (i < FEC_MII_LOOPS) { | ||
| 68 | out_be32(&fecp->fec_ievent, FEC_ENET_MII); | ||
| 69 | ret = in_be32(&fecp->fec_mii_data) & 0xffff; | ||
| 70 | } | ||
| 71 | |||
| 72 | return ret; | ||
| 73 | } | ||
| 74 | |||
| 75 | static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) | ||
| 76 | { | ||
| 77 | struct fec_info* fec = bus->priv; | ||
| 78 | struct fec __iomem *fecp = fec->fecp; | ||
| 79 | int i; | ||
| 80 | |||
| 81 | /* this must never happen */ | ||
| 82 | BUG_ON((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0); | ||
| 83 | |||
| 84 | /* Add PHY address to register command. */ | ||
| 85 | out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_write(location, val)); | ||
| 86 | |||
| 87 | for (i = 0; i < FEC_MII_LOOPS; i++) | ||
| 88 | if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0) | ||
| 89 | break; | ||
| 90 | |||
| 91 | if (i < FEC_MII_LOOPS) | ||
| 92 | out_be32(&fecp->fec_ievent, FEC_ENET_MII); | ||
| 93 | |||
| 94 | return 0; | ||
| 95 | |||
| 96 | } | ||
| 97 | |||
| 98 | static int fs_enet_fec_mii_reset(struct mii_bus *bus) | ||
| 99 | { | ||
| 100 | /* nothing here - for now */ | ||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | |||
| 104 | static struct of_device_id fs_enet_mdio_fec_match[]; | ||
| 105 | static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev) | ||
| 106 | { | ||
| 107 | const struct of_device_id *match; | ||
| 108 | struct resource res; | ||
| 109 | struct mii_bus *new_bus; | ||
| 110 | struct fec_info *fec; | ||
| 111 | int (*get_bus_freq)(struct device_node *); | ||
| 112 | int ret = -ENOMEM, clock, speed; | ||
| 113 | |||
| 114 | match = of_match_device(fs_enet_mdio_fec_match, &ofdev->dev); | ||
| 115 | if (!match) | ||
| 116 | return -EINVAL; | ||
| 117 | get_bus_freq = match->data; | ||
| 118 | |||
| 119 | new_bus = mdiobus_alloc(); | ||
| 120 | if (!new_bus) | ||
| 121 | goto out; | ||
| 122 | |||
| 123 | fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL); | ||
| 124 | if (!fec) | ||
| 125 | goto out_mii; | ||
| 126 | |||
| 127 | new_bus->priv = fec; | ||
| 128 | new_bus->name = "FEC MII Bus"; | ||
| 129 | new_bus->read = &fs_enet_fec_mii_read; | ||
| 130 | new_bus->write = &fs_enet_fec_mii_write; | ||
| 131 | new_bus->reset = &fs_enet_fec_mii_reset; | ||
| 132 | |||
| 133 | ret = of_address_to_resource(ofdev->dev.of_node, 0, &res); | ||
| 134 | if (ret) | ||
| 135 | goto out_res; | ||
| 136 | |||
| 137 | snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", res.start); | ||
| 138 | |||
| 139 | fec->fecp = ioremap(res.start, resource_size(&res)); | ||
| 140 | if (!fec->fecp) | ||
| 141 | goto out_fec; | ||
| 142 | |||
| 143 | if (get_bus_freq) { | ||
| 144 | clock = get_bus_freq(ofdev->dev.of_node); | ||
| 145 | if (!clock) { | ||
| 146 | /* Use maximum divider if clock is unknown */ | ||
| 147 | dev_warn(&ofdev->dev, "could not determine IPS clock\n"); | ||
| 148 | clock = 0x3F * 5000000; | ||
| 149 | } | ||
| 150 | } else | ||
| 151 | clock = ppc_proc_freq; | ||
| 152 | |||
| 153 | /* | ||
| 154 | * Scale for a MII clock <= 2.5 MHz | ||
| 155 | * Note that only 6 bits (25:30) are available for MII speed. | ||
| 156 | */ | ||
| 157 | speed = (clock + 4999999) / 5000000; | ||
| 158 | if (speed > 0x3F) { | ||
| 159 | speed = 0x3F; | ||
| 160 | dev_err(&ofdev->dev, | ||
| 161 | "MII clock (%d Hz) exceeds max (2.5 MHz)\n", | ||
| 162 | clock / speed); | ||
| 163 | } | ||
| 164 | |||
| 165 | fec->mii_speed = speed << 1; | ||
| 166 | |||
| 167 | setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); | ||
| 168 | setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | | ||
| 169 | FEC_ECNTRL_ETHER_EN); | ||
| 170 | out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII); | ||
| 171 | clrsetbits_be32(&fec->fecp->fec_mii_speed, 0x7E, fec->mii_speed); | ||
| 172 | |||
| 173 | new_bus->phy_mask = ~0; | ||
| 174 | new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); | ||
| 175 | if (!new_bus->irq) | ||
| 176 | goto out_unmap_regs; | ||
| 177 | |||
| 178 | new_bus->parent = &ofdev->dev; | ||
| 179 | dev_set_drvdata(&ofdev->dev, new_bus); | ||
| 180 | |||
| 181 | ret = of_mdiobus_register(new_bus, ofdev->dev.of_node); | ||
| 182 | if (ret) | ||
| 183 | goto out_free_irqs; | ||
| 184 | |||
| 185 | return 0; | ||
| 186 | |||
| 187 | out_free_irqs: | ||
| 188 | dev_set_drvdata(&ofdev->dev, NULL); | ||
| 189 | kfree(new_bus->irq); | ||
| 190 | out_unmap_regs: | ||
| 191 | iounmap(fec->fecp); | ||
| 192 | out_res: | ||
| 193 | out_fec: | ||
| 194 | kfree(fec); | ||
| 195 | out_mii: | ||
| 196 | mdiobus_free(new_bus); | ||
| 197 | out: | ||
| 198 | return ret; | ||
| 199 | } | ||
| 200 | |||
| 201 | static int fs_enet_mdio_remove(struct platform_device *ofdev) | ||
| 202 | { | ||
| 203 | struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); | ||
| 204 | struct fec_info *fec = bus->priv; | ||
| 205 | |||
| 206 | mdiobus_unregister(bus); | ||
| 207 | dev_set_drvdata(&ofdev->dev, NULL); | ||
| 208 | kfree(bus->irq); | ||
| 209 | iounmap(fec->fecp); | ||
| 210 | kfree(fec); | ||
| 211 | mdiobus_free(bus); | ||
| 212 | |||
| 213 | return 0; | ||
| 214 | } | ||
| 215 | |||
| 216 | static struct of_device_id fs_enet_mdio_fec_match[] = { | ||
| 217 | { | ||
| 218 | .compatible = "fsl,pq1-fec-mdio", | ||
| 219 | }, | ||
| 220 | #if defined(CONFIG_PPC_MPC512x) | ||
| 221 | { | ||
| 222 | .compatible = "fsl,mpc5121-fec-mdio", | ||
| 223 | .data = mpc5xxx_get_bus_frequency, | ||
| 224 | }, | ||
| 225 | #endif | ||
| 226 | {}, | ||
| 227 | }; | ||
| 228 | MODULE_DEVICE_TABLE(of, fs_enet_mdio_fec_match); | ||
| 229 | |||
| 230 | static struct platform_driver fs_enet_fec_mdio_driver = { | ||
| 231 | .driver = { | ||
| 232 | .name = "fsl-fec-mdio", | ||
| 233 | .owner = THIS_MODULE, | ||
| 234 | .of_match_table = fs_enet_mdio_fec_match, | ||
| 235 | }, | ||
| 236 | .probe = fs_enet_mdio_probe, | ||
| 237 | .remove = fs_enet_mdio_remove, | ||
| 238 | }; | ||
| 239 | |||
| 240 | static int fs_enet_mdio_fec_init(void) | ||
| 241 | { | ||
| 242 | return platform_driver_register(&fs_enet_fec_mdio_driver); | ||
| 243 | } | ||
| 244 | |||
| 245 | static void fs_enet_mdio_fec_exit(void) | ||
| 246 | { | ||
| 247 | platform_driver_unregister(&fs_enet_fec_mdio_driver); | ||
| 248 | } | ||
| 249 | |||
| 250 | module_init(fs_enet_mdio_fec_init); | ||
| 251 | module_exit(fs_enet_mdio_fec_exit); | ||
