ixp4xx 2.6.26 support
[openwrt/svn-archive/archive.git] / target / linux / ixp4xx / patches-2.6.26 / 202-npe_driver_switch_support.patch
1 --- a/drivers/net/arm/ixp4xx_eth.c
2 +++ b/drivers/net/arm/ixp4xx_eth.c
3 @@ -165,14 +165,15 @@
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 */
13 u32 desc_tab_phys;
14 int id; /* logical port ID */
15 - u16 mii_bmcr;
16 + u16 mii_bmcr[IXP4XX_ETH_PHY_MAX_ADDR];
17 + int phy_count;
18 };
19
20 /* NPE message structure */
21 @@ -316,12 +317,13 @@
22 spin_unlock_irqrestore(&mdio_lock, flags);
23 }
24
25 -static void phy_reset(struct net_device *dev, int phy_id)
26 +static void phy_reset(struct net_device *dev, int idx)
27 {
28 struct port *port = netdev_priv(dev);
29 + int phy_id = port->mii[idx].phy_id;
30 int cycles = 0;
31
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);
34
35 while (cycles < MAX_MII_RESET_RETRIES) {
36 if (!(mdio_read(dev, phy_id, MII_BMCR) & BMCR_RESET)) {
37 @@ -335,12 +337,12 @@
38 cycles++;
39 }
40
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);
43 }
44
45 -static void eth_set_duplex(struct port *port)
46 +static void eth_set_duplex(struct port *port, int full_duplex)
47 {
48 - if (port->mii.full_duplex)
49 + if (full_duplex)
50 __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
51 &port->regs->tx_control[0]);
52 else
53 @@ -348,7 +350,7 @@
54 &port->regs->tx_control[0]);
55 }
56
57 -
58 +#if 0
59 static void phy_check_media(struct port *port, int init)
60 {
61 if (mii_check_media(&port->mii, 1, init))
62 @@ -367,7 +369,63 @@
63 }
64 }
65 }
66 +#else
67 +static void phy_update_link(struct net_device *dev, int link)
68 +{
69 + int prev_link = netif_carrier_ok(dev);
70 +
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);
77 + }
78 +}
79 +
80 +static void phy_check_media(struct port *port, int init)
81 +{
82 + struct net_device *dev = port->netdev;
83 +
84 + if (port->phy_count == 1) {
85 + struct mii_if_info *mii = &port->mii[0];
86 +
87 + if (mii_check_media(mii, 1, init))
88 + eth_set_duplex(port, mii->full_duplex);
89 +
90 + if (mii->force_media) /* mii_check_media() doesn't work */
91 + phy_update_link(dev, mii_link_ok(mii));
92 + } else {
93 + int cur_link = 0;
94 + int i;
95 +
96 + if (init)
97 + eth_set_duplex(port, 1);
98 +
99 + for (i = 0; i < port->phy_count; i++)
100 + cur_link |= mii_link_ok(&port->mii[i]);
101 +
102 + phy_update_link(dev, cur_link);
103 + }
104 +}
105 +#endif
106 +
107 +static void phy_power_down(struct net_device *dev, int idx)
108 +{
109 + struct port *port = netdev_priv(dev);
110 + int phy_id = port->mii[idx].phy_id;
111 +
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);
115 +}
116 +
117 +static void phy_power_up(struct net_device *dev, int idx)
118 +{
119 + struct port *port = netdev_priv(dev);
120
121 + mdio_write(dev, port->mii[idx].phy_id, MII_BMCR, port->mii_bmcr[idx]);
122 +}
123
124 static void mdio_thread(struct work_struct *work)
125 {
126 @@ -792,9 +850,12 @@
127
128 if (!netif_running(dev))
129 return -EINVAL;
130 - err = generic_mii_ioctl(&port->mii, if_mii(req), cmd, &duplex_chg);
131 + if (port->phy_count != 1)
132 + return -EOPNOTSUPP;
133 +
134 + err = generic_mii_ioctl(&port->mii[0], if_mii(req), cmd, &duplex_chg);
135 if (duplex_chg)
136 - eth_set_duplex(port);
137 + eth_set_duplex(port, port->mii[0].full_duplex);
138 return err;
139 }
140
141 @@ -947,7 +1008,8 @@
142 }
143 }
144
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);
148
149 memset(&msg, 0, sizeof(msg));
150 msg.cmd = NPE_VLAN_SETRXQOSENTRY;
151 @@ -1107,10 +1169,8 @@
152 printk(KERN_CRIT "%s: unable to disable loopback\n",
153 dev->name);
154
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);
161
162 if (!ports_open)
163 qmgr_disable_irq(TXDONE_QUEUE);
164 @@ -1120,6 +1180,42 @@
165 return 0;
166 }
167
168 +static void eth_add_phy(struct net_device *dev, int phy_id)
169 +{
170 + struct port *port = netdev_priv(dev);
171 + int i;
172 +
173 + i = port->phy_count++;
174 +
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;
181 +
182 + printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, phy_id,
183 + npe_name(port->npe));
184 +
185 + phy_reset(dev, i);
186 + phy_power_down(dev, i);
187 +}
188 +
189 +static void eth_init_mii(struct net_device *dev)
190 +{
191 + struct port *port = netdev_priv(dev);
192 +
193 + if (port->plat->phy < IXP4XX_ETH_PHY_MAX_ADDR) {
194 + eth_add_phy(dev, port->plat->phy);
195 + } else {
196 + int i;
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);
200 + }
201 +
202 +}
203 +
204 static int __devinit eth_init_one(struct platform_device *pdev)
205 {
206 struct port *port;
207 @@ -1192,20 +1288,7 @@
208 __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
209 udelay(50);
210
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;
217 -
218 - printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,
219 - npe_name(port->npe));
220 -
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);
225 + eth_init_mii(dev);
226
227 INIT_DELAYED_WORK(&port->mdio_thread, mdio_thread);
228 return 0;
229 --- a/include/asm-arm/arch-ixp4xx/platform.h
230 +++ b/include/asm-arm/arch-ixp4xx/platform.h
231 @@ -95,12 +95,15 @@
232 #define IXP4XX_ETH_NPEB 0x10
233 #define IXP4XX_ETH_NPEC 0x20
234
235 +#define IXP4XX_ETH_PHY_MAX_ADDR 32
236 +
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 */
241 u8 txreadyq;
242 u8 hwaddr[6];
243 + u32 phy_mask;
244 };
245
246 /* Information about built-in HSS (synchronous serial) interfaces */