1 --- a/drivers/net/arm/ixp4xx_eth.c
2 +++ b/drivers/net/arm/ixp4xx_eth.c
3 @@ -165,14 +165,15 @@ struct port {
4 struct net_device *netdev;
5 struct napi_struct napi;
6 struct net_device_stats stat;
7 - struct mii_if_info mii;
8 + struct mii_if_info mii[IXP4XX_ETH_PHY_MAX_ADDR];
9 struct delayed_work mdio_thread;
10 struct eth_plat_info *plat;
11 buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS];
12 struct desc *desc_tab; /* coherent */
14 int id; /* logical port ID */
16 + u16 mii_bmcr[IXP4XX_ETH_PHY_MAX_ADDR];
20 /* NPE message structure */
21 @@ -316,12 +317,13 @@ static void mdio_write(struct net_device
22 spin_unlock_irqrestore(&mdio_lock, flags);
25 -static void phy_reset(struct net_device *dev, int phy_id)
26 +static void phy_reset(struct net_device *dev, int idx)
28 struct port *port = netdev_priv(dev);
29 + int phy_id = port->mii[idx].phy_id;
32 - mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr | BMCR_RESET);
33 + mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr[idx] | BMCR_RESET);
35 while (cycles < MAX_MII_RESET_RETRIES) {
36 if (!(mdio_read(dev, phy_id, MII_BMCR) & BMCR_RESET)) {
37 @@ -335,12 +337,12 @@ static void phy_reset(struct net_device
41 - printk(KERN_ERR "%s: MII reset failed\n", dev->name);
42 + printk(KERN_ERR "%s: MII reset failed on PHY%2d\n", dev->name, phy_id);
45 -static void eth_set_duplex(struct port *port)
46 +static void eth_set_duplex(struct port *port, int full_duplex)
48 - if (port->mii.full_duplex)
50 __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
51 &port->regs->tx_control[0]);
53 @@ -348,7 +350,7 @@ static void eth_set_duplex(struct port *
54 &port->regs->tx_control[0]);
59 static void phy_check_media(struct port *port, int init)
61 if (mii_check_media(&port->mii, 1, init))
62 @@ -367,7 +369,63 @@ static void phy_check_media(struct port
67 +static void phy_update_link(struct net_device *dev, int link)
69 + int prev_link = netif_carrier_ok(dev);
71 + if (!prev_link && link) {
72 + printk(KERN_INFO "%s: link up\n", dev->name);
73 + netif_carrier_on(dev);
74 + } else if (prev_link && !link) {
75 + printk(KERN_INFO "%s: link down\n", dev->name);
76 + netif_carrier_off(dev);
80 +static void phy_check_media(struct port *port, int init)
82 + struct net_device *dev = port->netdev;
84 + if (port->phy_count == 1) {
85 + struct mii_if_info *mii = &port->mii[0];
87 + if (mii_check_media(mii, 1, init))
88 + eth_set_duplex(port, mii->full_duplex);
90 + if (mii->force_media) /* mii_check_media() doesn't work */
91 + phy_update_link(dev, mii_link_ok(mii));
97 + eth_set_duplex(port, 1);
99 + for (i = 0; i < port->phy_count; i++)
100 + cur_link |= mii_link_ok(&port->mii[i]);
102 + phy_update_link(dev, cur_link);
107 +static void phy_power_down(struct net_device *dev, int idx)
109 + struct port *port = netdev_priv(dev);
110 + int phy_id = port->mii[idx].phy_id;
112 + port->mii_bmcr[idx] = mdio_read(dev, phy_id, MII_BMCR) &
113 + ~(BMCR_RESET | BMCR_PDOWN);
114 + mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr[idx] | BMCR_PDOWN);
117 +static void phy_power_up(struct net_device *dev, int idx)
119 + struct port *port = netdev_priv(dev);
121 + mdio_write(dev, port->mii[idx].phy_id, MII_BMCR, port->mii_bmcr[idx]);
124 static void mdio_thread(struct work_struct *work)
126 @@ -792,9 +850,12 @@ static int eth_ioctl(struct net_device *
128 if (!netif_running(dev))
130 - err = generic_mii_ioctl(&port->mii, if_mii(req), cmd, &duplex_chg);
131 + if (port->phy_count != 1)
132 + return -EOPNOTSUPP;
134 + err = generic_mii_ioctl(&port->mii[0], if_mii(req), cmd, &duplex_chg);
136 - eth_set_duplex(port);
137 + eth_set_duplex(port, port->mii[0].full_duplex);
141 @@ -947,7 +1008,8 @@ static int eth_open(struct net_device *d
145 - mdio_write(dev, port->plat->phy, MII_BMCR, port->mii_bmcr);
146 + for (i = 0; i < port->phy_count; i++)
147 + phy_power_up(dev, i);
149 memset(&msg, 0, sizeof(msg));
150 msg.cmd = NPE_VLAN_SETRXQOSENTRY;
151 @@ -1107,10 +1169,8 @@ static int eth_close(struct net_device *
152 printk(KERN_CRIT "%s: unable to disable loopback\n",
155 - port->mii_bmcr = mdio_read(dev, port->plat->phy, MII_BMCR) &
156 - ~(BMCR_RESET | BMCR_PDOWN); /* may have been altered */
157 - mdio_write(dev, port->plat->phy, MII_BMCR,
158 - port->mii_bmcr | BMCR_PDOWN);
159 + for (i = 0; i < port->phy_count; i++)
160 + phy_power_down(dev, i);
163 qmgr_disable_irq(TXDONE_QUEUE);
164 @@ -1120,6 +1180,42 @@ static int eth_close(struct net_device *
168 +static void eth_add_phy(struct net_device *dev, int phy_id)
170 + struct port *port = netdev_priv(dev);
173 + i = port->phy_count++;
175 + port->mii[i].dev = dev;
176 + port->mii[i].mdio_read = mdio_read;
177 + port->mii[i].mdio_write = mdio_write;
178 + port->mii[i].phy_id = phy_id;
179 + port->mii[i].phy_id_mask = 0x1F;
180 + port->mii[i].reg_num_mask = 0x1F;
182 + printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, phy_id,
183 + npe_name(port->npe));
186 + phy_power_down(dev, i);
189 +static void eth_init_mii(struct net_device *dev)
191 + struct port *port = netdev_priv(dev);
193 + if (port->plat->phy < IXP4XX_ETH_PHY_MAX_ADDR) {
194 + eth_add_phy(dev, port->plat->phy);
197 + for (i = 0; i < IXP4XX_ETH_PHY_MAX_ADDR; i++)
198 + if (port->plat->phy_mask & (1U << i))
199 + eth_add_phy(dev, i);
204 static int __devinit eth_init_one(struct platform_device *pdev)
207 @@ -1192,20 +1288,7 @@ static int __devinit eth_init_one(struct
208 __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
211 - port->mii.dev = dev;
212 - port->mii.mdio_read = mdio_read;
213 - port->mii.mdio_write = mdio_write;
214 - port->mii.phy_id = plat->phy;
215 - port->mii.phy_id_mask = 0x1F;
216 - port->mii.reg_num_mask = 0x1F;
218 - printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,
219 - npe_name(port->npe));
221 - phy_reset(dev, plat->phy);
222 - port->mii_bmcr = mdio_read(dev, plat->phy, MII_BMCR) &
223 - ~(BMCR_RESET | BMCR_PDOWN);
224 - mdio_write(dev, plat->phy, MII_BMCR, port->mii_bmcr | BMCR_PDOWN);
227 INIT_DELAYED_WORK(&port->mdio_thread, mdio_thread);
229 --- a/include/asm-arm/arch-ixp4xx/platform.h
230 +++ b/include/asm-arm/arch-ixp4xx/platform.h
231 @@ -95,12 +95,15 @@ struct sys_timer;
232 #define IXP4XX_ETH_NPEB 0x10
233 #define IXP4XX_ETH_NPEC 0x20
235 +#define IXP4XX_ETH_PHY_MAX_ADDR 32
237 /* Information about built-in Ethernet MAC interfaces */
238 struct eth_plat_info {
239 u8 phy; /* MII PHY ID, 0 - 31 */
240 u8 rxq; /* configurable, currently 0 - 31 only */
246 /* Information about built-in HSS (synchronous serial) interfaces */