[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-Id: <20070914192140.15b18ecb.akpm@linux-foundation.org>
Date: Fri, 14 Sep 2007 19:21:40 -0700
From: Andrew Morton <akpm@...ux-foundation.org>
To: Francois Romieu <romieu@...zoreil.com>
Cc: jeff@...zik.org, Jesse Huang <jesse@...lus.com.tw>,
netdev@...r.kernel.org, shemminger@...ux-foundation.org,
s.l-h@....de
Subject: Re: [PATCH] ipg: add IP1000A driver to kernel tree
On Fri, 14 Sep 2007 23:21:05 +0200 Francois Romieu <romieu@...zoreil.com> wrote:
> ...
>
> +
> +static void ipg_dump_tfdlist(struct net_device *dev)
> +{
> + struct ipg_nic_private *sp = netdev_priv(dev);
> + void __iomem *ioaddr = sp->ioaddr;
> + unsigned int i;
> + u32 offset;
> +
> + IPG_DEBUG_MSG("_dump_tfdlist\n");
> +
> + printk(KERN_INFO "tx_current = %2.2x\n", sp->tx_current);
> + printk(KERN_INFO "tx_dirty = %2.2x\n", sp->tx_dirty);
> + printk(KERN_INFO "TFDList start address = %16.16lx\n",
> + (unsigned long) sp->txd_map);
> + printk(KERN_INFO "TFDListPtr register = %8.8x%8.8x\n",
> + ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0));
> +
> + for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
> + offset = (u32) &sp->txd[i].next_desc - (u32) sp->txd;
> + printk(KERN_INFO "%2.2x %4.4x TFDNextPtr = %16.16lx\n", i,
> + offset, (unsigned long) sp->txd[i].next_desc);
> +
> + offset = (u32) &sp->txd[i].tfc - (u32) sp->txd;
Is the u32 cast safe here on all architectures?
> + printk(KERN_INFO "%2.2x %4.4x TFC = %16.16lx\n", i,
> + offset, (unsigned long) sp->txd[i].tfc);
> + offset = (u32) &sp->txd[i].frag_info - (u32) sp->txd;
> + printk(KERN_INFO "%2.2x %4.4x frag_info = %16.16lx\n", i,
> + offset, (unsigned long) sp->txd[i].frag_info);
> + }
> +}
>
> ...
>
> +static int mdio_read(struct net_device * dev, int phy_id, int phy_reg)
> +{
> + void __iomem *ioaddr = ipg_ioaddr(dev);
> + /*
> + * The GMII mangement frame structure for a read is as follows:
> + *
> + * |Preamble|st|op|phyad|regad|ta| data |idle|
> + * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z |
> + *
> + * <32 1s> = 32 consecutive logic 1 values
> + * A = bit of Physical Layer device address (MSB first)
> + * R = bit of register address (MSB first)
> + * z = High impedance state
> + * D = bit of read data (MSB first)
> + *
> + * Transmission order is 'Preamble' field first, bits transmitted
> + * left to right (first to last).
> + */
> + struct {
> + u32 field;
> + unsigned int len;
> + } p[] = {
> + { GMII_PREAMBLE, 32 }, /* Preamble */
> + { GMII_ST, 2 }, /* ST */
> + { GMII_READ, 2 }, /* OP */
> + { phy_id, 5 }, /* PHYAD */
> + { phy_reg, 5 }, /* REGAD */
> + { 0x0000, 2 }, /* TA */
> + { 0x0000, 16 }, /* DATA */
> + { 0x0000, 1 } /* IDLE */
> + };
This will be built on the stack at runtime.
> + unsigned int i, j;
> + u8 polarity, data;
> +
> + polarity = ipg_r8(PHY_CTRL);
> + polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
> +
> + /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
> + for (j = 0; j < 5; j++) {
> + for (i = 0; i < p[j].len; i++) {
> + /* For each variable length field, the MSB must be
> + * transmitted first. Rotate through the field bits,
> + * starting with the MSB, and move each bit into the
> + * the 1st (2^1) bit position (this is the bit position
> + * corresponding to the MgmtData bit of the PhyCtrl
> + * register for the IPG).
> + *
> + * Example: ST = 01;
> + *
> + * First write a '0' to bit 1 of the PhyCtrl
> + * register, then write a '1' to bit 1 of the
> + * PhyCtrl register.
> + *
> + * To do this, right shift the MSB of ST by the value:
> + * [field length - 1 - #ST bits already written]
> + * then left shift this result by 1.
> + */
> + data = (p[j].field >> (p[j].len - 1 - i)) << 1;
> + data &= IPG_PC_MGMTDATA;
> + data |= polarity | IPG_PC_MGMTDIR;
> +
> + ipg_drive_phy_ctl_low_high(ioaddr, data);
> + }
> + }
> +
> + send_three_state(ioaddr, polarity);
> +
> + read_phy_bit(ioaddr, polarity);
> +
> + /*
> + * For a read cycle, the bits for the next two fields (TA and
> + * DATA) are driven by the PHY (the IPG reads these bits).
> + */
> + for (i = 0; i < p[6].len; i++) {
> + p[6].field |=
> + (read_phy_bit(ioaddr, polarity) << (p[6].len - 1 - i));
> + }
Simply because we're using p[6] as a temporary variable.
This can be tightened up.
> + send_three_state(ioaddr, polarity);
> + send_three_state(ioaddr, polarity);
> + send_three_state(ioaddr, polarity);
> + send_end(ioaddr, polarity);
> +
> + /* Return the value of the DATA field. */
> + return p[6].field;
> +}
> +
> +/*
> + * Write to a register from the Physical Layer device located
> + * on the IPG NIC, using the IPG PHYCTRL register.
> + */
> +static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val)
> +{
> + void __iomem *ioaddr = ipg_ioaddr(dev);
> + /*
> + * The GMII mangement frame structure for a read is as follows:
> + *
> + * |Preamble|st|op|phyad|regad|ta| data |idle|
> + * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z |
> + *
> + * <32 1s> = 32 consecutive logic 1 values
> + * A = bit of Physical Layer device address (MSB first)
> + * R = bit of register address (MSB first)
> + * z = High impedance state
> + * D = bit of write data (MSB first)
> + *
> + * Transmission order is 'Preamble' field first, bits transmitted
> + * left to right (first to last).
> + */
> + struct {
> + u32 field;
> + unsigned int len;
> + } p[] = {
> + { GMII_PREAMBLE, 32 }, /* Preamble */
> + { GMII_ST, 2 }, /* ST */
> + { GMII_WRITE, 2 }, /* OP */
> + { phy_id, 5 }, /* PHYAD */
> + { phy_reg, 5 }, /* REGAD */
> + { 0x0002, 2 }, /* TA */
> + { val & 0xffff, 16 }, /* DATA */
> + { 0x0000, 1 } /* IDLE */
> + };
similar here
> + unsigned int i, j;
> + u8 polarity, data;
> +
> + polarity = ipg_r8(PHY_CTRL);
> + polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
> +
> + /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
> + for (j = 0; j < 7; j++) {
> + for (i = 0; i < p[j].len; i++) {
> + /* For each variable length field, the MSB must be
> + * transmitted first. Rotate through the field bits,
> + * starting with the MSB, and move each bit into the
> + * the 1st (2^1) bit position (this is the bit position
> + * corresponding to the MgmtData bit of the PhyCtrl
> + * register for the IPG).
> + *
> + * Example: ST = 01;
> + *
> + * First write a '0' to bit 1 of the PhyCtrl
> + * register, then write a '1' to bit 1 of the
> + * PhyCtrl register.
> + *
> + * To do this, right shift the MSB of ST by the value:
> + * [field length - 1 - #ST bits already written]
> + * then left shift this result by 1.
> + */
> + data = (p[j].field >> (p[j].len - 1 - i)) << 1;
> + data &= IPG_PC_MGMTDATA;
> + data |= polarity | IPG_PC_MGMTDIR;
> +
> + ipg_drive_phy_ctl_low_high(ioaddr, data);
> + }
> + }
> +
> + /* The last cycle is a tri-state, so read from the PHY. */
> + for (j = 7; j < 8; j++) {
> + for (i = 0; i < p[j].len; i++) {
> + ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | polarity);
> +
> + p[j].field |= ((ipg_r8(PHY_CTRL) &
> + IPG_PC_MGMTDATA) >> 1) << (p[j].len - 1 - i);
> +
> + ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | polarity);
> + }
> + }
although it might be tricky to avoid
> +}
> +
>
> ...
>
> +static int ipg_reset(struct net_device *dev, u32 resetflags)
> +{
> + /* Assert functional resets via the IPG AsicCtrl
> + * register as specified by the 'resetflags' input
> + * parameter.
> + */
> + void __iomem *ioaddr = ipg_ioaddr(dev); //JES20040127EEPROM:
> + unsigned int timeout_count = 0;
> +
> + IPG_DEBUG_MSG("_reset\n");
> +
> + ipg_w32(ipg_r32(ASIC_CTRL) | resetflags, ASIC_CTRL);
> +
> + /* Delay added to account for problem with 10Mbps reset. */
> + mdelay(IPG_AC_RESETWAIT);
> +
> + while (IPG_AC_RESET_BUSY & ipg_r32(ASIC_CTRL)) {
> + mdelay(IPG_AC_RESETWAIT);
> + if (++timeout_count > IPG_AC_RESET_TIMEOUT)
> + return -ETIME;
Is ETIME an appropriate errno here? Zillions of drivers use it, but I
think it's for posix timers or something like that?
> + }
> + /* Set LED Mode in Asic Control JES20040127EEPROM */
> + ipg_set_led_mode(dev);
> +
> + /* Set PHYSet Register Value JES20040127EEPROM */
> + ipg_set_phy_set(dev);
> + return 0;
> +}
> +
>
> [vast amounts trimmed]
>
Attention span expired, sorry. ETIME.
-
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