[ixp4xx] add switch support to the npe driver
[openwrt/svn-archive/archive.git] / target / linux / ixp4xx / patches-2.6.24 / 202-npe_driver_switch_support.patch
1 Index: linux-2.6.24.2/drivers/net/arm/ixp4xx_eth.c
2 ===================================================================
3 --- linux-2.6.24.2.orig/drivers/net/arm/ixp4xx_eth.c
4 +++ linux-2.6.24.2/drivers/net/arm/ixp4xx_eth.c
5 @@ -165,14 +165,15 @@ struct port {
6 struct net_device *netdev;
7 struct napi_struct napi;
8 struct net_device_stats stat;
9 - struct mii_if_info mii;
10 + struct mii_if_info mii[IXP4XX_ETH_PHY_MAX_ADDR];
11 struct delayed_work mdio_thread;
12 struct eth_plat_info *plat;
13 buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS];
14 struct desc *desc_tab; /* coherent */
15 u32 desc_tab_phys;
16 int id; /* logical port ID */
17 - u16 mii_bmcr;
18 + u16 mii_bmcr[IXP4XX_ETH_PHY_MAX_ADDR];
19 + int phy_count;
20 };
21
22 /* NPE message structure */
23 @@ -316,13 +317,14 @@ static void mdio_write(struct net_device
24 spin_unlock_irqrestore(&mdio_lock, flags);
25 }
26
27 -static void phy_reset(struct net_device *dev, int phy_id)
28 +static void phy_reset(struct net_device *dev, int idx)
29 {
30 struct port *port = netdev_priv(dev);
31 + int phy_id = port->mii[idx].phy_id;
32 int cycles = 0;
33
34 - mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr | BMCR_RESET);
35 -
36 + mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr[idx] | BMCR_RESET);
37 +
38 while (cycles < MAX_MII_RESET_RETRIES) {
39 if (!(mdio_read(dev, phy_id, MII_BMCR) & BMCR_RESET)) {
40 #if DEBUG_MDIO
41 @@ -335,12 +337,12 @@ static void phy_reset(struct net_device
42 cycles++;
43 }
44
45 - printk(KERN_ERR "%s: MII reset failed\n", dev->name);
46 + printk(KERN_ERR "%s: MII reset failed on PHY%2d\n", dev->name, phy_id);
47 }
48
49 -static void eth_set_duplex(struct port *port)
50 +static void eth_set_duplex(struct port *port, int full_duplex)
51 {
52 - if (port->mii.full_duplex)
53 + if (full_duplex)
54 __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
55 &port->regs->tx_control[0]);
56 else
57 @@ -348,7 +350,7 @@ static void eth_set_duplex(struct port *
58 &port->regs->tx_control[0]);
59 }
60
61 -
62 +#if 0
63 static void phy_check_media(struct port *port, int init)
64 {
65 if (mii_check_media(&port->mii, 1, init))
66 @@ -367,7 +369,63 @@ static void phy_check_media(struct port
67 }
68 }
69 }
70 +#else
71 +static void phy_update_link(struct net_device *dev, int link)
72 +{
73 + int prev_link = netif_carrier_ok(dev);
74 +
75 + if (!prev_link && link) {
76 + printk(KERN_INFO "%s: link up\n", dev->name);
77 + netif_carrier_on(dev);
78 + } else if (prev_link && !link) {
79 + printk(KERN_INFO "%s: link down\n", dev->name);
80 + netif_carrier_off(dev);
81 + }
82 +}
83 +
84 +static void phy_check_media(struct port *port, int init)
85 +{
86 + struct net_device *dev = port->netdev;
87 +
88 + if (port->phy_count == 1) {
89 + struct mii_if_info *mii = &port->mii[0];
90 +
91 + if (mii_check_media(mii, 1, init))
92 + eth_set_duplex(port, mii->full_duplex);
93 +
94 + if (mii->force_media) /* mii_check_media() doesn't work */
95 + phy_update_link(dev, mii_link_ok(mii));
96 + } else {
97 + int cur_link = 0;
98 + int i;
99 +
100 + if (init)
101 + eth_set_duplex(port, 1);
102 +
103 + for (i = 0; i < port->phy_count; i++)
104 + cur_link |= mii_link_ok(&port->mii[i]);
105 +
106 + phy_update_link(dev, cur_link);
107 + }
108 +}
109 +#endif
110
111 +static void phy_power_down(struct net_device *dev, int idx)
112 +{
113 + struct port *port = netdev_priv(dev);
114 + int phy_id = port->mii[idx].phy_id;
115 +
116 + port->mii_bmcr[idx] = mdio_read(dev, phy_id, MII_BMCR) &
117 + ~(BMCR_RESET | BMCR_PDOWN);
118 + mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr[idx] | BMCR_PDOWN);
119 +}
120 +
121 +static void phy_power_up(struct net_device *dev, int idx)
122 +{
123 + struct port *port = netdev_priv(dev);
124 +
125 + mdio_write(dev, port->mii[idx].phy_id, MII_BMCR, port->mii_bmcr[idx]);
126 +}
127
128 static void mdio_thread(struct work_struct *work)
129 {
130 @@ -790,9 +848,12 @@ static int eth_ioctl(struct net_device *
131
132 if (!netif_running(dev))
133 return -EINVAL;
134 - err = generic_mii_ioctl(&port->mii, if_mii(req), cmd, &duplex_chg);
135 + if (port->phy_count != 1)
136 + return -EOPNOTSUPP;
137 +
138 + err = generic_mii_ioctl(&port->mii[0], if_mii(req), cmd, &duplex_chg);
139 if (duplex_chg)
140 - eth_set_duplex(port);
141 + eth_set_duplex(port, port->mii[0].full_duplex);
142 return err;
143 }
144
145 @@ -944,7 +1005,8 @@ static int eth_open(struct net_device *d
146 }
147 }
148
149 - mdio_write(dev, port->plat->phy, MII_BMCR, port->mii_bmcr);
150 + for (i = 0; i < port->phy_count; i++)
151 + phy_power_up(dev, i);
152
153 memset(&msg, 0, sizeof(msg));
154 msg.cmd = NPE_VLAN_SETRXQOSENTRY;
155 @@ -1103,10 +1165,8 @@ static int eth_close(struct net_device *
156 printk(KERN_CRIT "%s: unable to disable loopback\n",
157 dev->name);
158
159 - port->mii_bmcr = mdio_read(dev, port->plat->phy, MII_BMCR) &
160 - ~(BMCR_RESET | BMCR_PDOWN); /* may have been altered */
161 - mdio_write(dev, port->plat->phy, MII_BMCR,
162 - port->mii_bmcr | BMCR_PDOWN);
163 + for (i = 0; i < port->phy_count; i++)
164 + phy_power_down(dev, i);
165
166 if (!ports_open)
167 qmgr_disable_irq(TXDONE_QUEUE);
168 @@ -1117,6 +1177,42 @@ static int eth_close(struct net_device *
169 return 0;
170 }
171
172 +static void eth_add_phy(struct net_device *dev, int phy_id)
173 +{
174 + struct port *port = netdev_priv(dev);
175 + int i;
176 +
177 + i = port->phy_count++;
178 +
179 + port->mii[i].dev = dev;
180 + port->mii[i].mdio_read = mdio_read;
181 + port->mii[i].mdio_write = mdio_write;
182 + port->mii[i].phy_id = phy_id;
183 + port->mii[i].phy_id_mask = 0x1F;
184 + port->mii[i].reg_num_mask = 0x1F;
185 +
186 + printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, phy_id,
187 + npe_name(port->npe));
188 +
189 + phy_reset(dev, i);
190 + phy_power_down(dev, i);
191 +}
192 +
193 +static void eth_init_mii(struct net_device *dev)
194 +{
195 + struct port *port = netdev_priv(dev);
196 +
197 + if (port->plat->phy < IXP4XX_ETH_PHY_MAX_ADDR) {
198 + eth_add_phy(dev, port->plat->phy);
199 + } else {
200 + int i;
201 + for (i = 0; i < IXP4XX_ETH_PHY_MAX_ADDR; i++)
202 + if (port->plat->phy_mask & (1U << i))
203 + eth_add_phy(dev, i);
204 + }
205 +
206 +}
207 +
208 static int __devinit eth_init_one(struct platform_device *pdev)
209 {
210 struct port *port;
211 @@ -1189,20 +1285,7 @@ static int __devinit eth_init_one(struct
212 __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
213 udelay(50);
214
215 - port->mii.dev = dev;
216 - port->mii.mdio_read = mdio_read;
217 - port->mii.mdio_write = mdio_write;
218 - port->mii.phy_id = plat->phy;
219 - port->mii.phy_id_mask = 0x1F;
220 - port->mii.reg_num_mask = 0x1F;
221 -
222 - printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,
223 - npe_name(port->npe));
224 -
225 - phy_reset(dev, plat->phy);
226 - port->mii_bmcr = mdio_read(dev, plat->phy, MII_BMCR) &
227 - ~(BMCR_RESET | BMCR_PDOWN);
228 - mdio_write(dev, plat->phy, MII_BMCR, port->mii_bmcr | BMCR_PDOWN);
229 + eth_init_mii(dev);
230
231 INIT_DELAYED_WORK(&port->mdio_thread, mdio_thread);
232 return 0;
233 Index: linux-2.6.24.2/include/asm-arm/arch-ixp4xx/platform.h
234 ===================================================================
235 --- linux-2.6.24.2.orig/include/asm-arm/arch-ixp4xx/platform.h
236 +++ linux-2.6.24.2/include/asm-arm/arch-ixp4xx/platform.h
237 @@ -106,12 +106,15 @@ struct sys_timer;
238 #define IXP4XX_ETH_NPEB 0x10
239 #define IXP4XX_ETH_NPEC 0x20
240
241 +#define IXP4XX_ETH_PHY_MAX_ADDR 32
242 +
243 /* Information about built-in Ethernet MAC interfaces */
244 struct eth_plat_info {
245 u8 phy; /* MII PHY ID, 0 - 31 */
246 u8 rxq; /* configurable, currently 0 - 31 only */
247 u8 txreadyq;
248 u8 hwaddr[6];
249 + u32 phy_mask;
250 };
251
252 /* Information about built-in HSS (synchronous serial) interfaces */