I am using the following snippet of code to find out some information about the
MII PHY interface of my ethernet device (which uses the tulip driver). When I
did some timing measurements with gettimeofday() I found that the ioctl call
takes a bit over a millisecond to complete. This seems to me to be an awfully
long time for what should be (as far as I can see) a very simple operation.
Is this the normal amount of time that this should take, and if so then why in
the world does it take so long? If not, then does anyone have any idea why it's
taking so long?
Thanks,
Chris
// code follows //
int skfd;
struct ifreq ifr;
ifname = "eth1";
if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0)
{
perror("socket");
exit(-1);
}
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(skfd, SIOCDEVPRIVATE, &ifr) < 0)
{
fprintf(stderr, "SIOCDEVPRIVATE, on %s failed: %s\n", ifname,
strerror(errno));
close(skfd);
exit(-1);
}
--
Chris Friesen | MailStop: 043/33/F10
Nortel Networks | work: (613) 765-0557
3500 Carling Avenue | fax: (613) 765-2986
Nepean, ON K2H 8E9 Canada | email: [email protected]
On Fri, 6 Jul 2001, Chris Friesen wrote:
>
> I am using the following snippet of code to find out some information about the
> MII PHY interface of my ethernet device (which uses the tulip driver). When I
> did some timing measurements with gettimeofday() I found that the ioctl call
> takes a bit over a millisecond to complete. This seems to me to be an awfully
> long time for what should be (as far as I can see) a very simple operation.
>
> Is this the normal amount of time that this should take, and if so then why in
> the world does it take so long? If not, then does anyone have any idea why it's
> taking so long?
>
> Thanks,
>
It's not ioctl() overhead, it's what has to be done in the driver to
get the information you request.
(1) Stop the chip
(2) Read the media interface using an awful SERIAL protocol in which
you manipulate 3 bits using multiple instructions, to send
or receive a single BIT (not BYTE) of data. You do the 8 times
per byte.
(3) Restart the chip.
You are lucky it doesn't take an hour. This garbage 1 bit interface,
in which hardware designers assumed that software was free, is an
example of the junk software engineers have to put up with.
This is, obviously, not designed to be accessed very often, just
any time somebody disconnects/reconnects the network wire. Don't
ioctl-it in a loop. You will lose most of the network packets.
Cheers,
Dick Johnson
Penguin : Linux version 2.4.1 on an i686 machine (799.53 BogoMips).
I was going to compile a list of innovations that could be
attributed to Microsoft. Once I realized that Ctrl-Alt-Del
was handled in the BIOS, I found that there aren't any.
"Richard B. Johnson" wrote:
>
> On Fri, 6 Jul 2001, Chris Friesen wrote:
>
> > I am using the following snippet of code to find out some information about the
> > MII PHY interface of my ethernet device (which uses the tulip driver). When I
> > did some timing measurements with gettimeofday() I found that the ioctl call
> > takes a bit over a millisecond to complete. This seems to me to be an awfully
> > long time for what should be (as far as I can see) a very simple operation.
> It's not ioctl() overhead, it's what has to be done in the driver to
> get the information you request.
>
> (1) Stop the chip
> (2) Read the media interface using an awful SERIAL protocol in which
> you manipulate 3 bits using multiple instructions, to send
> or receive a single BIT (not BYTE) of data. You do the 8 times
> per byte.
> (3) Restart the chip.
Are you sure about this? In the tulip.c driver the following appears to be the
salient code:
static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
long ioaddr = dev->base_addr;
u16 *data = (u16 *)&rq->ifr_data;
int phy = tp->phys[0] & 0x1f;
long flags;
switch(cmd) {
case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
if (tp->mii_cnt)
data[0] = phy;
else if (tp->flags & HAS_NWAY143)
data[0] = 32;
else if (tp->chip_id == COMET)
data[0] = 1;
else
return -ENODEV;
I don't see any device stopping or reading of the media interface here. Now
there may be something very subtle hidden somewhere that I'm not seeing, but
this looks like some relatively straightforward comparisons.
Chris
--
Chris Friesen | MailStop: 043/33/F10
Nortel Networks | work: (613) 765-0557
3500 Carling Avenue | fax: (613) 765-2986
Nepean, ON K2H 8E9 Canada | email: [email protected]
On Fri, 6 Jul 2001, Chris Friesen wrote:
> "Richard B. Johnson" wrote:
> >
> > On Fri, 6 Jul 2001, Chris Friesen wrote:
> >
> > > I am using the following snippet of code to find out some information about the
> > > MII PHY interface of my ethernet device (which uses the tulip driver). When I
> > > did some timing measurements with gettimeofday() I found that the ioctl call
> > > takes a bit over a millisecond to complete. This seems to me to be an awfully
> > > long time for what should be (as far as I can see) a very simple operation.
>
> > It's not ioctl() overhead, it's what has to be done in the driver to
> > get the information you request.
> >
> > (1) Stop the chip
> > (2) Read the media interface using an awful SERIAL protocol in which
> > you manipulate 3 bits using multiple instructions, to send
> > or receive a single BIT (not BYTE) of data. You do the 8 times
> > per byte.
> > (3) Restart the chip.
>
> Are you sure about this? In the tulip.c driver the following appears to be the
> salient code:
>
> static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd)
> {
> struct tulip_private *tp = (struct tulip_private *)dev->priv;
> long ioaddr = dev->base_addr;
> u16 *data = (u16 *)&rq->ifr_data;
> int phy = tp->phys[0] & 0x1f;
> long flags;
>
> switch(cmd) {
> case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
> if (tp->mii_cnt)
> data[0] = phy;
> else if (tp->flags & HAS_NWAY143)
> data[0] = 32;
> else if (tp->chip_id == COMET)
> data[0] = 1;
> else
> return -ENODEV;
>
..... This falls through to
SIOCDEVPRIVATE+1
>
> I don't see any device stopping or reading of the media interface here. Now
> there may be something very subtle hidden somewhere that I'm not seeing, but
> this looks like some relatively straightforward comparisons.
Look at tulip_mdio_read() and the zillions of times it's called.
It's called in SIOCDEVPRIVATE+1 when SIOCDEVPRIVATE falls through.
It falls through always, unless there is the -ENODEV error.
tulip_mdio_read() does the bit-banging junk.
Cheers,
Dick Johnson
Penguin : Linux version 2.4.1 on an i686 machine (799.53 BogoMips).
I was going to compile a list of innovations that could be
attributed to Microsoft. Once I realized that Ctrl-Alt-Del
was handled in the BIOS, I found that there aren't any.
"Richard B. Johnson" wrote:
>
> On Fri, 6 Jul 2001, Chris Friesen wrote:
> > Are you sure about this? In the tulip.c driver the following appears to be the
> > salient code:
<snip>
> ..... This falls through to
> SIOCDEVPRIVATE+1
Doh! Okay, I need caffeine, or sugar, or something...
Sorry about that.
Chris
--
Chris Friesen | MailStop: 043/33/F10
Nortel Networks | work: (613) 765-0557
3500 Carling Avenue | fax: (613) 765-2986
Nepean, ON K2H 8E9 Canada | email: [email protected]
The beginning of mdio_read() in tulip.c goes like this:
static int mdio_read(struct device *dev, int phy_id, int location)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
int i;
int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
int retval = 0;
long ioaddr = dev->base_addr;
long mdio_addr = ioaddr + CSR9;
if (tp->chip_id == LC82C168) {
int i = 1000;
outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
inl(ioaddr + 0xA0);
inl(ioaddr + 0xA0);
while (--i > 0)
if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
return retval & 0xffff;
return 0xffff;
}
if (tp->chip_id == COMET) {
if (phy_id == 1) {
if (location < 7)
return inl(ioaddr + 0xB4 + (location<<2));
else if (location == 17)
return inl(ioaddr + 0xD0);
else if (location >= 29 && location <= 31)
return inl(ioaddr + 0xD4 + ((location-29)<<2));
}
return 0xffff;
}
mdelay(1); /* One ms delay... */
...rest of code...
The chip I'm using is the DEC 21143, which means that we skip over the two
conditional blocks, so the first thing that happens when we call this is to
wait around doing nothing for a millisecond. Is there some subtle reason why we
would want to wait around for a millisecond before doing anything?
Thanks for your help,
Chris
--
Chris Friesen | MailStop: 043/33/F10
Nortel Networks | work: (613) 765-0557
3500 Carling Avenue | fax: (613) 765-2986
Nepean, ON K2H 8E9 Canada | email: [email protected]
On Fri, 6 Jul 2001, Chris Friesen wrote:
> The beginning of mdio_read() in tulip.c goes like this:
>
> static int mdio_read(struct device *dev, int phy_id, int location)
> {
> struct tulip_private *tp = (struct tulip_private *)dev->priv;
> int i;
> int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
> int retval = 0;
> long ioaddr = dev->base_addr;
> long mdio_addr = ioaddr + CSR9;
>
> if (tp->chip_id == LC82C168) {
> int i = 1000;
> outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
> inl(ioaddr + 0xA0);
> inl(ioaddr + 0xA0);
> while (--i > 0)
> if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
> return retval & 0xffff;
> return 0xffff;
> }
>
> if (tp->chip_id == COMET) {
> if (phy_id == 1) {
> if (location < 7)
> return inl(ioaddr + 0xB4 + (location<<2));
> else if (location == 17)
> return inl(ioaddr + 0xD0);
> else if (location >= 29 && location <= 31)
> return inl(ioaddr + 0xD4 + ((location-29)<<2));
> }
> return 0xffff;
> }
>
> mdelay(1); /* One ms delay... */
>
> ...rest of code...
>
What? What kernel version?
The code here says:
/* Establish sync by sending at least 32 logic ones */
for (i = 32; i >=0; i--) {..........}
There is a mdio_delay() between each of the bit operations. This
is required to give time for the chip's internals to set up.
There is no mdelay in any of the code in .../linux/drivers/net/tulip/.
Cheers,
Dick Johnson
Penguin : Linux version 2.4.1 on an i686 machine (799.53 BogoMips).
I was going to compile a list of innovations that could be
attributed to Microsoft. Once I realized that Ctrl-Alt-Del
was handled in the BIOS, I found that there aren't any.
"Richard B. Johnson" wrote:
>
> On Fri, 6 Jul 2001, Chris Friesen wrote:
> > mdelay(1); /* One ms delay... */
> >
> > ...rest of code...
> >
>
> What? What kernel version?
> The code here says:
> /* Establish sync by sending at least 32 logic ones */
> for (i = 32; i >=0; i--) {..........}
I had assumed that it was part of the normal drivers, but now after digging into
it some more it appears to have been added as part of a patch from Motorola for
a compact PCI board. I can't see why they would have done this but I'm trying
to track it down now.
Thanks for all your help,
Chris
--
Chris Friesen | MailStop: 043/33/F10
Nortel Networks | work: (613) 765-0557
3500 Carling Avenue | fax: (613) 765-2986
Nepean, ON K2H 8E9 Canada | email: [email protected]
On Fri, 6 Jul 2001, Chris Friesen wrote:
> Subject: why this 1ms delay in mdio_read? (cont'd from "are ioctl calls
supposed to take this long?")
>
> The beginning of mdio_read() in tulip.c goes like this:
>
> static int mdio_read(struct device *dev, int phy_id, int location)
...
> mdelay(1); /* One ms delay... */
Ackkk! What driver version?
And who put this bogus delay in the code?
Putting arbitrary delays in drivers is usually a sign that the someone
didn't understand how to fix a bug and is just trying to wait it out.
> The chip I'm using is the DEC 21143, which means that we skip over the two
> conditional blocks, so the first thing that happens when we call this is to
> wait around doing nothing for a millisecond. Is there some subtle
> reason why we would want to wait around for a millisecond before doing
> anything?
Nope. None at all.
Donald Becker [email protected]
Scyld Computing Corporation http://www.scyld.com
410 Severn Ave. Suite 210 Second Generation Beowulf Clusters
Annapolis MD 21403 410-990-9993