8f75415145d49a2cbcb1280b05ced27ebf5353c5
[openwrt.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 @@ 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 */
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 @@ static void mdio_write(struct net_device
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 @@ static void phy_reset(struct net_device 
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 @@ static void eth_set_duplex(struct port *
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 @@ static void phy_check_media(struct port 
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 @@ static int eth_ioctl(struct net_device *
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 @@ static int eth_open(struct net_device *d
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 @@ static int eth_close(struct net_device *
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 @@ static int eth_close(struct net_device *
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 @@ static int __devinit eth_init_one(struct
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 @@ struct sys_timer;
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 */