[<prev] [next>] [day] [month] [year] [list]
Message-ID: <9adbc84c0805131203x4af69c15lbdd7317dbeee44f3@mail.gmail.com>
Date: Tue, 13 May 2008 21:03:29 +0200
From: "Billy Smith" <gambuzo@...il.com>
To: netdev@...r.kernel.org
Subject: 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).
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?
###########################################################
// dma_map_single() version
#define FRAME_SIZE 64
// 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;
...
pci_enable_device(pdev);
pci_set_master(pdev);
if (request_irq(pdev->irq, drvhandler, IRQF_SHARED, "3ComNIC", (void*)
&netdev) == 0)
{error... return -1;}
// 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 Data Packet Descriptor
DPD_mem[0] = 0; // DnNextPtr - there is no next DPD
DPD_mem[1] = 0x80008000; // FSH
DPD_mem[2] = frame; // FirstDnFragAddr
DPD_mem[3] = 0x8000000040; // FirstDnFragLen; 3c means the frame length
}
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 64
// 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;
...
pci_enable_device(pdev);
pci_set_master(pdev);
if (request_irq(pdev->irq, drvhandler, IRQF_SHARED, "3ComNIC", (void*)
&netdev) == 0)
{error... return -1;}
// 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 Data Packet Descriptor
DPD[0] = 0; // DnNextPtr
DPD[1] = 0x80008000; // FSH
DPD[2] = frame_handle; // FirstDnFragAddr
DPD[3] = 0x80000040; // FirstDnFragLen
// Send the frame
iowrite16(TxEnable, HostRegBaseAddr+14);
iowrite32(DPD_handle, HostRegBaseAddr+0x24);
...
#############################################################
I attach the full module code. Thank you,
gambuzo.
Download attachment "drv_tx.c" of type "application/octet-stream" (7284 bytes)
Download attachment "drv_tx1.c" of type "application/octet-stream" (7622 bytes)
Powered by blists - more mailing lists