blob: c6770377ef8746c384d815d5067a469d872a3b59 [file] [log] [blame]
Pantelis Antoniou48257c42005-10-28 16:25:58 -04001/*
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
19#include <linux/config.h>
20#include <linux/module.h>
21#include <linux/types.h>
22#include <linux/kernel.h>
23#include <linux/sched.h>
24#include <linux/string.h>
25#include <linux/ptrace.h>
26#include <linux/errno.h>
27#include <linux/ioport.h>
28#include <linux/slab.h>
29#include <linux/interrupt.h>
30#include <linux/pci.h>
31#include <linux/init.h>
32#include <linux/delay.h>
33#include <linux/netdevice.h>
34#include <linux/etherdevice.h>
35#include <linux/skbuff.h>
36#include <linux/spinlock.h>
37#include <linux/mii.h>
38#include <linux/ethtool.h>
39#include <linux/bitops.h>
40
41#include <asm/pgtable.h>
42#include <asm/irq.h>
43#include <asm/uaccess.h>
44
45#include "fs_enet.h"
46
47/*************************************************/
48
49/*
50 * Generic PHY support.
51 * Should work for all PHYs, but link change is detected by polling
52 */
53
54static void generic_timer_callback(unsigned long data)
55{
56 struct net_device *dev = (struct net_device *)data;
57 struct fs_enet_private *fep = netdev_priv(dev);
58
59 fep->phy_timer_list.expires = jiffies + HZ / 2;
60
61 add_timer(&fep->phy_timer_list);
62
63 fs_mii_link_status_change_check(dev, 0);
64}
65
66static void generic_startup(struct net_device *dev)
67{
68 struct fs_enet_private *fep = netdev_priv(dev);
69
70 fep->phy_timer_list.expires = jiffies + HZ / 2; /* every 500ms */
71 fep->phy_timer_list.data = (unsigned long)dev;
72 fep->phy_timer_list.function = generic_timer_callback;
73 add_timer(&fep->phy_timer_list);
74}
75
76static void generic_shutdown(struct net_device *dev)
77{
78 struct fs_enet_private *fep = netdev_priv(dev);
79
80 del_timer_sync(&fep->phy_timer_list);
81}
82
83/* ------------------------------------------------------------------------- */
84/* The Davicom DM9161 is used on the NETTA board */
85
86/* register definitions */
87
88#define MII_DM9161_ANAR 4 /* Aux. Config Register */
89#define MII_DM9161_ACR 16 /* Aux. Config Register */
90#define MII_DM9161_ACSR 17 /* Aux. Config/Status Register */
91#define MII_DM9161_10TCSR 18 /* 10BaseT Config/Status Reg. */
92#define MII_DM9161_INTR 21 /* Interrupt Register */
93#define MII_DM9161_RECR 22 /* Receive Error Counter Reg. */
94#define MII_DM9161_DISCR 23 /* Disconnect Counter Register */
95
96static void dm9161_startup(struct net_device *dev)
97{
98 struct fs_enet_private *fep = netdev_priv(dev);
99
100 fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000);
101 /* Start autonegotiation */
102 fs_mii_write(dev, fep->mii_if.phy_id, MII_BMCR, 0x1200);
103
104 set_current_state(TASK_UNINTERRUPTIBLE);
105 schedule_timeout(HZ*8);
106}
107
108static void dm9161_ack_int(struct net_device *dev)
109{
110 struct fs_enet_private *fep = netdev_priv(dev);
111
112 fs_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR);
113}
114
115static void dm9161_shutdown(struct net_device *dev)
116{
117 struct fs_enet_private *fep = netdev_priv(dev);
118
119 fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00);
120}
121
122/**********************************************************************************/
123
124static const struct phy_info phy_info[] = {
125 {
126 .id = 0x00181b88,
127 .name = "DM9161",
128 .startup = dm9161_startup,
129 .ack_int = dm9161_ack_int,
130 .shutdown = dm9161_shutdown,
131 }, {
132 .id = 0,
133 .name = "GENERIC",
134 .startup = generic_startup,
135 .shutdown = generic_shutdown,
136 },
137};
138
139/**********************************************************************************/
140
141static int phy_id_detect(struct net_device *dev)
142{
143 struct fs_enet_private *fep = netdev_priv(dev);
144 const struct fs_platform_info *fpi = fep->fpi;
145 struct fs_enet_mii_bus *bus = fep->mii_bus;
146 int i, r, start, end, phytype, physubtype;
147 const struct phy_info *phy;
148 int phy_hwid, phy_id;
149
150 phy_hwid = -1;
151 fep->phy = NULL;
152
153 /* auto-detect? */
154 if (fpi->phy_addr == -1) {
155 start = 1;
156 end = 32;
157 } else { /* direct */
158 start = fpi->phy_addr;
159 end = start + 1;
160 }
161
162 for (phy_id = start; phy_id < end; phy_id++) {
163 /* skip already used phy addresses on this bus */
164 if (bus->usage_map & (1 << phy_id))
165 continue;
166 r = fs_mii_read(dev, phy_id, MII_PHYSID1);
167 if (r == -1 || (phytype = (r & 0xffff)) == 0xffff)
168 continue;
169 r = fs_mii_read(dev, phy_id, MII_PHYSID2);
170 if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff)
171 continue;
172 phy_hwid = (phytype << 16) | physubtype;
173 if (phy_hwid != -1)
174 break;
175 }
176
177 if (phy_hwid == -1) {
178 printk(KERN_ERR DRV_MODULE_NAME
179 ": %s No PHY detected! range=0x%02x-0x%02x\n",
180 dev->name, start, end);
181 return -1;
182 }
183
184 for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++)
185 if (phy->id == (phy_hwid >> 4) || phy->id == 0)
186 break;
187
188 if (i >= ARRAY_SIZE(phy_info)) {
189 printk(KERN_ERR DRV_MODULE_NAME
190 ": %s PHY id 0x%08x is not supported!\n",
191 dev->name, phy_hwid);
192 return -1;
193 }
194
195 fep->phy = phy;
196
197 /* mark this address as used */
198 bus->usage_map |= (1 << phy_id);
199
200 printk(KERN_INFO DRV_MODULE_NAME
201 ": %s Phy @ 0x%x, type %s (0x%08x)%s\n",
202 dev->name, phy_id, fep->phy->name, phy_hwid,
203 fpi->phy_addr == -1 ? " (auto-detected)" : "");
204
205 return phy_id;
206}
207
208void fs_mii_startup(struct net_device *dev)
209{
210 struct fs_enet_private *fep = netdev_priv(dev);
211
212 if (fep->phy->startup)
213 (*fep->phy->startup) (dev);
214}
215
216void fs_mii_shutdown(struct net_device *dev)
217{
218 struct fs_enet_private *fep = netdev_priv(dev);
219
220 if (fep->phy->shutdown)
221 (*fep->phy->shutdown) (dev);
222}
223
224void fs_mii_ack_int(struct net_device *dev)
225{
226 struct fs_enet_private *fep = netdev_priv(dev);
227
228 if (fep->phy->ack_int)
229 (*fep->phy->ack_int) (dev);
230}
231
232#define MII_LINK 0x0001
233#define MII_HALF 0x0002
234#define MII_FULL 0x0004
235#define MII_BASE4 0x0008
236#define MII_10M 0x0010
237#define MII_100M 0x0020
238#define MII_1G 0x0040
239#define MII_10G 0x0080
240
241/* return full mii info at one gulp, with a usable form */
242static unsigned int mii_full_status(struct mii_if_info *mii)
243{
244 unsigned int status;
245 int bmsr, adv, lpa, neg;
246 struct fs_enet_private* fep = netdev_priv(mii->dev);
247
248 /* first, a dummy read, needed to latch some MII phys */
249 (void)mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
250 bmsr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
251
252 /* no link */
253 if ((bmsr & BMSR_LSTATUS) == 0)
254 return 0;
255
256 status = MII_LINK;
257
258 /* Lets look what ANEG says if it's supported - otherwize we shall
259 take the right values from the platform info*/
260 if(!mii->force_media) {
261 /* autoneg not completed; don't bother */
262 if ((bmsr & BMSR_ANEGCOMPLETE) == 0)
263 return 0;
264
265 adv = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_ADVERTISE);
266 lpa = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_LPA);
267
268 neg = lpa & adv;
269 } else {
270 neg = fep->fpi->bus_info->lpa;
271 }
272
273 if (neg & LPA_100FULL)
274 status |= MII_FULL | MII_100M;
275 else if (neg & LPA_100BASE4)
276 status |= MII_FULL | MII_BASE4 | MII_100M;
277 else if (neg & LPA_100HALF)
278 status |= MII_HALF | MII_100M;
279 else if (neg & LPA_10FULL)
280 status |= MII_FULL | MII_10M;
281 else
282 status |= MII_HALF | MII_10M;
283
284 return status;
285}
286
287void fs_mii_link_status_change_check(struct net_device *dev, int init_media)
288{
289 struct fs_enet_private *fep = netdev_priv(dev);
290 struct mii_if_info *mii = &fep->mii_if;
291 unsigned int mii_status;
292 int ok_to_print, link, duplex, speed;
293 unsigned long flags;
294
295 ok_to_print = netif_msg_link(fep);
296
297 mii_status = mii_full_status(mii);
298
299 if (!init_media && mii_status == fep->last_mii_status)
300 return;
301
302 fep->last_mii_status = mii_status;
303
304 link = !!(mii_status & MII_LINK);
305 duplex = !!(mii_status & MII_FULL);
306 speed = (mii_status & MII_100M) ? 100 : 10;
307
308 if (link == 0) {
309 netif_carrier_off(mii->dev);
310 netif_stop_queue(dev);
311 if (!init_media) {
312 spin_lock_irqsave(&fep->lock, flags);
313 (*fep->ops->stop)(dev);
314 spin_unlock_irqrestore(&fep->lock, flags);
315 }
316
317 if (ok_to_print)
318 printk(KERN_INFO "%s: link down\n", mii->dev->name);
319
320 } else {
321
322 mii->full_duplex = duplex;
323
324 netif_carrier_on(mii->dev);
325
326 spin_lock_irqsave(&fep->lock, flags);
327 fep->duplex = duplex;
328 fep->speed = speed;
329 (*fep->ops->restart)(dev);
330 spin_unlock_irqrestore(&fep->lock, flags);
331
332 netif_start_queue(dev);
333
334 if (ok_to_print)
335 printk(KERN_INFO "%s: link up, %dMbps, %s-duplex\n",
336 dev->name, speed, duplex ? "full" : "half");
337 }
338}
339
340/**********************************************************************************/
341
342int fs_mii_read(struct net_device *dev, int phy_id, int location)
343{
344 struct fs_enet_private *fep = netdev_priv(dev);
345 struct fs_enet_mii_bus *bus = fep->mii_bus;
346
347 unsigned long flags;
348 int ret;
349
350 spin_lock_irqsave(&bus->mii_lock, flags);
351 ret = (*bus->mii_read)(bus, phy_id, location);
352 spin_unlock_irqrestore(&bus->mii_lock, flags);
353
354 return ret;
355}
356
357void fs_mii_write(struct net_device *dev, int phy_id, int location, int value)
358{
359 struct fs_enet_private *fep = netdev_priv(dev);
360 struct fs_enet_mii_bus *bus = fep->mii_bus;
361 unsigned long flags;
362
363 spin_lock_irqsave(&bus->mii_lock, flags);
364 (*bus->mii_write)(bus, phy_id, location, value);
365 spin_unlock_irqrestore(&bus->mii_lock, flags);
366}
367
368/*****************************************************************************/
369
370/* list of all registered mii buses */
371static LIST_HEAD(fs_mii_bus_list);
372
373static struct fs_enet_mii_bus *lookup_bus(int method, int id)
374{
375 struct list_head *ptr;
376 struct fs_enet_mii_bus *bus;
377
378 list_for_each(ptr, &fs_mii_bus_list) {
379 bus = list_entry(ptr, struct fs_enet_mii_bus, list);
380 if (bus->bus_info->method == method &&
381 bus->bus_info->id == id)
382 return bus;
383 }
384 return NULL;
385}
386
387static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi)
388{
389 struct fs_enet_mii_bus *bus;
390 int ret = 0;
391
392 bus = kmalloc(sizeof(*bus), GFP_KERNEL);
393 if (bus == NULL) {
394 ret = -ENOMEM;
395 goto err;
396 }
397 memset(bus, 0, sizeof(*bus));
398 spin_lock_init(&bus->mii_lock);
399 bus->bus_info = bi;
400 bus->refs = 0;
401 bus->usage_map = 0;
402
403 /* perform initialization */
404 switch (bi->method) {
405
406 case fsmii_fixed:
407 ret = fs_mii_fixed_init(bus);
408 if (ret != 0)
409 goto err;
410 break;
411
412 case fsmii_bitbang:
413 ret = fs_mii_bitbang_init(bus);
414 if (ret != 0)
415 goto err;
416 break;
417#ifdef CONFIG_FS_ENET_HAS_FEC
418 case fsmii_fec:
419 ret = fs_mii_fec_init(bus);
420 if (ret != 0)
421 goto err;
422 break;
423#endif
424 default:
425 ret = -EINVAL;
426 goto err;
427 }
428
429 list_add(&bus->list, &fs_mii_bus_list);
430
431 return bus;
432
433err:
434 if (bus)
435 kfree(bus);
436 return ERR_PTR(ret);
437}
438
439static void destroy_bus(struct fs_enet_mii_bus *bus)
440{
441 /* remove from bus list */
442 list_del(&bus->list);
443
444 /* nothing more needed */
445 kfree(bus);
446}
447
448int fs_mii_connect(struct net_device *dev)
449{
450 struct fs_enet_private *fep = netdev_priv(dev);
451 const struct fs_platform_info *fpi = fep->fpi;
452 struct fs_enet_mii_bus *bus = NULL;
453
454 /* check method validity */
455 switch (fpi->bus_info->method) {
456 case fsmii_fixed:
457 case fsmii_bitbang:
458 break;
459#ifdef CONFIG_FS_ENET_HAS_FEC
460 case fsmii_fec:
461 break;
462#endif
463 default:
464 printk(KERN_ERR DRV_MODULE_NAME
465 ": %s Unknown MII bus method (%d)!\n",
466 dev->name, fpi->bus_info->method);
467 return -EINVAL;
468 }
469
470 bus = lookup_bus(fpi->bus_info->method, fpi->bus_info->id);
471
472 /* if not found create new bus */
473 if (bus == NULL) {
474 bus = create_bus(fpi->bus_info);
475 if (IS_ERR(bus)) {
476 printk(KERN_ERR DRV_MODULE_NAME
477 ": %s MII bus creation failure!\n", dev->name);
478 return PTR_ERR(bus);
479 }
480 }
481
482 bus->refs++;
483
484 fep->mii_bus = bus;
485
486 fep->mii_if.dev = dev;
487 fep->mii_if.phy_id_mask = 0x1f;
488 fep->mii_if.reg_num_mask = 0x1f;
489 fep->mii_if.mdio_read = fs_mii_read;
490 fep->mii_if.mdio_write = fs_mii_write;
491 fep->mii_if.force_media = fpi->bus_info->disable_aneg;
492 fep->mii_if.phy_id = phy_id_detect(dev);
493
494 return 0;
495}
496
497void fs_mii_disconnect(struct net_device *dev)
498{
499 struct fs_enet_private *fep = netdev_priv(dev);
500 struct fs_enet_mii_bus *bus = NULL;
501
502 bus = fep->mii_bus;
503 fep->mii_bus = NULL;
504
505 if (--bus->refs <= 0)
506 destroy_bus(bus);
507}