[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20080207010529.868e931b.akpm@linux-foundation.org>
Date: Thu, 7 Feb 2008 01:05:29 -0800
From: Andrew Morton <akpm@...ux-foundation.org>
To: Yoshihiro Shimoda <shimoda.yoshihiro@...esas.com>
Cc: jgarzik@...ox.com, netdev@...r.kernel.org,
David Brownell <david-b@...bell.net>
Subject: Re: [PATCHv2] net: sh_eth: Add support for Renesas SuperH Ethernet
On Thu, 07 Feb 2008 17:39:23 +0900 Yoshihiro Shimoda <shimoda.yoshihiro@...esas.com> 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 majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists