2006-09-10 14:32:17

by mwitosz-linux

[permalink] [raw]
Subject: problem with OWN bit when writting driver for rtl8139?

hi, everybody
my name is Mariusz, I am newbie to linux kernel,
For several weeks I have been writing kernel driver for network card based on
rtl8139c chip.

I have some problems with DMA, i suppose.

there is a bit in Transmit Status Descriptor of RTL8139c which after clearing(It must be cleared to
start transmit operation) shouldb be placed in 1 state - which according to RTL8139 specification means that
DMA copy from memory to internal RTL fifo has finished.

The problem is: rtl doesn't clear this bit

I use pci_map_single to map address of packet buffer to dma capable memory, then cpu_to_le32 to get physicall
address of this buffer.

Do you have any idea what may work wrong?

here is transmit part of my driver:

/**function called by kernel when kernel wat to transmit packet which is
located in socket buffer structure skb
@param skb: socket buffer structure with packet to transmit
@param netdev: device used to send this packet
*/
int rtl_tx(struct sk_buff *skb, struct net_device *netdev){
int len;
char *data, shortpkt[ETH_ZLEN];
struct rtl_private_data *priv;

//get private data pointer
priv = netdev_priv(netdev);

//if the length of this packet is below 64 bytes, expand it to 64 bytes
//by padding
data = skb->data;
len = skb->len;
if(len < ETH_ZLEN){
memset(shortpkt, 0, ETH_ZLEN);
memcpy(shortpkt, skb->data, skb->len);
len = ETH_ZLEN;
data = shortpkt;
}

//save skb for freeing when this packet will be transmited
priv->skb = skb;


//finaly transmit this packet
udelay(500);
rtl_hw_tx(data, len, netdev, skb);

return 0;
};


/**transmit data from packet
@param data: buffer with packet
@param len: lenth of this packet
@param netdev: network device used to transmit this packet
*/
int rtl_hw_tx(char *data, int len, struct net_device *netdev, struct sk_buff *skb){
unsigned char td;
u32 physical_addr;
unsigned int physical_addr_len;
//void *base_ptr;
u32 io_base;
struct rtl_private_data *priv;
unsigned int dword;
//u32 ertx;
int i;
u16 word;
bool assigned;
dma_addr_t mapping;
int result;
int j;


//KDEBUG("@PACKET IS --------------------------------------------------------------\n");
//show_packet(data, len);
//KDEBUG("@PACKET IS --------------------------------------------------------------\n");

KDEBUG("@rtl_hw_tx: new packet to transmit \n");

priv = netdev_priv(netdev);
//base_ptr = priv->base_ptr;
io_base = priv->io_base;

//wait for available free transmit descriptor
assigned = false;
//while(true){
for(i=0; i<1000; i++){

if( !is_empty( &descriptors ) ){
//there is no available transmit descriptor

assigned = true;
break;
}
}

if( !assigned) {
KERROR("@rtl_hw_txt: no available desriptor \n");
return 1;
}

//free transmit descriptor found, get it!
dequeue(&descriptors, &td);

spin_lock_irq(&priv->lock);


//skb_copy_and_csum_dev(skb, priv->tx_buff[td]);
//dev_kfree_skb(skb);



//get physical address of data buffer
//physical_addr = __pa(data);
mapping = pci_map_single(priv->pcidev, data, len, PCI_DMA_TODEVICE);
if(mapping == NULL){
KERROR("MAPPING null \n");
}

KDEBUG("@rtl_hw_tx: mapping is %d \n", mapping);
physical_addr = cpu_to_le32(mapping);


//KDEBUG("@rtl_hw_tx: compare: %ld ... %ld \n", physical_addr, __pa(data));


//set physical_address of this packet in tsad register
outl(physical_addr, io_base + tsad[td]);
//outl(priv->dma_buff[td], io_base + tsad[td]);
//iowrite32(physical_addr, base_ptr + tsad[td]);
//outl(physical_addr, io_ba


//early transmit threshlog
//ertx = 2;
//ertx = ertx << TSD_ERTHX_OFS;

//set size of transmited data
physical_addr_len = len;
KINFO("@rtl_hw_tx: physical_addr_len is %x \n", physical_addr_len);

dword = inl(io_base + tsd[td]);
KINFO("@rtl_hw_tx: current tsd is %x \n", dword);

dword = dword & ~(TSD_SIZE | TSD_ERTHX);
physical_addr_len = physical_addr_len & TSD_SIZE;
dword = dword | (physical_addr_len);
KINFO("@rtl_hw_tx: new tsd is %x \n", dword);

outl(dword, io_base + tsd[td]);
dword = inl(io_base + tsd[td]);
KINFO("@rtl_hw_tx: written tsd is %x \n", dword);

//save skb buffer pointer for future use
//skbs[td]= priv->skb;

priv->x = 0;
//clear own bit to start transmision
KINFO("@rtl_hw_tx: before clearing OWN: %x \n", dword);

word = inw(io_base+ IMR);
dword = inl(io_base + tsd[td]);
KDEBUG("@-----------IMR-------------: %x \n", word);
KDEBUG("@-----------TSD: %d %x-------------: \n", td, dword);

netdev->trans_start = jiffies;

dword = dword & ~TSD_OWN;
outl(dword, io_base + tsd[td]);

//dword = inl(io_base + tsd[td]);
//KINFO("@rtl_hw_tx: after clearing OWN: %x \n", dword);

for(j=0; j<500; j++){
word = inw(io_base + ISR);
dword = inl(io_base + tsd[td]);
KINFO("@rtl_hw_tx: ISR is %x TSD is %x \n", word, dword);
udelay(10000);
}

spin_unlock_irq(&priv->lock);
return 0;
}



and here is output from kernel

klogd 1.4.1#17.2, log source = /proc/kmsg started.
Cannot find map file.
No module symbols loaded - kernel modules not enabled.

<7>kobject rtl: registering. parent: <NULL>, set: module
<7>DEBUG __________________________module rtlmodule loaded___________________________
<7>DEBUG @register_as_network_device: New pci_dev to register as net_device
<6>ACPI: PCI Interrupt 0000:00:09.0[A] -> Link [LNKB] -> GSI 11 (level, low) -> IRQ 11
<7>DEBUG @register_as_network_device: Device Enabled
<7>DEBUG @register_as_network_device: pci_set_dma_mask ok
<7>DEBUG @register_as_network_device: request region ok
<7>DEBUG @register_as_network_device: IOAR is e001
<7>PCI: Enabling bus mastering for device 0000:00:09.0
<7>DEBUG @ether_dev_init: New net_device registered
<7>DEBUG @init_hardware: initializing hardware
<7>DEBUG @init_hardware: reseting rtl8139
<3>ERROR @init_hardware: NOT RESET
<7>DEBUG @init_hardware: enabling transmiter and receiver
<7>DEBUG @init_hardware: TCR is 74400600
<7>DEBUG @create_transmit_descriptors: creating 4 transmit descriptors
<7>DEBUG @create_transmit_descriptors: queue initialized
<7>DEBUG @create_transmit_descriptors: 4 transmit descriptors enqueued
<7>DEBUG @create TSD is 2000
<7>DEBUG @create TSD is 2000
<7>DEBUG @create TSD is 2000
<7>DEBUG @create TSD is 2000
<7>DEBUG @create ISR is 0
<7>DEBUG @init_software: found irq for this device: 11
<7>kobject eth1: registering. parent: net, set: class_obj
<7>DEBUG @register_as_network_device: netdev registered
<7>DEBUG @rtlinit: New device found
<7>DEBUG @ether_dev_open: interface is going up
<7>DEBUG @ether_dev_open: setting mac address to 0:e:2e:80:2d:de
<7>DEBUG @ether_dev_open: mac addres set properly
<7>DEBUG @ether_dev_open: irq successfuly requested
<7>DEBUG @ether_dev_open: setting interrupt mask register: 49260
<7>DEBUG @ether_dev_open: queue stared
tx: ISR is 0 TSD is 3c
<6>INFO @rtl_hw_tx: ISR is 0 TSD is 3c
<6>INFO @rtl_hw_tx: ISR is 0 TSD is 3c
...
...
<6>INFO @rtl_hw_tx: ISR is 0 TSD is 3c

best regards,
Mariusz Witosz


2006-09-10 15:50:00

by Dave Jones

[permalink] [raw]
Subject: Re: problem with OWN bit when writting driver for rtl8139?

On Sun, Sep 10, 2006 at 04:32:13PM +0200, mwitosz-linux wrote:
> hi, everybody
> my name is Mariusz, I am newbie to linux kernel,
> For several weeks I have been writing kernel driver for network card based on
> rtl8139c chip.

You do realise that 8139too already supports 8139C ?

Dave

2006-09-10 15:47:24

by Jindrich Makovicka

[permalink] [raw]
Subject: Re: problem with OWN bit when writting driver for rtl8139?

On Sun, 10 Sep 2006 16:32:13 +0200
mwitosz-linux <[email protected]> wrote:

> hi, everybody
> my name is Mariusz, I am newbie to linux kernel,
> For several weeks I have been writing kernel driver for network card
> based on rtl8139c chip.

[...]

Just curious - do you write it for fun or you have some special reason
for not using 8139too?

Regards,
--
Jindrich Makovicka