On Thu, 07 Feb 2008 17:39:23 +0900 Yoshihiro Shimoda <[EMAIL PROTECTED]> wrote:
> Add support for Renesas SuperH Ethernet controller. > This driver supported SH7710 and SH7712. > Nice looking driver. Quick comments: > ... > > +/* > + * Program the hardware MAC address from dev->dev_addr. > + */ > +static void __init update_mac_address(struct net_device *ndev) > +{ > + u32 ioaddr = ndev->base_addr; > + > + ctrl_outl((ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) | > + (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]), > + ioaddr + MAHR); > + ctrl_outl((ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]), > + ioaddr + MALR); > +} > + > +/* > + * Get MAC address from SuperH MAC address register > + * > + * SuperH's Ethernet device doesn't have 'ROM' to MAC address. > + * This driver get MAC address that use by bootloader(U-boot or sh-ipl+g). > + * When you want use this device, you must set MAC address in bootloader. > + * > + */ > +static void __init read_mac_address(struct net_device *ndev) > +{ > + u32 ioaddr = ndev->base_addr; > + > + ndev->dev_addr[0] = (ctrl_inl(ioaddr + MAHR) >> 24); > + ndev->dev_addr[1] = (ctrl_inl(ioaddr + MAHR) >> 16) & 0xFF; > + ndev->dev_addr[2] = (ctrl_inl(ioaddr + MAHR) >> 8) & 0xFF; > + ndev->dev_addr[3] = (ctrl_inl(ioaddr + MAHR) & 0xFF); > + ndev->dev_addr[4] = (ctrl_inl(ioaddr + MALR) >> 8) & 0xFF; > + ndev->dev_addr[5] = (ctrl_inl(ioaddr + MALR) & 0xFF); > +} Both the above functions are called from non-__init code and hence cannot be __init. sh_eth_tsu_init() is wrong too. Please check all section annotations in the driver. > +struct bb_info { > + struct mdiobb_ctrl ctrl; > + u32 addr; > + u32 mmd_msk;/* MMD */ > + u32 mdo_msk; > + u32 mdi_msk; > + u32 mdc_msk; > +}; Please cc David Brownell on updates to this driver - perhaps he will find time to review the bit-banging interface usage. > +/* PHY bit set */ > +static void bb_set(u32 addr, u32 msk) > +{ > + ctrl_outl(ctrl_inl(addr) | msk, addr); > +} > + > +/* PHY bit clear */ > +static void bb_clr(u32 addr, u32 msk) > +{ > + ctrl_outl((ctrl_inl(addr) & ~msk), addr); > +} > + > +/* PHY bit read */ > +static int bb_read(u32 addr, u32 msk) > +{ > + return (ctrl_inl(addr) & msk) != 0; > +} > + > +/* Data I/O pin control */ > +static inline void sh__mmd_ctrl(struct mdiobb_ctrl *ctrl, int bit) > +{ > + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); > + if (bit) > + bb_set(bitbang->addr, bitbang->mmd_msk); > + else > + bb_clr(bitbang->addr, bitbang->mmd_msk); > +} > + > +/* Set bit data*/ > +static inline void sh__set_mdio(struct mdiobb_ctrl *ctrl, int bit) > +{ > + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); > + > + if (bit) > + bb_set(bitbang->addr, bitbang->mdo_msk); > + else > + bb_clr(bitbang->addr, bitbang->mdo_msk); > +} > + > +/* Get bit data*/ > +static inline int sh__get_mdio(struct mdiobb_ctrl *ctrl) > +{ > + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); > + return bb_read(bitbang->addr, bitbang->mdi_msk); > +} There seems to be a fairly random mixture of inline and non-inline here. I'd suggest that you just remove all the `inline's. The compiler does a pretty good job of working doing this for you. > +/* MDC pin control */ > +static inline void sh__mdc_ctrl(struct mdiobb_ctrl *ctrl, int bit) > +{ > + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); > + > + if (bit) > + bb_set(bitbang->addr, bitbang->mdc_msk); > + else > + bb_clr(bitbang->addr, bitbang->mdc_msk); > +} > + > +/* mdio bus control struct */ > +static struct mdiobb_ops bb_ops = { > + .owner = THIS_MODULE, > + .set_mdc = sh__mdc_ctrl, > + .set_mdio_dir = sh__mmd_ctrl, > + .set_mdio_data = sh__set_mdio, > + .get_mdio_data = sh__get_mdio, > +}; It's particularly inappropriate that sh__mdc_ctrl() was inlined - it is only ever called via a function pointer and hence will never be inlined! > ... > > +static void sh_eth_timer(unsigned long data) > +{ > + struct net_device *ndev = (struct net_device *)data; > + struct sh_eth_private *mdp = netdev_priv(ndev); > + int next_tick = 10 * HZ; > + > + /* We could do something here... nah. */ > + mdp->timer.expires = jiffies + next_tick; > + add_timer(&mdp->timer); mod_timer() would be neater here. > +} > > ... > > + > +/* network device open function */ > +static int sh_eth_open(struct net_device *ndev) > +{ > + int ret = 0; > + struct sh_eth_private *mdp = netdev_priv(ndev); > + > + ret = request_irq(ndev->irq, &sh_eth_interrupt, 0, ndev->name, ndev); > + if (ret) { > + printk(KERN_ERR "Can not assign IRQ number to %s\n", CARDNAME); > + return ret; > + } > + > + /* Descriptor set */ > + ret = sh_eth_ring_init(ndev); > + if (ret) > + goto out_free_irq; > + > + /* device init */ > + ret = sh_eth_dev_init(ndev); > + if (ret) > + goto out_free_irq; > + > + /* PHY control start*/ > + ret = sh_eth_phy_start(ndev); > + if (ret) > + goto out_free_irq; > + > + /* Set the timer to check for link beat. */ > + init_timer(&mdp->timer); > + mdp->timer.expires = (jiffies + (24 * HZ)) / 10;/* 2.4 sec. */ > + mdp->timer.data = (u32) ndev; > + mdp->timer.function = sh_eth_timer; /* timer handler */ setup_timer() > + add_timer(&mdp->timer); > + > + return ret; > + > +out_free_irq: > + free_irq(ndev->irq, ndev); > + return ret; > +} > + > +/* Timeout function */ > +static void sh_eth_tx_timeout(struct net_device *ndev) > +{ > + struct sh_eth_private *mdp = netdev_priv(ndev); > + u32 ioaddr = ndev->base_addr; > + struct sh_eth_rxdesc *rxdesc; > + int i; > + > + netif_stop_queue(ndev); > + > + /* worning message out. */ > + printk(KERN_WARNING "%s: transmit timed out, status %8.8x," > + " resetting...\n", ndev->name, (int)ctrl_inl(ioaddr + EESR)); > + > + /* tx_errors count up */ > + mdp->stats.tx_errors++; > + > + /* timer off */ > + del_timer_sync(&mdp->timer); > + > + /* Free all the skbuffs in the Rx queue. */ > + for (i = 0; i < RX_RING_SIZE; i++) { > + rxdesc = &mdp->rx_ring[i]; > + rxdesc->status = 0; > + rxdesc->addr = 0xBADF00D0; > + if (mdp->rx_skbuff[i]) > + dev_kfree_skb(mdp->rx_skbuff[i]); > + mdp->rx_skbuff[i] = NULL; > + } > + for (i = 0; i < TX_RING_SIZE; i++) { > + if (mdp->tx_skbuff[i]) > + dev_kfree_skb(mdp->tx_skbuff[i]); > + mdp->tx_skbuff[i] = NULL; > + } > + > + /* device init */ > + sh_eth_dev_init(ndev); > + > + /* timer on */ > + mdp->timer.expires = (jiffies + (24 * HZ)) / 10;/* 2.4 sec. */ > + add_timer(&mdp->timer); mod_timer() > +} > + > > +#ifdef __LITTLE_ENDIAN__ > +static inline void swaps(char *src, int len) > +{ > + u32 *p = (u32 *)src; > + u32 *maxp; > + maxp = p + ((len + sizeof(u32) - 1) / sizeof(u32)); > + > + for (; p < maxp; p++) > + *p = swab32(*p); > +} > +#else > +#define swaps(x, y) > +#endif > + I'd say that the big-endian version of swaps() should be a C function rather than a macro. It's nicer to look at, consistent, provides typechecking, can help avoid unused-variable warnings (an inline function provides a reference to the arguments whereas a macro does not). The little-endian version of this function is too large to be inlined. This function looks fairly generic. Are we sure there isn't some library function which does this? -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html