brcm-2.6: remove old b44 support patches, integrate bcm47xx support into newest versi...
[openwrt.git] / target / linux / brcm-2.6 / patches / 004-b44_bcm47xx_support.patch
1 diff -urN linux.old/drivers/net/b44.c linux.dev/drivers/net/b44.c
2 --- linux.old/drivers/net/b44.c 2006-01-12 01:44:42.548326000 +0100
3 +++ linux.dev/drivers/net/b44.c 2006-01-12 03:07:38.209775500 +0100
4 @@ -1,7 +1,9 @@
5 -/* b44.c: Broadcom 4400 device driver.
6 +/* b44.c: Broadcom 4400/47xx device driver.
7   *
8   * Copyright (C) 2002 David S. Miller (davem@redhat.com)
9 - * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
10 + * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi)
11 + * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
12 + * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org)
13   *
14   * Distribute under GPL.
15   */
16 @@ -31,6 +33,28 @@
17  #define DRV_MODULE_VERSION     "0.97"
18  #define DRV_MODULE_RELDATE     "Nov 30, 2005"
19  
20 +#ifdef CONFIG_BCM947XX
21 +extern char *nvram_get(char *name);
22 +static inline void e_aton(char *str, char *dest)
23 +{
24 +       int i = 0;
25 +
26 +       if (str == NULL) {
27 +               memset(dest, 0, 6);
28 +               return;
29 +       }
30 +       
31 +       for (;;) {
32 +               dest[i++] = (char) simple_strtoul(str, NULL, 16);
33 +               str += 2;
34 +               if (!*str++ || i == 6)
35 +                       break;
36 +       }
37 +}
38 +
39 +static int b44_4713_instance;
40 +#endif
41 +
42  #define B44_DEF_MSG_ENABLE       \
43         (NETIF_MSG_DRV          | \
44          NETIF_MSG_PROBE        | \
45 @@ -77,8 +101,8 @@
46  static char version[] __devinitdata =
47         DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
48  
49 -MODULE_AUTHOR("Florian Schirmer, Pekka Pietikainen, David S. Miller");
50 -MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver");
51 +MODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller");
52 +MODULE_DESCRIPTION("Broadcom 4400/47xx 10/100 PCI ethernet driver");
53  MODULE_LICENSE("GPL");
54  MODULE_VERSION(DRV_MODULE_VERSION);
55  
56 @@ -93,6 +117,10 @@
57           PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
58         { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1,
59           PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
60 +#ifdef CONFIG_BCM947XX
61 +       { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4713,
62 +         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
63 +#endif
64         { }     /* terminate list with empty entry */
65  };
66  
67 @@ -131,17 +159,6 @@
68                                       dma_desc_sync_size, dir);
69  }
70  
71 -static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
72 -{
73 -       return readl(bp->regs + reg);
74 -}
75 -
76 -static inline void bw32(const struct b44 *bp, 
77 -                       unsigned long reg, unsigned long val)
78 -{
79 -       writel(val, bp->regs + reg);
80 -}
81 -
82  static int b44_wait_bit(struct b44 *bp, unsigned long reg,
83                         u32 bit, unsigned long timeout, const int clear)
84  {
85 @@ -268,6 +285,10 @@
86                 break;
87         };
88  #endif
89 +#ifdef CONFIG_BCM947XX
90 +       if (bp->pdev->device == PCI_DEVICE_ID_BCM4713)
91 +               return b44_4713_instance++;
92 +#endif
93         return 0;
94  }
95  
96 @@ -313,14 +334,14 @@
97         bw32(bp, B44_IMASK, bp->imask);
98  }
99  
100 -static int b44_readphy(struct b44 *bp, int reg, u32 *val)
101 +static int __b44_readphy(struct b44 *bp, int phy_addr, int reg, u32 *val)
102  {
103         int err;
104  
105         bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
106         bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
107                              (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) |
108 -                            (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
109 +                            (phy_addr << MDIO_DATA_PMD_SHIFT) |
110                              (reg << MDIO_DATA_RA_SHIFT) |
111                              (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT)));
112         err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
113 @@ -329,18 +350,34 @@
114         return err;
115  }
116  
117 -static int b44_writephy(struct b44 *bp, int reg, u32 val)
118 +static int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val)
119  {
120         bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
121         bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
122                              (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) |
123 -                            (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
124 +                            (phy_addr << MDIO_DATA_PMD_SHIFT) |
125                              (reg << MDIO_DATA_RA_SHIFT) |
126                              (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) |
127                              (val & MDIO_DATA_DATA)));
128         return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
129  }
130  
131 +static inline int b44_readphy(struct b44 *bp, int reg, u32 *val)
132 +{
133 +       if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
134 +               return 0;
135 +
136 +       return __b44_readphy(bp, bp->phy_addr, reg, val);
137 +}
138 +
139 +static inline int b44_writephy(struct b44 *bp, int reg, u32 val)
140 +{
141 +       if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
142 +               return 0;
143 +               
144 +       return __b44_writephy(bp, bp->phy_addr, reg, val);
145 +}
146 +
147  /* miilib interface */
148  /* FIXME FIXME: phy_id is ignored, bp->phy_addr use is unconditional
149   * due to code existing before miilib use was added to this driver.
150 @@ -369,6 +406,8 @@
151         u32 val;
152         int err;
153  
154 +       if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
155 +               return 0;
156         err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
157         if (err)
158                 return err;
159 @@ -439,6 +478,8 @@
160         u32 val;
161         int err;
162  
163 +       if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
164 +               return 0;
165         if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
166                 goto out;
167         if ((err = b44_writephy(bp, B44_MII_ALEDCTRL,
168 @@ -534,6 +575,19 @@
169  {
170         u32 bmsr, aux;
171  
172 +       if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
173 +               bp->flags |= B44_FLAG_100_BASE_T;
174 +               bp->flags |= B44_FLAG_FULL_DUPLEX;
175 +               if (!netif_carrier_ok(bp->dev)) {
176 +                       u32 val = br32(bp, B44_TX_CTRL);
177 +                       val |= TX_CTRL_DUPLEX;
178 +                       bw32(bp, B44_TX_CTRL, val);
179 +                       netif_carrier_on(bp->dev);
180 +                       b44_link_report(bp);
181 +               }
182 +               return;
183 +       }
184 +
185         if (!b44_readphy(bp, MII_BMSR, &bmsr) &&
186             !b44_readphy(bp, B44_MII_AUXCTRL, &aux) &&
187             (bmsr != 0xffff)) {
188 @@ -1281,9 +1335,10 @@
189                 bw32(bp, B44_DMARX_CTRL, 0);
190                 bp->rx_prod = bp->rx_cons = 0;
191         } else {
192 -               ssb_pci_setup(bp, (bp->core_unit == 0 ?
193 -                                  SBINTVEC_ENET0 :
194 -                                  SBINTVEC_ENET1));
195 +               if (bp->pdev->device != PCI_DEVICE_ID_BCM4713)
196 +                       ssb_pci_setup(bp, (bp->core_unit == 0 ?
197 +                                          SBINTVEC_ENET0 :
198 +                                          SBINTVEC_ENET1));
199         }
200  
201         ssb_core_reset(bp);
202 @@ -1291,8 +1346,14 @@
203         b44_clear_stats(bp);
204  
205         /* Make PHY accessible. */
206 -       bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
207 +       if (bp->pdev->device == PCI_DEVICE_ID_BCM4713)
208 +               bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
209 +                            (((100000000 + (B44_MDC_RATIO / 2)) / B44_MDC_RATIO)
210 +                            & MDIO_CTRL_MAXF_MASK)));
211 +       else
212 +               bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
213                              (0x0d & MDIO_CTRL_MAXF_MASK)));
214 +
215         br32(bp, B44_MDIO_CTRL);
216  
217         if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) {
218 @@ -1834,18 +1895,297 @@
219         .get_perm_addr          = ethtool_op_get_perm_addr,
220  };
221  
222 +static int b44_ethtool_ioctl (struct net_device *dev, void __user *useraddr)
223 +{
224 +       struct b44 *bp = dev->priv;
225 +       struct pci_dev *pci_dev = bp->pdev;
226 +       u32 ethcmd;
227 +
228 +       if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
229 +               return -EFAULT;
230 +
231 +       switch (ethcmd) {
232 +       case ETHTOOL_GDRVINFO: {
233 +               struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
234 +               strcpy (info.driver, DRV_MODULE_NAME);
235 +               strcpy (info.version, DRV_MODULE_VERSION);
236 +               memset(&info.fw_version, 0, sizeof(info.fw_version));
237 +               strcpy (info.bus_info, pci_name(pci_dev));
238 +               info.eedump_len = 0;
239 +               info.regdump_len = 0;
240 +               if (copy_to_user (useraddr, &info, sizeof (info)))
241 +                       return -EFAULT;
242 +               return 0;
243 +       }
244 +
245 +       case ETHTOOL_GSET: {
246 +               struct ethtool_cmd cmd = { ETHTOOL_GSET };
247 +
248 +               if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
249 +                       return -EAGAIN;
250 +               cmd.supported = (SUPPORTED_Autoneg);
251 +               cmd.supported |= (SUPPORTED_100baseT_Half |
252 +                                 SUPPORTED_100baseT_Full |
253 +                                 SUPPORTED_10baseT_Half |
254 +                                 SUPPORTED_10baseT_Full |
255 +                                 SUPPORTED_MII);
256 +
257 +               cmd.advertising = 0;
258 +               if (bp->flags & B44_FLAG_ADV_10HALF)
259 +                       cmd.advertising |= ADVERTISE_10HALF;
260 +               if (bp->flags & B44_FLAG_ADV_10FULL)
261 +                       cmd.advertising |= ADVERTISE_10FULL;
262 +               if (bp->flags & B44_FLAG_ADV_100HALF)
263 +                       cmd.advertising |= ADVERTISE_100HALF;
264 +               if (bp->flags & B44_FLAG_ADV_100FULL)
265 +                       cmd.advertising |= ADVERTISE_100FULL;
266 +               cmd.advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
267 +               cmd.speed = (bp->flags & B44_FLAG_100_BASE_T) ?
268 +                       SPEED_100 : SPEED_10;
269 +               cmd.duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ?
270 +                       DUPLEX_FULL : DUPLEX_HALF;
271 +               cmd.port = 0;
272 +               cmd.phy_address = bp->phy_addr;
273 +               cmd.transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ?
274 +                       XCVR_INTERNAL : XCVR_EXTERNAL;
275 +               cmd.autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ?
276 +                       AUTONEG_DISABLE : AUTONEG_ENABLE;
277 +               cmd.maxtxpkt = 0;
278 +               cmd.maxrxpkt = 0;
279 +               if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
280 +                       return -EFAULT;
281 +               return 0;
282 +       }
283 +       case ETHTOOL_SSET: {
284 +               struct ethtool_cmd cmd;
285 +
286 +               if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
287 +                       return -EAGAIN;
288 +
289 +               if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
290 +                       return -EFAULT;
291 +
292 +               /* We do not support gigabit. */
293 +               if (cmd.autoneg == AUTONEG_ENABLE) {
294 +                       if (cmd.advertising &
295 +                           (ADVERTISED_1000baseT_Half |
296 +                            ADVERTISED_1000baseT_Full))
297 +                               return -EINVAL;
298 +               } else if ((cmd.speed != SPEED_100 &&
299 +                           cmd.speed != SPEED_10) ||
300 +                          (cmd.duplex != DUPLEX_HALF &&
301 +                           cmd.duplex != DUPLEX_FULL)) {
302 +                               return -EINVAL;
303 +               }
304 +
305 +               spin_lock_irq(&bp->lock);
306 +
307 +               if (cmd.autoneg == AUTONEG_ENABLE) {
308 +                       bp->flags &= ~B44_FLAG_FORCE_LINK;
309 +                       bp->flags &= ~(B44_FLAG_ADV_10HALF |
310 +                                      B44_FLAG_ADV_10FULL |
311 +                                      B44_FLAG_ADV_100HALF |
312 +                                      B44_FLAG_ADV_100FULL);
313 +                       if (cmd.advertising & ADVERTISE_10HALF)
314 +                               bp->flags |= B44_FLAG_ADV_10HALF;
315 +                       if (cmd.advertising & ADVERTISE_10FULL)
316 +                               bp->flags |= B44_FLAG_ADV_10FULL;
317 +                       if (cmd.advertising & ADVERTISE_100HALF)
318 +                               bp->flags |= B44_FLAG_ADV_100HALF;
319 +                       if (cmd.advertising & ADVERTISE_100FULL)
320 +                               bp->flags |= B44_FLAG_ADV_100FULL;
321 +               } else {
322 +                       bp->flags |= B44_FLAG_FORCE_LINK;
323 +                       if (cmd.speed == SPEED_100)
324 +                               bp->flags |= B44_FLAG_100_BASE_T;
325 +                       if (cmd.duplex == DUPLEX_FULL)
326 +                               bp->flags |= B44_FLAG_FULL_DUPLEX;
327 +               }
328 +
329 +               b44_setup_phy(bp);
330 +
331 +               spin_unlock_irq(&bp->lock);
332 +
333 +               return 0;
334 +       }
335 +
336 +       case ETHTOOL_GMSGLVL: {
337 +               struct ethtool_value edata = { ETHTOOL_GMSGLVL };
338 +               edata.data = bp->msg_enable;
339 +               if (copy_to_user(useraddr, &edata, sizeof(edata)))
340 +                       return -EFAULT;
341 +               return 0;
342 +       }
343 +       case ETHTOOL_SMSGLVL: {
344 +               struct ethtool_value edata;
345 +               if (copy_from_user(&edata, useraddr, sizeof(edata)))
346 +                       return -EFAULT;
347 +               bp->msg_enable = edata.data;
348 +               return 0;
349 +       }
350 +       case ETHTOOL_NWAY_RST: {
351 +               u32 bmcr;
352 +               int r;
353 +
354 +               spin_lock_irq(&bp->lock);
355 +               b44_readphy(bp, MII_BMCR, &bmcr);
356 +               b44_readphy(bp, MII_BMCR, &bmcr);
357 +               r = -EINVAL;
358 +               if (bmcr & BMCR_ANENABLE) {
359 +                       b44_writephy(bp, MII_BMCR,
360 +                                    bmcr | BMCR_ANRESTART);
361 +                       r = 0;
362 +               }
363 +               spin_unlock_irq(&bp->lock);
364 +
365 +               return r;
366 +       }
367 +       case ETHTOOL_GLINK: {
368 +               struct ethtool_value edata = { ETHTOOL_GLINK };
369 +               edata.data = netif_carrier_ok(bp->dev) ? 1 : 0;
370 +               if (copy_to_user(useraddr, &edata, sizeof(edata)))
371 +                       return -EFAULT;
372 +               return 0;
373 +       }
374 +       case ETHTOOL_GRINGPARAM: {
375 +               struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
376 +
377 +               ering.rx_max_pending = B44_RX_RING_SIZE - 1;
378 +               ering.rx_pending = bp->rx_pending;
379 +
380 +               /* XXX ethtool lacks a tx_max_pending, oops... */
381 +
382 +               if (copy_to_user(useraddr, &ering, sizeof(ering)))
383 +                       return -EFAULT;
384 +               return 0;
385 +       }
386 +       case ETHTOOL_SRINGPARAM: {
387 +               struct ethtool_ringparam ering;
388 +
389 +               if (copy_from_user(&ering, useraddr, sizeof(ering)))
390 +                       return -EFAULT;
391 +
392 +               if ((ering.rx_pending > B44_RX_RING_SIZE - 1) ||
393 +                   (ering.rx_mini_pending != 0) ||
394 +                   (ering.rx_jumbo_pending != 0) ||
395 +                   (ering.tx_pending > B44_TX_RING_SIZE - 1))
396 +                       return -EINVAL;
397 +
398 +               spin_lock_irq(&bp->lock);
399 +
400 +               bp->rx_pending = ering.rx_pending;
401 +               bp->tx_pending = ering.tx_pending;
402 +
403 +               b44_halt(bp);
404 +               b44_init_rings(bp);
405 +               b44_init_hw(bp);
406 +               netif_wake_queue(bp->dev);
407 +               spin_unlock_irq(&bp->lock);
408 +
409 +               b44_enable_ints(bp);
410 +               
411 +               return 0;
412 +       }
413 +       case ETHTOOL_GPAUSEPARAM: {
414 +               struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM };
415 +
416 +               epause.autoneg =
417 +                       (bp->flags & B44_FLAG_PAUSE_AUTO) != 0;
418 +               epause.rx_pause =
419 +                       (bp->flags & B44_FLAG_RX_PAUSE) != 0;
420 +               epause.tx_pause =
421 +                       (bp->flags & B44_FLAG_TX_PAUSE) != 0;
422 +               if (copy_to_user(useraddr, &epause, sizeof(epause)))
423 +                       return -EFAULT;
424 +               return 0;
425 +       }
426 +       case ETHTOOL_SPAUSEPARAM: {
427 +               struct ethtool_pauseparam epause;
428 +
429 +               if (copy_from_user(&epause, useraddr, sizeof(epause)))
430 +                       return -EFAULT;
431 +
432 +               spin_lock_irq(&bp->lock);
433 +               if (epause.autoneg)
434 +                       bp->flags |= B44_FLAG_PAUSE_AUTO;
435 +               else
436 +                       bp->flags &= ~B44_FLAG_PAUSE_AUTO;
437 +               if (epause.rx_pause)
438 +                       bp->flags |= B44_FLAG_RX_PAUSE;
439 +               else
440 +                       bp->flags &= ~B44_FLAG_RX_PAUSE;
441 +               if (epause.tx_pause)
442 +                       bp->flags |= B44_FLAG_TX_PAUSE;
443 +               else
444 +                       bp->flags &= ~B44_FLAG_TX_PAUSE;
445 +               if (bp->flags & B44_FLAG_PAUSE_AUTO) {
446 +                       b44_halt(bp);
447 +                       b44_init_rings(bp);
448 +                       b44_init_hw(bp);
449 +               } else {
450 +                       __b44_set_flow_ctrl(bp, bp->flags);
451 +               }
452 +               spin_unlock_irq(&bp->lock);
453 +
454 +               b44_enable_ints(bp);
455 +               
456 +               return 0;
457 +       }
458 +       };
459 +
460 +       return -EOPNOTSUPP;
461 +}
462 +
463  static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
464  {
465         struct mii_ioctl_data *data = if_mii(ifr);
466         struct b44 *bp = netdev_priv(dev);
467         int err = -EINVAL;
468  
469 -       if (!netif_running(dev))
470 +       if (bp->pdev->device != PCI_DEVICE_ID_BCM4713) {
471 +               if (!netif_running(dev))
472 +                       goto out;
473 +
474 +               spin_lock_irq(&bp->lock);
475 +               err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL);
476 +               spin_unlock_irq(&bp->lock);
477                 goto out;
478 +       }
479  
480 -       spin_lock_irq(&bp->lock);
481 -       err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL);
482 -       spin_unlock_irq(&bp->lock);
483 +       switch (cmd) {
484 +       case SIOCETHTOOL:
485 +               return b44_ethtool_ioctl(dev, (void __user*) ifr->ifr_data);
486 +
487 +       case SIOCGMIIPHY:
488 +               data->phy_id = bp->phy_addr;
489 +
490 +               /* fallthru */
491 +       case SIOCGMIIREG: {
492 +               u32 mii_regval;
493 +               spin_lock_irq(&bp->lock);
494 +               err = __b44_readphy(bp, data->phy_id & 0x1f, data->reg_num & 0x1f, &mii_regval);
495 +               spin_unlock_irq(&bp->lock);
496 +
497 +               data->val_out = mii_regval;
498 +
499 +               return err;
500 +       }
501 +
502 +       case SIOCSMIIREG:
503 +               if (!capable(CAP_NET_ADMIN))
504 +                       return -EPERM;
505 +
506 +               spin_lock_irq(&bp->lock);
507 +               err = __b44_writephy(bp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
508 +               spin_unlock_irq(&bp->lock);
509 +
510 +               return err;
511 +
512 +       default:
513 +               break;
514 +       };
515 +       return -EOPNOTSUPP;
516 +               
517  out:
518         return err;
519  }
520 @@ -1865,22 +2205,43 @@
521  static int __devinit b44_get_invariants(struct b44 *bp)
522  {
523         u8 eeprom[128];
524 -       int err;
525 +       u8 buf[32];
526 +       int err = 0;
527  
528 -       err = b44_read_eeprom(bp, &eeprom[0]);
529 -       if (err)
530 -               goto out;
531 -
532 -       bp->dev->dev_addr[0] = eeprom[79];
533 -       bp->dev->dev_addr[1] = eeprom[78];
534 -       bp->dev->dev_addr[2] = eeprom[81];
535 -       bp->dev->dev_addr[3] = eeprom[80];
536 -       bp->dev->dev_addr[4] = eeprom[83];
537 -       bp->dev->dev_addr[5] = eeprom[82];
538 -       memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
539 -
540 -       bp->phy_addr = eeprom[90] & 0x1f;
541 +#ifdef CONFIG_BCM947XX
542 +       if (bp->pdev->device == PCI_DEVICE_ID_BCM4713) {
543 +               /* 
544 +                * BCM47xx boards don't have a EEPROM. The MAC is stored in
545 +                * a NVRAM area somewhere in the flash memory.
546 +                */
547 +               sprintf(buf, "et%dmacaddr", b44_4713_instance);
548 +               e_aton(nvram_get(buf), bp->dev->dev_addr);
549  
550 +               /* 
551 +                * BCM47xx boards don't have a PHY. Usually there is a switch
552 +                * chip with multiple PHYs connected to the PHY port.
553 +                */
554 +               bp->phy_addr = B44_PHY_ADDR_NO_PHY;
555 +               bp->dma_offset = 0;
556 +       } else
557 +#endif
558 +       {
559 +               err = b44_read_eeprom(bp, &eeprom[0]);
560 +               if (err)
561 +                       goto out;
562 +       
563 +               bp->dev->dev_addr[0] = eeprom[79];
564 +               bp->dev->dev_addr[1] = eeprom[78];
565 +               bp->dev->dev_addr[2] = eeprom[81];
566 +               bp->dev->dev_addr[3] = eeprom[80];
567 +               bp->dev->dev_addr[4] = eeprom[83];
568 +               bp->dev->dev_addr[5] = eeprom[82];
569 +               memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
570 +       
571 +               bp->phy_addr = eeprom[90] & 0x1f;
572 +               bp->dma_offset = SB_PCI_DMA;
573 +       }
574 +       
575         /* With this, plus the rx_header prepended to the data by the
576          * hardware, we'll land the ethernet header on a 2-byte boundary.
577          */
578 @@ -1889,11 +2250,7 @@
579         bp->imask = IMASK_DEF;
580  
581         bp->core_unit = ssb_core_unit(bp);
582 -       bp->dma_offset = SB_PCI_DMA;
583  
584 -       /* XXX - really required? 
585 -          bp->flags |= B44_FLAG_BUGGY_TXPTR;
586 -         */
587  out:
588         return err;
589  }
590 @@ -2032,11 +2389,17 @@
591  
592         pci_save_state(bp->pdev);
593  
594 -       printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
595 +       printk(KERN_INFO "%s: Broadcom %s 10/100BaseT Ethernet ", dev->name,
596 +               (pdev->device == PCI_DEVICE_ID_BCM4713) ? "47xx" : "4400");
597         for (i = 0; i < 6; i++)
598                 printk("%2.2x%c", dev->dev_addr[i],
599                        i == 5 ? '\n' : ':');
600  
601 +       /* Initialize phy */
602 +       spin_lock_irq(&bp->lock);
603 +       b44_chip_reset(bp);
604 +       spin_unlock_irq(&bp->lock);
605 +
606         return 0;
607  
608  err_out_iounmap:
609 diff -urN linux.old/drivers/net/b44.h linux.dev/drivers/net/b44.h
610 --- linux.old/drivers/net/b44.h 2006-01-12 01:44:42.548326000 +0100
611 +++ linux.dev/drivers/net/b44.h 2006-01-12 02:55:06.290783500 +0100
612 @@ -292,6 +292,10 @@
613  #define SSB_PCI_MASK1          0xfc000000
614  #define SSB_PCI_MASK2          0xc0000000
615  
616 +#define br32(bp, REG)  readl((void *)bp->regs + (REG))
617 +#define bw32(bp, REG,VAL)      writel((VAL), (void *)bp->regs + (REG))
618 +#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
619 +
620  /* 4400 PHY registers */
621  #define B44_MII_AUXCTRL                24      /* Auxiliary Control */
622  #define  MII_AUXCTRL_DUPLEX    0x0001  /* Full Duplex */
623 @@ -345,6 +349,8 @@
624  };
625  
626  #define B44_MCAST_TABLE_SIZE   32
627 +#define B44_PHY_ADDR_NO_PHY    30
628 +#define B44_MDC_RATIO          5000000
629  
630  #define        B44_STAT_REG_DECLARE            \
631         _B44(tx_good_octets)            \
632 @@ -420,6 +426,7 @@
633  
634         u32                     dma_offset;
635         u32                     flags;
636 +#define B44_FLAG_INIT_COMPLETE 0x00000001
637  #define B44_FLAG_BUGGY_TXPTR   0x00000002
638  #define B44_FLAG_REORDER_BUG   0x00000004
639  #define B44_FLAG_PAUSE_AUTO    0x00008000