ia64/linux-2.6.18-xen.hg

view drivers/net/ucc_geth_phy.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 831230e53067
children
line source
1 /*
2 * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
3 *
4 * Author: Shlomi Gridish <gridish@freescale.com>
5 *
6 * Description:
7 * UCC GETH Driver -- PHY handling
8 *
9 * Changelog:
10 * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
11 * - Rearrange code and style fixes
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
17 *
18 */
20 #include <linux/config.h>
21 #include <linux/kernel.h>
22 #include <linux/sched.h>
23 #include <linux/string.h>
24 #include <linux/errno.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/mm.h>
34 #include <linux/module.h>
35 #include <linux/version.h>
36 #include <linux/crc32.h>
37 #include <linux/mii.h>
38 #include <linux/ethtool.h>
40 #include <asm/io.h>
41 #include <asm/irq.h>
42 #include <asm/uaccess.h>
44 #include "ucc_geth.h"
45 #include "ucc_geth_phy.h"
46 #include <platforms/83xx/mpc8360e_pb.h>
48 #define ugphy_printk(level, format, arg...) \
49 printk(level format "\n", ## arg)
51 #define ugphy_dbg(format, arg...) \
52 ugphy_printk(KERN_DEBUG, format , ## arg)
53 #define ugphy_err(format, arg...) \
54 ugphy_printk(KERN_ERR, format , ## arg)
55 #define ugphy_info(format, arg...) \
56 ugphy_printk(KERN_INFO, format , ## arg)
57 #define ugphy_warn(format, arg...) \
58 ugphy_printk(KERN_WARNING, format , ## arg)
60 #ifdef UGETH_VERBOSE_DEBUG
61 #define ugphy_vdbg ugphy_dbg
62 #else
63 #define ugphy_vdbg(fmt, args...) do { } while (0)
64 #endif /* UGETH_VERBOSE_DEBUG */
66 static void config_genmii_advert(struct ugeth_mii_info *mii_info);
67 static void genmii_setup_forced(struct ugeth_mii_info *mii_info);
68 static void genmii_restart_aneg(struct ugeth_mii_info *mii_info);
69 static int gbit_config_aneg(struct ugeth_mii_info *mii_info);
70 static int genmii_config_aneg(struct ugeth_mii_info *mii_info);
71 static int genmii_update_link(struct ugeth_mii_info *mii_info);
72 static int genmii_read_status(struct ugeth_mii_info *mii_info);
73 u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum);
74 void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val);
76 static u8 *bcsr_regs = NULL;
78 /* Write value to the PHY for this device to the register at regnum, */
79 /* waiting until the write is done before it returns. All PHY */
80 /* configuration has to be done through the TSEC1 MIIM regs */
81 void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value)
82 {
83 ucc_geth_private_t *ugeth = netdev_priv(dev);
84 ucc_mii_mng_t *mii_regs;
85 enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
86 u32 tmp_reg;
88 ugphy_vdbg("%s: IN", __FUNCTION__);
90 spin_lock_irq(&ugeth->lock);
92 mii_regs = ugeth->mii_info->mii_regs;
94 /* Set this UCC to be the master of the MII managment */
95 ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num);
97 /* Stop the MII management read cycle */
98 out_be32(&mii_regs->miimcom, 0);
99 /* Setting up the MII Mangement Address Register */
100 tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
101 out_be32(&mii_regs->miimadd, tmp_reg);
103 /* Setting up the MII Mangement Control Register with the value */
104 out_be32(&mii_regs->miimcon, (u32) value);
106 /* Wait till MII management write is complete */
107 while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY)
108 cpu_relax();
110 spin_unlock_irq(&ugeth->lock);
112 udelay(10000);
113 }
115 /* Reads from register regnum in the PHY for device dev, */
116 /* returning the value. Clears miimcom first. All PHY */
117 /* configuration has to be done through the TSEC1 MIIM regs */
118 int read_phy_reg(struct net_device *dev, int mii_id, int regnum)
119 {
120 ucc_geth_private_t *ugeth = netdev_priv(dev);
121 ucc_mii_mng_t *mii_regs;
122 enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
123 u32 tmp_reg;
124 u16 value;
126 ugphy_vdbg("%s: IN", __FUNCTION__);
128 spin_lock_irq(&ugeth->lock);
130 mii_regs = ugeth->mii_info->mii_regs;
132 /* Setting up the MII Mangement Address Register */
133 tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
134 out_be32(&mii_regs->miimadd, tmp_reg);
136 /* Perform an MII management read cycle */
137 out_be32(&mii_regs->miimcom, MIIMCOM_READ_CYCLE);
139 /* Wait till MII management write is complete */
140 while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY)
141 cpu_relax();
143 udelay(10000);
145 /* Read MII management status */
146 value = (u16) in_be32(&mii_regs->miimstat);
147 out_be32(&mii_regs->miimcom, 0);
148 if (value == 0xffff)
149 ugphy_warn("read wrong value : mii_id %d,mii_reg %d, base %08x",
150 mii_id, mii_reg, (u32) & (mii_regs->miimcfg));
152 spin_unlock_irq(&ugeth->lock);
154 return (value);
155 }
157 void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info)
158 {
159 ugphy_vdbg("%s: IN", __FUNCTION__);
161 if (mii_info->phyinfo->ack_interrupt)
162 mii_info->phyinfo->ack_interrupt(mii_info);
163 }
165 void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
166 u32 interrupts)
167 {
168 ugphy_vdbg("%s: IN", __FUNCTION__);
170 mii_info->interrupts = interrupts;
171 if (mii_info->phyinfo->config_intr)
172 mii_info->phyinfo->config_intr(mii_info);
173 }
175 /* Writes MII_ADVERTISE with the appropriate values, after
176 * sanitizing advertise to make sure only supported features
177 * are advertised
178 */
179 static void config_genmii_advert(struct ugeth_mii_info *mii_info)
180 {
181 u32 advertise;
182 u16 adv;
184 ugphy_vdbg("%s: IN", __FUNCTION__);
186 /* Only allow advertising what this PHY supports */
187 mii_info->advertising &= mii_info->phyinfo->features;
188 advertise = mii_info->advertising;
190 /* Setup standard advertisement */
191 adv = phy_read(mii_info, MII_ADVERTISE);
192 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
193 if (advertise & ADVERTISED_10baseT_Half)
194 adv |= ADVERTISE_10HALF;
195 if (advertise & ADVERTISED_10baseT_Full)
196 adv |= ADVERTISE_10FULL;
197 if (advertise & ADVERTISED_100baseT_Half)
198 adv |= ADVERTISE_100HALF;
199 if (advertise & ADVERTISED_100baseT_Full)
200 adv |= ADVERTISE_100FULL;
201 phy_write(mii_info, MII_ADVERTISE, adv);
202 }
204 static void genmii_setup_forced(struct ugeth_mii_info *mii_info)
205 {
206 u16 ctrl;
207 u32 features = mii_info->phyinfo->features;
209 ugphy_vdbg("%s: IN", __FUNCTION__);
211 ctrl = phy_read(mii_info, MII_BMCR);
213 ctrl &=
214 ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
215 ctrl |= BMCR_RESET;
217 switch (mii_info->speed) {
218 case SPEED_1000:
219 if (features & (SUPPORTED_1000baseT_Half
220 | SUPPORTED_1000baseT_Full)) {
221 ctrl |= BMCR_SPEED1000;
222 break;
223 }
224 mii_info->speed = SPEED_100;
225 case SPEED_100:
226 if (features & (SUPPORTED_100baseT_Half
227 | SUPPORTED_100baseT_Full)) {
228 ctrl |= BMCR_SPEED100;
229 break;
230 }
231 mii_info->speed = SPEED_10;
232 case SPEED_10:
233 if (features & (SUPPORTED_10baseT_Half
234 | SUPPORTED_10baseT_Full))
235 break;
236 default: /* Unsupported speed! */
237 ugphy_err("%s: Bad speed!", mii_info->dev->name);
238 break;
239 }
241 phy_write(mii_info, MII_BMCR, ctrl);
242 }
244 /* Enable and Restart Autonegotiation */
245 static void genmii_restart_aneg(struct ugeth_mii_info *mii_info)
246 {
247 u16 ctl;
249 ugphy_vdbg("%s: IN", __FUNCTION__);
251 ctl = phy_read(mii_info, MII_BMCR);
252 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
253 phy_write(mii_info, MII_BMCR, ctl);
254 }
256 static int gbit_config_aneg(struct ugeth_mii_info *mii_info)
257 {
258 u16 adv;
259 u32 advertise;
261 ugphy_vdbg("%s: IN", __FUNCTION__);
263 if (mii_info->autoneg) {
264 /* Configure the ADVERTISE register */
265 config_genmii_advert(mii_info);
266 advertise = mii_info->advertising;
268 adv = phy_read(mii_info, MII_1000BASETCONTROL);
269 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
270 MII_1000BASETCONTROL_HALFDUPLEXCAP);
271 if (advertise & SUPPORTED_1000baseT_Half)
272 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
273 if (advertise & SUPPORTED_1000baseT_Full)
274 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
275 phy_write(mii_info, MII_1000BASETCONTROL, adv);
277 /* Start/Restart aneg */
278 genmii_restart_aneg(mii_info);
279 } else
280 genmii_setup_forced(mii_info);
282 return 0;
283 }
285 static int genmii_config_aneg(struct ugeth_mii_info *mii_info)
286 {
287 ugphy_vdbg("%s: IN", __FUNCTION__);
289 if (mii_info->autoneg) {
290 config_genmii_advert(mii_info);
291 genmii_restart_aneg(mii_info);
292 } else
293 genmii_setup_forced(mii_info);
295 return 0;
296 }
298 static int genmii_update_link(struct ugeth_mii_info *mii_info)
299 {
300 u16 status;
302 ugphy_vdbg("%s: IN", __FUNCTION__);
304 /* Do a fake read */
305 phy_read(mii_info, MII_BMSR);
307 /* Read link and autonegotiation status */
308 status = phy_read(mii_info, MII_BMSR);
309 if ((status & BMSR_LSTATUS) == 0)
310 mii_info->link = 0;
311 else
312 mii_info->link = 1;
314 /* If we are autonegotiating, and not done,
315 * return an error */
316 if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE))
317 return -EAGAIN;
319 return 0;
320 }
322 static int genmii_read_status(struct ugeth_mii_info *mii_info)
323 {
324 u16 status;
325 int err;
327 ugphy_vdbg("%s: IN", __FUNCTION__);
329 /* Update the link, but return if there
330 * was an error */
331 err = genmii_update_link(mii_info);
332 if (err)
333 return err;
335 if (mii_info->autoneg) {
336 status = phy_read(mii_info, MII_LPA);
338 if (status & (LPA_10FULL | LPA_100FULL))
339 mii_info->duplex = DUPLEX_FULL;
340 else
341 mii_info->duplex = DUPLEX_HALF;
342 if (status & (LPA_100FULL | LPA_100HALF))
343 mii_info->speed = SPEED_100;
344 else
345 mii_info->speed = SPEED_10;
346 mii_info->pause = 0;
347 }
348 /* On non-aneg, we assume what we put in BMCR is the speed,
349 * though magic-aneg shouldn't prevent this case from occurring
350 */
352 return 0;
353 }
355 static int marvell_init(struct ugeth_mii_info *mii_info)
356 {
357 ugphy_vdbg("%s: IN", __FUNCTION__);
359 phy_write(mii_info, 0x14, 0x0cd2);
360 phy_write(mii_info, MII_BMCR,
361 phy_read(mii_info, MII_BMCR) | BMCR_RESET);
362 msleep(4000);
364 return 0;
365 }
367 static int marvell_config_aneg(struct ugeth_mii_info *mii_info)
368 {
369 ugphy_vdbg("%s: IN", __FUNCTION__);
371 /* The Marvell PHY has an errata which requires
372 * that certain registers get written in order
373 * to restart autonegotiation */
374 phy_write(mii_info, MII_BMCR, BMCR_RESET);
376 phy_write(mii_info, 0x1d, 0x1f);
377 phy_write(mii_info, 0x1e, 0x200c);
378 phy_write(mii_info, 0x1d, 0x5);
379 phy_write(mii_info, 0x1e, 0);
380 phy_write(mii_info, 0x1e, 0x100);
382 gbit_config_aneg(mii_info);
384 return 0;
385 }
387 static int marvell_read_status(struct ugeth_mii_info *mii_info)
388 {
389 u16 status;
390 int err;
392 ugphy_vdbg("%s: IN", __FUNCTION__);
394 /* Update the link, but return if there
395 * was an error */
396 err = genmii_update_link(mii_info);
397 if (err)
398 return err;
400 /* If the link is up, read the speed and duplex */
401 /* If we aren't autonegotiating, assume speeds
402 * are as set */
403 if (mii_info->autoneg && mii_info->link) {
404 int speed;
405 status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS);
407 /* Get the duplexity */
408 if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
409 mii_info->duplex = DUPLEX_FULL;
410 else
411 mii_info->duplex = DUPLEX_HALF;
413 /* Get the speed */
414 speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK;
415 switch (speed) {
416 case MII_M1011_PHY_SPEC_STATUS_1000:
417 mii_info->speed = SPEED_1000;
418 break;
419 case MII_M1011_PHY_SPEC_STATUS_100:
420 mii_info->speed = SPEED_100;
421 break;
422 default:
423 mii_info->speed = SPEED_10;
424 break;
425 }
426 mii_info->pause = 0;
427 }
429 return 0;
430 }
432 static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info)
433 {
434 ugphy_vdbg("%s: IN", __FUNCTION__);
436 /* Clear the interrupts by reading the reg */
437 phy_read(mii_info, MII_M1011_IEVENT);
439 return 0;
440 }
442 static int marvell_config_intr(struct ugeth_mii_info *mii_info)
443 {
444 ugphy_vdbg("%s: IN", __FUNCTION__);
446 if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
447 phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
448 else
449 phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
451 return 0;
452 }
454 static int cis820x_init(struct ugeth_mii_info *mii_info)
455 {
456 ugphy_vdbg("%s: IN", __FUNCTION__);
458 phy_write(mii_info, MII_CIS8201_AUX_CONSTAT,
459 MII_CIS8201_AUXCONSTAT_INIT);
460 phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT);
462 return 0;
463 }
465 static int cis820x_read_status(struct ugeth_mii_info *mii_info)
466 {
467 u16 status;
468 int err;
470 ugphy_vdbg("%s: IN", __FUNCTION__);
472 /* Update the link, but return if there
473 * was an error */
474 err = genmii_update_link(mii_info);
475 if (err)
476 return err;
478 /* If the link is up, read the speed and duplex */
479 /* If we aren't autonegotiating, assume speeds
480 * are as set */
481 if (mii_info->autoneg && mii_info->link) {
482 int speed;
484 status = phy_read(mii_info, MII_CIS8201_AUX_CONSTAT);
485 if (status & MII_CIS8201_AUXCONSTAT_DUPLEX)
486 mii_info->duplex = DUPLEX_FULL;
487 else
488 mii_info->duplex = DUPLEX_HALF;
490 speed = status & MII_CIS8201_AUXCONSTAT_SPEED;
492 switch (speed) {
493 case MII_CIS8201_AUXCONSTAT_GBIT:
494 mii_info->speed = SPEED_1000;
495 break;
496 case MII_CIS8201_AUXCONSTAT_100:
497 mii_info->speed = SPEED_100;
498 break;
499 default:
500 mii_info->speed = SPEED_10;
501 break;
502 }
503 }
505 return 0;
506 }
508 static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info)
509 {
510 ugphy_vdbg("%s: IN", __FUNCTION__);
512 phy_read(mii_info, MII_CIS8201_ISTAT);
514 return 0;
515 }
517 static int cis820x_config_intr(struct ugeth_mii_info *mii_info)
518 {
519 ugphy_vdbg("%s: IN", __FUNCTION__);
521 if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
522 phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK);
523 else
524 phy_write(mii_info, MII_CIS8201_IMASK, 0);
526 return 0;
527 }
529 #define DM9161_DELAY 10
531 static int dm9161_read_status(struct ugeth_mii_info *mii_info)
532 {
533 u16 status;
534 int err;
536 ugphy_vdbg("%s: IN", __FUNCTION__);
538 /* Update the link, but return if there
539 * was an error */
540 err = genmii_update_link(mii_info);
541 if (err)
542 return err;
544 /* If the link is up, read the speed and duplex */
545 /* If we aren't autonegotiating, assume speeds
546 * are as set */
547 if (mii_info->autoneg && mii_info->link) {
548 status = phy_read(mii_info, MII_DM9161_SCSR);
549 if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H))
550 mii_info->speed = SPEED_100;
551 else
552 mii_info->speed = SPEED_10;
554 if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F))
555 mii_info->duplex = DUPLEX_FULL;
556 else
557 mii_info->duplex = DUPLEX_HALF;
558 }
560 return 0;
561 }
563 static int dm9161_config_aneg(struct ugeth_mii_info *mii_info)
564 {
565 struct dm9161_private *priv = mii_info->priv;
567 ugphy_vdbg("%s: IN", __FUNCTION__);
569 if (0 == priv->resetdone)
570 return -EAGAIN;
572 return 0;
573 }
575 static void dm9161_timer(unsigned long data)
576 {
577 struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
578 struct dm9161_private *priv = mii_info->priv;
579 u16 status = phy_read(mii_info, MII_BMSR);
581 ugphy_vdbg("%s: IN", __FUNCTION__);
583 if (status & BMSR_ANEGCOMPLETE) {
584 priv->resetdone = 1;
585 } else
586 mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
587 }
589 static int dm9161_init(struct ugeth_mii_info *mii_info)
590 {
591 struct dm9161_private *priv;
593 ugphy_vdbg("%s: IN", __FUNCTION__);
595 /* Allocate the private data structure */
596 priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL);
598 if (NULL == priv)
599 return -ENOMEM;
601 mii_info->priv = priv;
603 /* Reset is not done yet */
604 priv->resetdone = 0;
606 phy_write(mii_info, MII_BMCR,
607 phy_read(mii_info, MII_BMCR) | BMCR_RESET);
609 phy_write(mii_info, MII_BMCR,
610 phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE);
612 config_genmii_advert(mii_info);
613 /* Start/Restart aneg */
614 genmii_config_aneg(mii_info);
616 /* Start a timer for DM9161_DELAY seconds to wait
617 * for the PHY to be ready */
618 init_timer(&priv->timer);
619 priv->timer.function = &dm9161_timer;
620 priv->timer.data = (unsigned long)mii_info;
621 mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
623 return 0;
624 }
626 static void dm9161_close(struct ugeth_mii_info *mii_info)
627 {
628 struct dm9161_private *priv = mii_info->priv;
630 ugphy_vdbg("%s: IN", __FUNCTION__);
632 del_timer_sync(&priv->timer);
633 kfree(priv);
634 }
636 static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info)
637 {
638 /* FIXME: This lines are for BUG fixing in the mpc8325.
639 Remove this from here when it's fixed */
640 if (bcsr_regs == NULL)
641 bcsr_regs = (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE);
642 bcsr_regs[14] |= 0x40;
643 ugphy_vdbg("%s: IN", __FUNCTION__);
645 /* Clear the interrupts by reading the reg */
646 phy_read(mii_info, MII_DM9161_INTR);
649 return 0;
650 }
652 static int dm9161_config_intr(struct ugeth_mii_info *mii_info)
653 {
654 /* FIXME: This lines are for BUG fixing in the mpc8325.
655 Remove this from here when it's fixed */
656 if (bcsr_regs == NULL) {
657 bcsr_regs = (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE);
658 bcsr_regs[14] &= ~0x40;
659 }
660 ugphy_vdbg("%s: IN", __FUNCTION__);
662 if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
663 phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT);
664 else
665 phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP);
667 return 0;
668 }
670 /* Cicada 820x */
671 static struct phy_info phy_info_cis820x = {
672 .phy_id = 0x000fc440,
673 .name = "Cicada Cis8204",
674 .phy_id_mask = 0x000fffc0,
675 .features = MII_GBIT_FEATURES,
676 .init = &cis820x_init,
677 .config_aneg = &gbit_config_aneg,
678 .read_status = &cis820x_read_status,
679 .ack_interrupt = &cis820x_ack_interrupt,
680 .config_intr = &cis820x_config_intr,
681 };
683 static struct phy_info phy_info_dm9161 = {
684 .phy_id = 0x0181b880,
685 .phy_id_mask = 0x0ffffff0,
686 .name = "Davicom DM9161E",
687 .init = dm9161_init,
688 .config_aneg = dm9161_config_aneg,
689 .read_status = dm9161_read_status,
690 .close = dm9161_close,
691 };
693 static struct phy_info phy_info_dm9161a = {
694 .phy_id = 0x0181b8a0,
695 .phy_id_mask = 0x0ffffff0,
696 .name = "Davicom DM9161A",
697 .features = MII_BASIC_FEATURES,
698 .init = dm9161_init,
699 .config_aneg = dm9161_config_aneg,
700 .read_status = dm9161_read_status,
701 .ack_interrupt = dm9161_ack_interrupt,
702 .config_intr = dm9161_config_intr,
703 .close = dm9161_close,
704 };
706 static struct phy_info phy_info_marvell = {
707 .phy_id = 0x01410c00,
708 .phy_id_mask = 0xffffff00,
709 .name = "Marvell 88E11x1",
710 .features = MII_GBIT_FEATURES,
711 .init = &marvell_init,
712 .config_aneg = &marvell_config_aneg,
713 .read_status = &marvell_read_status,
714 .ack_interrupt = &marvell_ack_interrupt,
715 .config_intr = &marvell_config_intr,
716 };
718 static struct phy_info phy_info_genmii = {
719 .phy_id = 0x00000000,
720 .phy_id_mask = 0x00000000,
721 .name = "Generic MII",
722 .features = MII_BASIC_FEATURES,
723 .config_aneg = genmii_config_aneg,
724 .read_status = genmii_read_status,
725 };
727 static struct phy_info *phy_info[] = {
728 &phy_info_cis820x,
729 &phy_info_marvell,
730 &phy_info_dm9161,
731 &phy_info_dm9161a,
732 &phy_info_genmii,
733 NULL
734 };
736 u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum)
737 {
738 u16 retval;
739 unsigned long flags;
741 ugphy_vdbg("%s: IN", __FUNCTION__);
743 spin_lock_irqsave(&mii_info->mdio_lock, flags);
744 retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum);
745 spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
747 return retval;
748 }
750 void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val)
751 {
752 unsigned long flags;
754 ugphy_vdbg("%s: IN", __FUNCTION__);
756 spin_lock_irqsave(&mii_info->mdio_lock, flags);
757 mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val);
758 spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
759 }
761 /* Use the PHY ID registers to determine what type of PHY is attached
762 * to device dev. return a struct phy_info structure describing that PHY
763 */
764 struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info)
765 {
766 u16 phy_reg;
767 u32 phy_ID;
768 int i;
769 struct phy_info *theInfo = NULL;
770 struct net_device *dev = mii_info->dev;
772 ugphy_vdbg("%s: IN", __FUNCTION__);
774 /* Grab the bits from PHYIR1, and put them in the upper half */
775 phy_reg = phy_read(mii_info, MII_PHYSID1);
776 phy_ID = (phy_reg & 0xffff) << 16;
778 /* Grab the bits from PHYIR2, and put them in the lower half */
779 phy_reg = phy_read(mii_info, MII_PHYSID2);
780 phy_ID |= (phy_reg & 0xffff);
782 /* loop through all the known PHY types, and find one that */
783 /* matches the ID we read from the PHY. */
784 for (i = 0; phy_info[i]; i++)
785 if (phy_info[i]->phy_id == (phy_ID & phy_info[i]->phy_id_mask)){
786 theInfo = phy_info[i];
787 break;
788 }
790 /* This shouldn't happen, as we have generic PHY support */
791 if (theInfo == NULL) {
792 ugphy_info("%s: PHY id %x is not supported!", dev->name,
793 phy_ID);
794 return NULL;
795 } else {
796 ugphy_info("%s: PHY is %s (%x)", dev->name, theInfo->name,
797 phy_ID);
798 }
800 return theInfo;
801 }