LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Networking (http://www.linuxquestions.org/questions/linux-networking-3/)
-   -   3Com 3c905 - Problems trying to send a frame in my own kernel module (http://www.linuxquestions.org/questions/linux-networking-3/3com-3c905-problems-trying-to-send-a-frame-in-my-own-kernel-module-640263/)

gambuzo 05-06-2008 08:30 AM

3Com 3c905 - Problems trying to send a frame in my own kernel module
 
Hi all,

I've been trying to write a simple network driver for the 3Com 3c509B device in Linux, just for fun. Unfortunately, with no success. In my "module" I try to only send one frame, but it never gets downloaded by the NIC.

My kernel is 2.6.18, the bus is PCI.
I get all registers set as expected. I suppose something is wrong with DMA bus mastering. It seems as if the NIC doesn't download the data from the addresses I provide.
I get the dnInProg bit set in the DmaCtrl register (one of the NIC registers), so "Download is in progress", but in fact it doesn't work.

Below I put my code (somewhat modified to be short) in two versions, one with dma_pool_create/alloc() calls, and the other with dma_map_single(). Both produce the same results, but with no success (sending one frame). All of this runs after a successful request_irq().

I based the code on the "3C90x and 3C90xB NICs Technical Reference" from 3Com, published August 1998.

Could anybody help me ? I'm quite discouraged and frustrated. What is wrong with the code? Did I miss something to get DMA working? The NIC register details are not important here, I'm asking mainly about DMA.

###########################################################
// dma_map_single() version

#define FRAME_SIZE 60

// Example ARP Request with random padding
u8 string[FRAME_SIZE] =
{0xff,0xff,0xff,0xff,0xff,0xff,...};

unsigned long HostRegBaseAddr; // NIC registers
u32 *DPD_mem=NULL;
u8 *frame_mem=NULL;
dma_addr_t DPD = 0, frame = 0;

struct pci_dev *pdev = NULL;

// Reset the device
iowrite16(GlobalReset,HostRegBaseAddr+14);
while (ioread16(HostRegBaseAddr+14)& cmdInProgress)
printk("Waiting...\n");

// Enable indications and interrupts
iowrite16(SetIndicationEnable | txComplete|dnComplete,HostRegBaseAddr+14);
iowrite16(SetInterruptEnable | txComplete|dnComplete,HostRegBaseAddr+14);

if ((frame_mem=kmalloc(FRAME_SIZE, GFP_DMA)) != NULL)
{
for (i=0; i<FRAME_SIZE; i++)
frame_mem[i] = string[i];
}
else
{error...}

if ((DPD_mem = kmalloc(16, GFP_DMA)) != NULL)
{
// Construct the DPD
DPD_mem[0] = 0; // DnNextPtr
DPD_mem[1] = 0x80008000; // FSH
DPD_mem[2] = frame; // FirstDnFragAddr
DPD_mem[3] = 0x800000003c; // FirstDnFragLen
}
else {error...}

DPD = dma_map_single(&pdev->dev, DPD_mem, 16, DMA_TO_DEVICE);
if (!DPD) {error...}

frame = dma_map_single(&pdev->dev, frame_mem, FRAME_SIZE, DMA_TO_DEVICE);
if (!frame) {error...}

// Send the frame
iowrite16(TxEnable, HostRegBaseAddr+14);
iowrite32(DPD, HostRegBaseAddr+0x24);
...
#############################################################



###########################################################
// dma_pool_create/alloc() version

#define FRAME_SIZE 60

// Example ARP Request with random padding
u8 string[FRAME_SIZE] =
{0xff,0xff,0xff,0xff,0xff,0xff,...};

unsigned long HostRegBaseAddr; // NIC registers
struct dma_pool *DPD_pool=NULL, *frame_pool=NULL;
unsigned long DPD_handle=0, frame_handle=0;
dma_addr_t DPD = 0, frame = 0;

struct pci_dev *pdev = NULL;

// Reset the device
iowrite16(GlobalReset,HostRegBaseAddr+14);
while (ioread16(HostRegBaseAddr+14)& cmdInProgress)
printk("Waiting...\n");

// Enable indications and interrupts
iowrite16(SetIndicationEnable | txComplete|dnComplete,HostRegBaseAddr+14);
iowrite16(SetInterruptEnable | txComplete|dnComplete,HostRegBaseAddr+14);

// Allocate DMA-memory for storing the DPD
if ((DPD_pool = dma_pool_create("DPD_pool", &(pdev->dev), 16, 16, 4096)) == NULL)
{
printk(KERN_ALERT "DPD_pool error");
return -1;
}

if ((frame_pool = dma_pool_create("frame_pool", &(pdev->dev), FRAME_SIZE, 16, 4096)) == NULL)
{
printk(KERN_ALERT "frame_pool error");
return -1;
}

printk("Pools OK\n");

if ((DPD = dma_pool_alloc(DPD_pool, GFP_DMA, &DPD_handle)) == NULL)
{
printk(KERN_ALERT "DPD alloc error\n");
return -1;
}

if ((frame = dma_pool_alloc(frame_pool, GFP_DMA,
&frame_handle))==NULL)
{
printk(KERN_ALERT "frame alloc error\n");
return -1;
}

for (i=0; i<FRAME_SIZE; i++)
frame[i] = string[i];

// Construct the DPD
DPD[0] = 0; // DnNextPtr
DPD[1] = 0x80008000; // FSH
DPD[2] = frame_handle; // FirstDnFragAddr
DPD[3] = 0x8000003c; // FirstDnFragLen

// Send the frame
iowrite16(TxEnable, HostRegBaseAddr+14);
iowrite32(DPD_handle, HostRegBaseAddr+0x24);
...
#############################################################

Thank you,
gambuzo.


All times are GMT -5. The time now is 06:02 PM.