Forum Discussion
Altera_Forum
Honored Contributor
19 years ago --- Quote Start --- originally posted by graham615+mar 9 2006, 03:41 pm--><div class='quotetop'>quote (graham615 @ mar 9 2006, 03:41 pm)</div>
--- quote start ---
<!--quotebegin-tuck@Feb 24 2006, 02:01 PM ok i think i fixed the odd buffer size issue, but the checksum issue remains.
since this is calculated further up the stack, and my cursory glance didn't reveal any areas in the driver that may be corrupting the header i think there is another issue.
when i went in the debugger and manually corrected the crc in the header the remaining data looked fine, so hopefully this can help!
unfortunately i can't spend more time on this since i won't be using this driver once our boards arrive, and the issue isn't affecting me right this instant. i went ahead and put a patch together. it's not well tested, but the tests i have done indicate that it is working as designed.
if you take the following text save it to a file and execute patch -p0 < patchfile from your nios2 shell in the ecos-current dirctory (probably /cygdrive/c/altera/kits/nios2_51/components/ecos/ecos-current). it should resolve the buffer issue (i think http://forum.niosforum.com/work2/style_emoticons/<#emo_dir#>/smile.gif ).
diff -naru packagesorig/devs/eth/smsc/lan91cxx/current/src/if_lan91cxx.c packages/devs/eth/smsc/lan91cxx/current/src/if_lan91cxx.c
--- packagesorig/devs/eth/smsc/lan91cxx/current/src/if_lan91cxx.c 2005-01-07 12:50:34.000000000 -0500
+++ packages/devs/eth/smsc/lan91cxx/current/src/if_lan91cxx.c 2006-02-24 11:30:49.525340400 -0500
@@ -860,13 +860,53 @@
// packet length (includes status, byte-count and control shorts)
put_data(sc, cyg_cpu_to_le16(0x7fe & (plen + 6)) ); // always even, always < 15xx(dec)
+ //since this driver transfers 2 bytes at a time buffers in the beginning of
+ //the scatter gather list with odd lengths must be combined with their
+ //next neighbor to create 2 byte sets. the oddhandled variable tracks if
+ //the prior iteration handled one of these conditions
+ bool oddhandled = false;
// put data into buffer
for (i = 0; i < sg_len; i++) {
- sdata = (unsigned short *)sg_list.buf;
- len = sg_list.len;
+ // 2006.02.24 - thw - odd lengths now handled.
+ //cyg_assert(0 == (len & 1) || (i == (sg_len-1)), "odd length");
- cyg_assert(0 == (len & 1) || (i == (sg_len-1)), "odd length");
- cyg_assert( sdata, "no sg data pointer here" );
+ //if this is the first buffer then just process as normal
+ //if this is a middle buffer then inspect the previous buffer:
+ // - if previous length was odd and the last iteration didn't handle an
+ // odd buffer then we need to combine.
+ // - if the previous iteration did handle an odd buffer and it's length
+ // is even it total transfer was odd and i need to combine.
+ bool lastlenodd = sg_list.len & 1;
+ if(i && (lastlenodd ^ oddhandled)){
+ //notify the next iteration that this iteration handled an odd
+ //buffer.
+ oddhandled = true;
+
+ //get the last byte of the last buffer and shift it into msb.
+ short data = ((char*)sg_list.buf).len - 1)];
+ data = data << 8;
+
+ //add in the first byte from my buffer to the lsb.
+ data |= ((char*)sg_list.buf);
+ //correct my current pointer (since i just sent one of my bytes).
+ sdata = (unsigned short *)(sg_list.buf + 1);
+
+ //send this off.
+ put_data(sc, *sdata);
+ len = sg_list.len - 1;
+ }
+ else {
+ oddhandled = false;
+ sdata = (unsigned short *)sg_list.buf;
+ len = sg_list.len;
+ }
+ cyg_assert( sdata, "no sg data pointer here" );
+
+ //if this isn't the last buffer and my len is odd then don't transfer
+ //the last byte (the next iteration will handle it).
+ if(i != (sg_len - 1) && (len & 1))
+ len--;
+
while(len >= sizeof(*sdata)) {
put_data(sc, *sdata++);
len -= sizeof(*sdata); <div align='right'><{post_snapback}> (index.php?act=findpost&pid=12954)</div> --- Quote End --- <div align='right'><{post_snapback}> (index.php?act=findpost&pid=13264)</div> [/b] --- Quote End --- Tuck: Ok......thanks for your reply and directing me to the solution to this problem. Basically we only need to look at whether or not we have a byte left over from the last transmission. In that case, we need to output output the remain byte plus the first byte of the next buffer. This results in odd data alignment. To fix this, there are two while loops; one for even alignment and one for odd alignment. The following code works with no asserts and no checksum errors. // modified 03/09/2006 to handle odd lenght segment buffers bool byteRemaining = false; // indicates byte remaining from last buffer short data; // data to be sent to device char * pCData; // temp pointer to char array for (i = 0; i < sg_len; i++) { // get the data length and the pointer to the data sdata = (unsigned short *)sg_list.buf;
len = sg_list.len; CYG_ASSERT( sdata, "No sg data pointer here" ); // is there a byte remaining from the last buffer ? if( byteRemaining) { // yes - send the remaining byte with the first byte of this segment data = ((char*)sg_list[i-1].buf)[(sg_list[i-1].len - 1)]; //Add in the first byte from my buffer to the LSB. data |= ((char*)sg_list.buf)[0] << 8;
//send this off.
put_data(sc, data);
//correct my current pointer (since i just sent one of my bytes).
pcdata = ((char *)sg_list.buf) + 1; // adjust the length len--; // output data aligned to short while(len >= sizeof(*sdata)) { data = *pCData++; data |= *pCData++ << 8; put_data(sc, data); len -= sizeof( short); } } else { // output while(len >= sizeof(*sdata)) { put_data(sc, *sdata++); len -= sizeof(*sdata); } } byteRemaining = len; } CYG_ASSERT( sdata, "No sg data pointer outside" );