/* Init PHY interface and start link poll state machine */
static void gem_init_phy(struct gem *gp)
{
- u32 mif_cfg;
+ u32 mifcfg;
/* Revert MIF CFG setting done on stop_phy */
- mif_cfg = readl(gp->regs + MIF_CFG);
- mif_cfg &= ~(MIF_CFG_PSELECT|MIF_CFG_POLL|MIF_CFG_BBMODE|MIF_CFG_MDI1);
- mif_cfg |= MIF_CFG_MDI0;
- writel(mif_cfg, gp->regs + MIF_CFG);
- writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE);
- writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG);
+ mifcfg = readl(gp->regs + MIF_CFG);
+ mifcfg &= ~MIF_CFG_BBMODE;
+ writel(mifcfg, gp->regs + MIF_CFG);
if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
int i;
- u16 ctrl;
+ /* Those delay sucks, the HW seem to love them though, I'll
+ * serisouly consider breaking some locks here to be able
+ * to schedule instead
+ */
+ for (i = 0; i < 3; i++) {
#ifdef CONFIG_PPC_PMAC
- pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0);
+ pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0);
+ msleep(20);
#endif
-
- /* Some PHYs used by apple have problem getting back
- * to us, we do an additional reset here
- */
- phy_write(gp, MII_BMCR, BMCR_RESET);
- for (i = 0; i < 50; i++) {
- if ((phy_read(gp, MII_BMCR) & BMCR_RESET) == 0)
+ /* Some PHYs used by apple have problem getting back to us,
+ * we do an additional reset here
+ */
+ phy_write(gp, MII_BMCR, BMCR_RESET);
+ msleep(20);
+ if (phy_read(gp, MII_BMCR) != 0xffff)
break;
- msleep(10);
+ if (i == 2)
+ printk(KERN_WARNING "%s: GMAC PHY not responding !\n",
+ gp->dev->name);
}
- if (i == 50)
- printk(KERN_WARNING "%s: GMAC PHY not responding !\n",
- gp->dev->name);
- /* Make sure isolate is off */
- ctrl = phy_read(gp, MII_BMCR);
- if (ctrl & BMCR_ISOLATE)
- phy_write(gp, MII_BMCR, ctrl & ~BMCR_ISOLATE);
}
if (gp->pdev->vendor == PCI_VENDOR_ID_SUN &&
/* Must be invoked with no lock held. */
static void gem_stop_phy(struct gem *gp, int wol)
{
- u32 mif_cfg;
+ u32 mifcfg;
unsigned long flags;
/* Let the chip settle down a bit, it seems that helps
/* Make sure we aren't polling PHY status change. We
* don't currently use that feature though
*/
- mif_cfg = readl(gp->regs + MIF_CFG);
- mif_cfg &= ~MIF_CFG_POLL;
- writel(mif_cfg, gp->regs + MIF_CFG);
+ mifcfg = readl(gp->regs + MIF_CFG);
+ mifcfg &= ~MIF_CFG_POLL;
+ writel(mifcfg, gp->regs + MIF_CFG);
if (wol && gp->has_wol) {
unsigned char *e = &gp->dev->dev_addr[0];
/* According to Apple, we must set the MDIO pins to this begnign
* state or we may 1) eat more current, 2) damage some PHYs
*/
- mif_cfg = 0;
- writel(mif_cfg | MIF_CFG_BBMODE, gp->regs + MIF_CFG);
+ writel(mifcfg | MIF_CFG_BBMODE, gp->regs + MIF_CFG);
writel(0, gp->regs + MIF_BBCLK);
writel(0, gp->regs + MIF_BBDATA);
writel(0, gp->regs + MIF_BBOENAB);
return ip_route_output_flow(rp, &fl, sk, 0);
}
-static inline int ip_route_newports(struct rtable **rp, u16 sport, u16 dport,
- struct sock *sk)
+static inline int ip_route_newports(struct rtable **rp, u8 protocol,
+ u16 sport, u16 dport, struct sock *sk)
{
if (sport != (*rp)->fl.fl_ip_sport ||
dport != (*rp)->fl.fl_ip_dport) {
memcpy(&fl, &(*rp)->fl, sizeof(fl));
fl.fl_ip_sport = sport;
fl.fl_ip_dport = dport;
+ fl.proto = protocol;
ip_rt_put(*rp);
*rp = NULL;
return ip_route_output_flow(rp, &fl, sk, 0);
{
struct net_device *dev = p->dev;
+ dev->br_port = NULL;
p->br = NULL;
p->dev = NULL;
dev_put(dev);
destroy_nbp(p);
}
-/* called with RTNL */
+/* Delete port(interface) from bridge is done in two steps.
+ * via RCU. First step, marks device as down. That deletes
+ * all the timers and stops new packets from flowing through.
+ *
+ * Final cleanup doesn't occur until after all CPU's finished
+ * processing packets.
+ *
+ * Protected from multiple admin operations by RTNL mutex
+ */
static void del_nbp(struct net_bridge_port *p)
{
struct net_bridge *br = p->br;
struct net_device *dev = p->dev;
- dev->br_port = NULL;
+ /* Race between RTNL notify and RCU callback */
+ if (p->deleted)
+ return;
+
dev_set_promiscuity(dev, -1);
cancel_delayed_work(&p->carrier_check);
spin_lock_bh(&br->lock);
br_stp_disable_port(p);
+ p->deleted = 1;
spin_unlock_bh(&br->lock);
br_fdb_delete_by_port(br, p);
list_del_rcu(&p->list);
- del_timer_sync(&p->message_age_timer);
- del_timer_sync(&p->forward_delay_timer);
- del_timer_sync(&p->hold_timer);
-
call_rcu(&p->rcu, destroy_nbp_rcu);
}