[PATCH] libata: improve driver initialization and deinitialization
[linux-2.6/kvm.git] / drivers / net / fs_enet / fs_enet-mii.c
blobb7e6e21725cbcdfff6f6029b32153173b380155a
1 /*
2 * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
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>
10 * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>
11 * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
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.
19 #include <linux/module.h>
20 #include <linux/types.h>
21 #include <linux/kernel.h>
22 #include <linux/sched.h>
23 #include <linux/string.h>
24 #include <linux/ptrace.h>
25 #include <linux/errno.h>
26 #include <linux/ioport.h>
27 #include <linux/slab.h>
28 #include <linux/interrupt.h>
29 #include <linux/pci.h>
30 #include <linux/init.h>
31 #include <linux/delay.h>
32 #include <linux/netdevice.h>
33 #include <linux/etherdevice.h>
34 #include <linux/skbuff.h>
35 #include <linux/spinlock.h>
36 #include <linux/mii.h>
37 #include <linux/ethtool.h>
38 #include <linux/bitops.h>
40 #include <asm/pgtable.h>
41 #include <asm/irq.h>
42 #include <asm/uaccess.h>
44 #include "fs_enet.h"
46 /*************************************************/
49 * Generic PHY support.
50 * Should work for all PHYs, but link change is detected by polling
53 static void generic_timer_callback(unsigned long data)
55 struct net_device *dev = (struct net_device *)data;
56 struct fs_enet_private *fep = netdev_priv(dev);
58 fep->phy_timer_list.expires = jiffies + HZ / 2;
60 add_timer(&fep->phy_timer_list);
62 fs_mii_link_status_change_check(dev, 0);
65 static void generic_startup(struct net_device *dev)
67 struct fs_enet_private *fep = netdev_priv(dev);
69 fep->phy_timer_list.expires = jiffies + HZ / 2; /* every 500ms */
70 fep->phy_timer_list.data = (unsigned long)dev;
71 fep->phy_timer_list.function = generic_timer_callback;
72 add_timer(&fep->phy_timer_list);
75 static void generic_shutdown(struct net_device *dev)
77 struct fs_enet_private *fep = netdev_priv(dev);
79 del_timer_sync(&fep->phy_timer_list);
82 /* ------------------------------------------------------------------------- */
83 /* The Davicom DM9161 is used on the NETTA board */
85 /* register definitions */
87 #define MII_DM9161_ANAR 4 /* Aux. Config Register */
88 #define MII_DM9161_ACR 16 /* Aux. Config Register */
89 #define MII_DM9161_ACSR 17 /* Aux. Config/Status Register */
90 #define MII_DM9161_10TCSR 18 /* 10BaseT Config/Status Reg. */
91 #define MII_DM9161_INTR 21 /* Interrupt Register */
92 #define MII_DM9161_RECR 22 /* Receive Error Counter Reg. */
93 #define MII_DM9161_DISCR 23 /* Disconnect Counter Register */
95 static void dm9161_startup(struct net_device *dev)
97 struct fs_enet_private *fep = netdev_priv(dev);
99 fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000);
100 /* Start autonegotiation */
101 fs_mii_write(dev, fep->mii_if.phy_id, MII_BMCR, 0x1200);
103 set_current_state(TASK_UNINTERRUPTIBLE);
104 schedule_timeout(HZ*8);
107 static void dm9161_ack_int(struct net_device *dev)
109 struct fs_enet_private *fep = netdev_priv(dev);
111 fs_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR);
114 static void dm9161_shutdown(struct net_device *dev)
116 struct fs_enet_private *fep = netdev_priv(dev);
118 fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00);
121 /**********************************************************************************/
123 static const struct phy_info phy_info[] = {
125 .id = 0x00181b88,
126 .name = "DM9161",
127 .startup = dm9161_startup,
128 .ack_int = dm9161_ack_int,
129 .shutdown = dm9161_shutdown,
130 }, {
131 .id = 0,
132 .name = "GENERIC",
133 .startup = generic_startup,
134 .shutdown = generic_shutdown,
138 /**********************************************************************************/
140 static int phy_id_detect(struct net_device *dev)
142 struct fs_enet_private *fep = netdev_priv(dev);
143 const struct fs_platform_info *fpi = fep->fpi;
144 struct fs_enet_mii_bus *bus = fep->mii_bus;
145 int i, r, start, end, phytype, physubtype;
146 const struct phy_info *phy;
147 int phy_hwid, phy_id;
149 phy_hwid = -1;
150 fep->phy = NULL;
152 /* auto-detect? */
153 if (fpi->phy_addr == -1) {
154 start = 1;
155 end = 32;
156 } else { /* direct */
157 start = fpi->phy_addr;
158 end = start + 1;
161 for (phy_id = start; phy_id < end; phy_id++) {
162 /* skip already used phy addresses on this bus */
163 if (bus->usage_map & (1 << phy_id))
164 continue;
165 r = fs_mii_read(dev, phy_id, MII_PHYSID1);
166 if (r == -1 || (phytype = (r & 0xffff)) == 0xffff)
167 continue;
168 r = fs_mii_read(dev, phy_id, MII_PHYSID2);
169 if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff)
170 continue;
171 phy_hwid = (phytype << 16) | physubtype;
172 if (phy_hwid != -1)
173 break;
176 if (phy_hwid == -1) {
177 printk(KERN_ERR DRV_MODULE_NAME
178 ": %s No PHY detected! range=0x%02x-0x%02x\n",
179 dev->name, start, end);
180 return -1;
183 for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++)
184 if (phy->id == (phy_hwid >> 4) || phy->id == 0)
185 break;
187 if (i >= ARRAY_SIZE(phy_info)) {
188 printk(KERN_ERR DRV_MODULE_NAME
189 ": %s PHY id 0x%08x is not supported!\n",
190 dev->name, phy_hwid);
191 return -1;
194 fep->phy = phy;
196 /* mark this address as used */
197 bus->usage_map |= (1 << phy_id);
199 printk(KERN_INFO DRV_MODULE_NAME
200 ": %s Phy @ 0x%x, type %s (0x%08x)%s\n",
201 dev->name, phy_id, fep->phy->name, phy_hwid,
202 fpi->phy_addr == -1 ? " (auto-detected)" : "");
204 return phy_id;
207 void fs_mii_startup(struct net_device *dev)
209 struct fs_enet_private *fep = netdev_priv(dev);
211 if (fep->phy->startup)
212 (*fep->phy->startup) (dev);
215 void fs_mii_shutdown(struct net_device *dev)
217 struct fs_enet_private *fep = netdev_priv(dev);
219 if (fep->phy->shutdown)
220 (*fep->phy->shutdown) (dev);
223 void fs_mii_ack_int(struct net_device *dev)
225 struct fs_enet_private *fep = netdev_priv(dev);
227 if (fep->phy->ack_int)
228 (*fep->phy->ack_int) (dev);
231 #define MII_LINK 0x0001
232 #define MII_HALF 0x0002
233 #define MII_FULL 0x0004
234 #define MII_BASE4 0x0008
235 #define MII_10M 0x0010
236 #define MII_100M 0x0020
237 #define MII_1G 0x0040
238 #define MII_10G 0x0080
240 /* return full mii info at one gulp, with a usable form */
241 static unsigned int mii_full_status(struct mii_if_info *mii)
243 unsigned int status;
244 int bmsr, adv, lpa, neg;
245 struct fs_enet_private* fep = netdev_priv(mii->dev);
247 /* first, a dummy read, needed to latch some MII phys */
248 (void)mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
249 bmsr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
251 /* no link */
252 if ((bmsr & BMSR_LSTATUS) == 0)
253 return 0;
255 status = MII_LINK;
257 /* Lets look what ANEG says if it's supported - otherwize we shall
258 take the right values from the platform info*/
259 if(!mii->force_media) {
260 /* autoneg not completed; don't bother */
261 if ((bmsr & BMSR_ANEGCOMPLETE) == 0)
262 return 0;
264 adv = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_ADVERTISE);
265 lpa = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_LPA);
267 neg = lpa & adv;
268 } else {
269 neg = fep->fpi->bus_info->lpa;
272 if (neg & LPA_100FULL)
273 status |= MII_FULL | MII_100M;
274 else if (neg & LPA_100BASE4)
275 status |= MII_FULL | MII_BASE4 | MII_100M;
276 else if (neg & LPA_100HALF)
277 status |= MII_HALF | MII_100M;
278 else if (neg & LPA_10FULL)
279 status |= MII_FULL | MII_10M;
280 else
281 status |= MII_HALF | MII_10M;
283 return status;
286 void fs_mii_link_status_change_check(struct net_device *dev, int init_media)
288 struct fs_enet_private *fep = netdev_priv(dev);
289 struct mii_if_info *mii = &fep->mii_if;
290 unsigned int mii_status;
291 int ok_to_print, link, duplex, speed;
292 unsigned long flags;
294 ok_to_print = netif_msg_link(fep);
296 mii_status = mii_full_status(mii);
298 if (!init_media && mii_status == fep->last_mii_status)
299 return;
301 fep->last_mii_status = mii_status;
303 link = !!(mii_status & MII_LINK);
304 duplex = !!(mii_status & MII_FULL);
305 speed = (mii_status & MII_100M) ? 100 : 10;
307 if (link == 0) {
308 netif_carrier_off(mii->dev);
309 netif_stop_queue(dev);
310 if (!init_media) {
311 spin_lock_irqsave(&fep->lock, flags);
312 (*fep->ops->stop)(dev);
313 spin_unlock_irqrestore(&fep->lock, flags);
316 if (ok_to_print)
317 printk(KERN_INFO "%s: link down\n", mii->dev->name);
319 } else {
321 mii->full_duplex = duplex;
323 netif_carrier_on(mii->dev);
325 spin_lock_irqsave(&fep->lock, flags);
326 fep->duplex = duplex;
327 fep->speed = speed;
328 (*fep->ops->restart)(dev);
329 spin_unlock_irqrestore(&fep->lock, flags);
331 netif_start_queue(dev);
333 if (ok_to_print)
334 printk(KERN_INFO "%s: link up, %dMbps, %s-duplex\n",
335 dev->name, speed, duplex ? "full" : "half");
339 /**********************************************************************************/
341 int fs_mii_read(struct net_device *dev, int phy_id, int location)
343 struct fs_enet_private *fep = netdev_priv(dev);
344 struct fs_enet_mii_bus *bus = fep->mii_bus;
346 unsigned long flags;
347 int ret;
349 spin_lock_irqsave(&bus->mii_lock, flags);
350 ret = (*bus->mii_read)(bus, phy_id, location);
351 spin_unlock_irqrestore(&bus->mii_lock, flags);
353 return ret;
356 void fs_mii_write(struct net_device *dev, int phy_id, int location, int value)
358 struct fs_enet_private *fep = netdev_priv(dev);
359 struct fs_enet_mii_bus *bus = fep->mii_bus;
360 unsigned long flags;
362 spin_lock_irqsave(&bus->mii_lock, flags);
363 (*bus->mii_write)(bus, phy_id, location, value);
364 spin_unlock_irqrestore(&bus->mii_lock, flags);
367 /*****************************************************************************/
369 /* list of all registered mii buses */
370 static LIST_HEAD(fs_mii_bus_list);
372 static struct fs_enet_mii_bus *lookup_bus(int method, int id)
374 struct list_head *ptr;
375 struct fs_enet_mii_bus *bus;
377 list_for_each(ptr, &fs_mii_bus_list) {
378 bus = list_entry(ptr, struct fs_enet_mii_bus, list);
379 if (bus->bus_info->method == method &&
380 bus->bus_info->id == id)
381 return bus;
383 return NULL;
386 static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi)
388 struct fs_enet_mii_bus *bus;
389 int ret = 0;
391 bus = kmalloc(sizeof(*bus), GFP_KERNEL);
392 if (bus == NULL) {
393 ret = -ENOMEM;
394 goto err;
396 memset(bus, 0, sizeof(*bus));
397 spin_lock_init(&bus->mii_lock);
398 bus->bus_info = bi;
399 bus->refs = 0;
400 bus->usage_map = 0;
402 /* perform initialization */
403 switch (bi->method) {
405 case fsmii_fixed:
406 ret = fs_mii_fixed_init(bus);
407 if (ret != 0)
408 goto err;
409 break;
411 case fsmii_bitbang:
412 ret = fs_mii_bitbang_init(bus);
413 if (ret != 0)
414 goto err;
415 break;
416 #ifdef CONFIG_FS_ENET_HAS_FEC
417 case fsmii_fec:
418 ret = fs_mii_fec_init(bus);
419 if (ret != 0)
420 goto err;
421 break;
422 #endif
423 default:
424 ret = -EINVAL;
425 goto err;
428 list_add(&bus->list, &fs_mii_bus_list);
430 return bus;
432 err:
433 kfree(bus);
434 return ERR_PTR(ret);
437 static void destroy_bus(struct fs_enet_mii_bus *bus)
439 /* remove from bus list */
440 list_del(&bus->list);
442 /* nothing more needed */
443 kfree(bus);
446 int fs_mii_connect(struct net_device *dev)
448 struct fs_enet_private *fep = netdev_priv(dev);
449 const struct fs_platform_info *fpi = fep->fpi;
450 struct fs_enet_mii_bus *bus = NULL;
452 /* check method validity */
453 switch (fpi->bus_info->method) {
454 case fsmii_fixed:
455 case fsmii_bitbang:
456 break;
457 #ifdef CONFIG_FS_ENET_HAS_FEC
458 case fsmii_fec:
459 break;
460 #endif
461 default:
462 printk(KERN_ERR DRV_MODULE_NAME
463 ": %s Unknown MII bus method (%d)!\n",
464 dev->name, fpi->bus_info->method);
465 return -EINVAL;
468 bus = lookup_bus(fpi->bus_info->method, fpi->bus_info->id);
470 /* if not found create new bus */
471 if (bus == NULL) {
472 bus = create_bus(fpi->bus_info);
473 if (IS_ERR(bus)) {
474 printk(KERN_ERR DRV_MODULE_NAME
475 ": %s MII bus creation failure!\n", dev->name);
476 return PTR_ERR(bus);
480 bus->refs++;
482 fep->mii_bus = bus;
484 fep->mii_if.dev = dev;
485 fep->mii_if.phy_id_mask = 0x1f;
486 fep->mii_if.reg_num_mask = 0x1f;
487 fep->mii_if.mdio_read = fs_mii_read;
488 fep->mii_if.mdio_write = fs_mii_write;
489 fep->mii_if.force_media = fpi->bus_info->disable_aneg;
490 fep->mii_if.phy_id = phy_id_detect(dev);
492 return 0;
495 void fs_mii_disconnect(struct net_device *dev)
497 struct fs_enet_private *fep = netdev_priv(dev);
498 struct fs_enet_mii_bus *bus = NULL;
500 bus = fep->mii_bus;
501 fep->mii_bus = NULL;
503 if (--bus->refs <= 0)
504 destroy_bus(bus);