Hi All,
I am currently working on the realtek driver available in
http://linuxgazette.net/156/jangir.html.
When I run the driver, pci_request_regions is erring out as :
ifconfig rtl8139 up
SIOCSIFFLAGS: Device or resource busy
[root@asdlab realtek]# dmesg | tail -50
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_get_stats is called
pci 0000:04:03.0: PCI INT A disabled
pci 0000:04:03.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
Device enabled
----------------------------------------------------------------
Base 0 Starting Address = 9c00 End Address = 9cff Length = 256
This Port is I/O mapped. It is NON Prefetchable.This is readable and writable.
Base 1 Starting Address = fdaff000 End Address = fdaff0ff Length = 256
This Port is Memory mapped. It is NON Prefetchable. This is readable and
writable.
rtl8139_init is called
region is Memory mapped region
rtl8139_dev is not NULL
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_get_stats is called
rtl8139_open is called
IRQ handler type mismatch for IRQ 16
current handler: via@pci:0000:01:00.0
Pid: 8522, comm: ifconfig Tainted: P 2.6.27.5-117.fc10.i686 #1
[<c04637e7>] setup_irq+0x213/0x22d
[<f886d6c0>] ? rtl8139_interrupt+0x0/0x230 [real5]
[<c04638ef>] request_irq+0xee/0x10c
[<f886d4e6>] rtl8139_open+0x31/0x20b [real5]
[<c0631062>] dev_open+0x76/0xb4
[<c0630ae3>] dev_change_flags+0xa2/0x155
[<c067143b>] devinet_ioctl+0x21a/0x49b
[<c06721dc>] inet_ioctl+0x8e/0xa7
[<c0625597>] sock_ioctl+0x1b4/0x1d8
[<c06253e3>] ? sock_ioctl+0x0/0x1d8
[<c049a0b6>] vfs_ioctl+0x22/0x69
[<c049a347>] do_vfs_ioctl+0x24a/0x25d
[<c04f7b0c>] ? selinux_file_ioctl+0x35/0x38
[<c049a39a>] sys_ioctl+0x40/0x5a
[<c0403c76>] syscall_call+0x7/0xb
[<c06a007b>] ? init_intel_cacheinfo+0x0/0x421
I am attaching the code. Any clues as to why?
Thanks & Regards,
D.Giriprasad
#define REALTEK_VENDER_ID 0x10EC
#define REALTEK_DEVICE_ID 0x8139
//#define REALTEK_VENDER_ID 0x10b5
//#define REALTEK_DEVICE_ID 0x9050
//#define VENDOR_ID 0x10b5
//#define DEVICE_ID 0x9050
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/stddef.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
int print_pci(struct pci_dev *pdev);
#define TX_BUF_SIZE 1536 /* should be at least MTU + 14 + 4 */
#define TOTAL_TX_BUF_SIZE (TX_BUF_SIZE * NUM_TX_SIZE)
/* 8139 register offsets */
#define TSD0 0x10
#define TSAD0 0x20
#define RBSTART 0x30
#define CR 0x37
#define CAPR 0x38
#define IMR 0x3c
#define ISR 0x3e
#define TCR 0x40
#define RCR 0x44
#define MPC 0x4c
#define MULINT 0x5c
/* TSD register commands */
#define TxHostOwns 0x2000
#define TxUnderrun 0x4000
#define TxStatOK 0x8000
#define TxOutOfWindow 0x20000000
#define TxAborted 0x40000000
#define TxCarrierLost 0x80000000
/* CR register commands */
#define RxBufEmpty 0x01
#define CmdTxEnb 0x04
#define CmdRxEnb 0x08
#define CmdReset 0x10
/* ISR Bits */
#define RxOK 0x01
#define RxErr 0x02
#define TxOK 0x04
#define TxErr 0x08
#define RxOverFlow 0x10
#define RxUnderrun 0x20
#define RxFIFOOver 0x40
#define CableLen 0x2000
#define TimeOut 0x4000
#define SysErr 0x8000
#define INT_MASK (RxOK | RxErr | TxOK | TxErr | \
RxOverFlow | RxUnderrun | RxFIFOOver | \
CableLen | TimeOut | SysErr)
#define NUM_TX_SIZE 4
#define NUM_TX_DESC 4
/* Size of the in-memory receive ring. */
#define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */
#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
#define RX_BUF_PAD 16 /* see 11th and 12th bit of RCR: 0x44 */
#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle pkt wrap */
#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
static void rtl8139_init_ring (struct net_device *dev);
static void rtl8139_hw_start (struct net_device *dev);
static void rtl8139_chip_reset (void *ioaddr);
struct rtl8139_private
{
struct pci_dev *pci_dev; /* PCI device */
void *mmio_addr; /* memory mapped I/O addr */
unsigned long regs_len; /* length of I/O or MMI/O region */
unsigned int tx_flag;
unsigned int cur_tx;
unsigned int dirty_tx;
unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
unsigned char *tx_bufs; /* Tx bounce buffer region. */
dma_addr_t tx_bufs_dma;
struct net_device_stats stats;
unsigned char *rx_ring;
dma_addr_t rx_ring_dma;
unsigned int cur_rx;
};
static struct pci_dev* probe_for_realtek8139(void)
{
struct pci_dev *pdev = NULL;
/* Ensure we are not working on a non-PCI system */
//if(!pci_present( )) {
// printk("<1>pci not present\n");
// return pdev;
//}
//else
// printk("<1>pci device is present\n");
/* Look for RealTek 8139 NIC */
pdev = pci_find_device(REALTEK_VENDER_ID, REALTEK_DEVICE_ID, NULL);
if(pdev) {
//printk("Found PCI device with vendorid = %x deviceid = %x\n",
REALTEK_VENDER_ID, REALTEK_DEVICE_ID);
// device found, enable it
if(pci_enable_device(pdev)) {
//printk("Could not enable the device\n");
return NULL;
}
else
printk("Device enabled\n");
}
else {
//printk("device not found\n");
return pdev;
}
return pdev;
}
#define DRIVER "rtl8139"
static struct net_device *rtl8139_dev = NULL;
static int rtl8139_init(struct pci_dev *pdev, struct net_device **dev_out)
{
struct net_device *dev;
struct rtl8139_private *tp;
/*
* alloc_etherdev allocates memory for dev and dev->priv.
* dev->priv shall have sizeof(struct rtl8139_private) memory
* allocated.
*/
printk("rtl8139_init is called\n");
dev = alloc_etherdev(sizeof(struct rtl8139_private));
if(!dev) {
printk("Could not allocate etherdev\n");
return -1;
}
//printk("rtl8139_init , initializing the structure struct net_device
\n");
tp = dev->priv;
tp->pci_dev = pdev;
*dev_out = dev;
//printk("rtl8139_init exiting .........\n");
return 0;
}
static void rtl8139_interrupt (int irq, void *dev_instance, struct pt_regs
*regs)
{
struct net_device *dev = (struct net_device*)dev_instance;
struct rtl8139_private *tp = dev->priv;
void *ioaddr = tp->mmio_addr;
unsigned short isr = readw(ioaddr + ISR);
/* clear all interrupt.
* Specs says reading ISR clears all interrupts and writing
* has no effect. But this does not seem to be case. I keep on
* getting interrupt unless I forcibly clears all interrupt :-(
*/
writew(0xffff, ioaddr + ISR);
if((isr & TxOK) || (isr & TxErr))
{
while((tp->dirty_tx != tp->cur_tx) || netif_queue_stopped(dev))
{
unsigned int txstatus =
readl(ioaddr + TSD0 + tp->dirty_tx *
sizeof(int));
if(!(txstatus & (TxStatOK | TxAborted | TxUnderrun)))
break; /* yet not transmitted */
if(txstatus & TxStatOK) {
printk("Transmit OK interrupt\n");
tp->stats.tx_bytes += (txstatus & 0x1fff);
tp->stats.tx_packets++;
}
else {
printk("Transmit Error interrupt\n");
tp->stats.tx_errors++;
}
tp->dirty_tx++;
tp->dirty_tx = tp->dirty_tx % NUM_TX_DESC;
if((tp->dirty_tx == tp->cur_tx) &
netif_queue_stopped(dev))
{
printk("waking up queue\n");
netif_wake_queue(dev);
}
}
}
if(isr & RxErr) {
/* TODO: Need detailed analysis of error status */
printk("receive err interrupt\n");
tp->stats.rx_errors++;
}
if(isr & RxOK) {
printk("receive interrupt received\n");
while((readb(ioaddr + CR) & RxBufEmpty) == 0)
{
unsigned int rx_status;
unsigned short rx_size;
unsigned short pkt_size;
struct sk_buff *skb;
if(tp->cur_rx > RX_BUF_LEN)
tp->cur_rx = tp->cur_rx % RX_BUF_LEN;
/* TODO: need to convert rx_status from little to host
endian
* XXX: My CPU is little endian only :-)
*/
rx_status = *(unsigned int*)(tp->rx_ring + tp->cur_rx);
rx_size = rx_status >> 16;
/* first two bytes are receive status register
* and next two bytes are frame length
*/
pkt_size = rx_size - 4;
/* hand over packet to system */
skb = dev_alloc_skb (pkt_size + 2);
if (skb) {
skb->dev = dev;
skb_reserve (skb, 2); /* 16 byte align the IP
fields */
skb_copy_and_csum_dev(skb, tp->rx_ring +
tp->cur_rx + 4);
//eth_copy_and_sum( skb, tp->rx_ring +
tp->cur_rx + 4, pkt_size, 0);
skb_put (skb, pkt_size);
skb->protocol = eth_type_trans (skb, dev);
netif_rx (skb);
dev->last_rx = jiffies;
tp->stats.rx_bytes += pkt_size;
tp->stats.rx_packets++;
}
else {
printk("Memory squeeze, dropping packet.\n");
tp->stats.rx_dropped++;
}
/* update tp->cur_rx to next writing location * /
tp->cur_rx = (tp->cur_rx + rx_size + 4 + 3) & ~3;
/* update CAPR */
writew(tp->cur_rx, ioaddr + CAPR);
}
}
if(isr & CableLen)
printk("cable length change interrupt\n");
if(isr & TimeOut)
printk("time interrupt\n");
if(isr & SysErr)
printk("system err interrupt\n");
return;
}
static int rtl8139_open(struct net_device *dev)
{
int retval;
struct rtl8139_private *tp = dev->priv;
printk("rtl8139_open is called\n");
/* get the IRQ
* second arg is interrupt handler
* third is flags, 0 means no IRQ sharing
*/
retval = request_irq(dev->irq, rtl8139_interrupt, 0 , dev->name, NULL);
//retval = request_irq(dev->irq, rtl8139_interrupt, SA_INTERRUPT,
dev->name, dev);
if(retval)
return retval;
/* get memory for Tx buffers
* memory must be DMAable
*/
tp->tx_bufs = pci_alloc_consistent(
tp->pci_dev, TOTAL_TX_BUF_SIZE, &tp->tx_bufs_dma);
if(!tp->tx_bufs) {
free_irq(dev->irq, dev);
return -ENOMEM;
}
tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
&tp->rx_ring_dma);
if((!tp->tx_bufs) || (!tp->rx_ring)) {
free_irq(dev->irq, dev);
if(tp->tx_bufs) {
pci_free_consistent(tp->pci_dev,
TOTAL_TX_BUF_SIZE, tp->tx_bufs, tp->tx_bufs_dma);
tp->tx_bufs = NULL;
}
if(tp->rx_ring) {
pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
tp->rx_ring, tp->rx_ring_dma);
tp->rx_ring = NULL;
}
return -ENOMEM;
}
tp->tx_flag = 0;
rtl8139_init_ring(dev);
rtl8139_hw_start(dev);
return 0;
}
static void rtl8139_init_ring (struct net_device *dev)
{
struct rtl8139_private *tp = dev->priv;
int i;
tp->cur_tx = 0;
tp->dirty_tx = 0;
for (i = 0; i < NUM_TX_DESC; i++)
tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];
return;
}
static void rtl8139_hw_start (struct net_device *dev)
{
struct rtl8139_private *tp = dev->priv;
void *ioaddr = tp->mmio_addr;
u32 i;
rtl8139_chip_reset(ioaddr);
/* Must enable Tx/Rx before setting transfer thresholds! */
writeb(CmdTxEnb | CmdRxEnb, ioaddr + CR);
/* tx config */
writel(0x00000600, ioaddr + TCR); /* DMA burst size 1024 */
/* rx config */
writel(((1 << 12) | (7 << 8) | (1 << 7) |
(1 << 3) | (1 << 2) | (1 << 1)), ioaddr + RCR);
/* init Tx buffer DMA addresses */
for (i = 0; i < NUM_TX_DESC; i++) {
writel(tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs),
ioaddr + TSAD0 + (i * 4));
}
/* init RBSTART */
writel(tp->rx_ring_dma, ioaddr + RBSTART);
/* initialize missed packet counter */
writel(0, ioaddr + MPC);
/* no early-rx interrupts */
writew((readw(ioaddr + MULINT) & 0xF000), ioaddr + MULINT);
/* Enable all known interrupts by setting the interrupt mask. */
writew(INT_MASK, ioaddr + IMR);
netif_start_queue (dev);
return;
}
static void rtl8139_chip_reset (void *ioaddr)
{
int i;
/* Soft reset the chip. */
writeb(CmdReset, ioaddr + CR);
/* Check that the chip has finished the reset. */
for (i = 1000; i > 0; i--) {
barrier();
if ((readb(ioaddr + CR) & CmdReset) == 0)
break;
udelay (10);
}
return;
}
static int rtl8139_stop(struct net_device *dev)
{
printk("rtl8139_open is called\n");
free_irq(dev->irq, NULL);
return 0;
}
static int rtl8139_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct rtl8139_private *tp = dev->priv;
void *ioaddr = tp->mmio_addr;
unsigned int entry = tp->cur_tx;
unsigned int len = skb->len;
#define ETH_MIN_LEN 60 /* minimum Ethernet frame size */
printk("rtl8139_start_xmit is called\n");
if (len < TX_BUF_SIZE) {
if(len < ETH_MIN_LEN)
memset(tp->tx_buf[entry], 0, ETH_MIN_LEN);
skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
dev_kfree_skb(skb);
} else {
skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
dev_kfree_skb(skb);
return 0;
}
writel(tp->tx_flag | max(len, (unsigned int)ETH_MIN_LEN),
ioaddr + TSD0 + (entry * sizeof (u32)));
entry++;
tp->cur_tx = entry % NUM_TX_DESC;
if(tp->cur_tx == tp->dirty_tx) {
netif_stop_queue(dev);
}
return 0;
}
static struct net_device_stats* rtl8139_get_stats(struct net_device *dev)
{
struct rtl8139_private *tp;
printk("rtl8139_get_stats is called\n");
tp = netdev_priv(dev);
return &tp->stats;
//return 0;
}
int init_module(void)
{
struct pci_dev *pdev;
unsigned long mmio_start, mmio_end, mmio_len, mmio_flags;
void *ioaddr;
struct rtl8139_private *tp;
int i, err = 0;
pdev = probe_for_realtek8139( );
if(!pdev)
return 0;
print_pci(pdev);
if(rtl8139_init(pdev, &rtl8139_dev)) {
printk("Could not initialize device\n");
return 0;
}
tp = rtl8139_dev->priv; // rtl8139 private information
//printk("Reading the PCI BAR registers \n");
// get PCI memory mapped I/O space base address from BAR1
mmio_start = pci_resource_start(pdev, 1);
mmio_end = pci_resource_end(pdev, 1);
mmio_len = pci_resource_len(pdev, 1);
mmio_flags = pci_resource_flags(pdev, 1);
//printk("Checking the PCI BAR registers for Memory mapped flag \n");
// make sure above region is MMI/O
if(!(mmio_flags & IORESOURCE_MEM)) {
printk("region not MMI/O region\n");
goto cleanup1;
}
else
printk("region is Memory mapped region\n");
//printk("Calling pci_request_region \n");
// get PCI memory space
if(pci_request_regions(pdev, DRIVER)) {
printk("Could not get PCI region\n");
goto cleanup1;
}
//printk("Calling pci_set_master\n");
pci_set_master(pdev);
//printk("Calling ioremap\n");
// ioremap MMI/O region
ioaddr = ioremap(mmio_start, mmio_len);
if(!ioaddr) {
printk("Could not ioremap\n");
goto cleanup2;
}
//printk("Assigning ioaddress and length \n");
rtl8139_dev->base_addr = (long)ioaddr;
tp->mmio_addr = ioaddr;
tp->regs_len = mmio_len;
// UPDATE NET_DEVICE
//printk("Assigning hardware address \n");
for(i = 0; i < 6; i++) { // Hardware Address
rtl8139_dev->dev_addr[i] = readb(rtl8139_dev->base_addr+i);
rtl8139_dev->broadcast[i] = 0xff;
}
rtl8139_dev->hard_header_len = 14;
//printk("Assigning function address \n");
memcpy(rtl8139_dev->name, DRIVER, sizeof(DRIVER)); // Device Name
rtl8139_dev->irq = pdev->irq; // Interrupt Number
rtl8139_dev->open = rtl8139_open;
rtl8139_dev->stop = rtl8139_stop;
rtl8139_dev->hard_start_xmit = rtl8139_start_xmit;
rtl8139_dev->get_stats = rtl8139_get_stats;
if(rtl8139_dev != NULL)
printk("rtl8139_dev is not NULL\n");
//printk("Calling register_netdev \n");
// register the device
if(register_netdev(rtl8139_dev)) {
printk("Could not register netdevice\n");
goto cleanup0;
}
//printk("AFTEr the call to register_netdev \n");
goto noerror;
cleanup0:
//printk("Error so, unregister_netdev \n");
unregister_netdev(rtl8139_dev);
err = 1;
cleanup2:
//printk("Error so, unmap \n");
iounmap(tp->mmio_addr);
err = 1;
cleanup1:
//printk("Error so, pci_release_regions \n");
pci_release_regions(tp->pci_dev);
err = 1;
noerror:
//printk("Init function exiting fine ...............\n");
return err;
}
void cleanup_module(void)
{
struct rtl8139_private *tp;
tp = rtl8139_dev->priv;
iounmap(tp->mmio_addr);
pci_release_regions(tp->pci_dev);
unregister_netdev(rtl8139_dev);
pci_disable_device(tp->pci_dev);
return;
}
// Should be called after pci_find_device and pci_enable_device have been called
int print_pci(struct pci_dev *dev)
{
int i;
int start, end, length, resflags;
for (i = 0; i < 6; i++)
{
start = pci_resource_start (dev, i);
if (!start)
continue;
end = pci_resource_end (dev, i);
length = pci_resource_len (dev, i);
resflags = pci_resource_flags (dev, i);
if (resflags & IORESOURCE_IO)
{
printk("----------------------------------------------------------------\n");
printk("Base %d Starting Address = %x End Address = %x
Length = %d\n",i, start, end, length);
printk ("This Port is I/O mapped. ");
if (resflags & IORESOURCE_PREFETCH)
printk ("It is Prefetchable.");
else
printk ("It is NON Prefetchable.");
if (resflags & IORESOURCE_READONLY)
printk ("This is read only.\n");
else
printk ("This is readable and writable.\n");
if (check_region (start, length) < 0)
printk
("Base %d starting Address = %x End Address =
%x Length = %d resource is not available \n",
i, start, end, length);
//else if (request_region (start, length, DRIVER_NAME)
< 0)
// printk ("The Resource is not allocated for BAR
%d\n", i);
// else
// printk ("The Resource is allocated for BAR
%d\n", i);
}
else
{
if (resflags & IORESOURCE_MEM)
{
printk
("Base %d Starting Address = %x End Address =
%x Length = %d\n",i, start, end, length);
printk ("This Port is Memory mapped. ");
if (resflags & IORESOURCE_PREFETCH)
printk ("It is Prefetchable. ");
else
printk ("It is NON Prefetchable. ");
if (resflags & IORESOURCE_READONLY)
printk ("It is read only.\n");
else
printk ("This is readable and
writable.\n");
if (check_mem_region (start, length) < 0)
printk
("Base %d starting Address = %x End Address =
%x Length = %d resource is not available \n",
i, start, end, length);
else
{
//if (request_mem_region (start,
length, DRIVER_NAME) < 0)
// printk("The Resource is not
allocated for BAR %d\n", i);
//else
// printk ("The Resource is
allocated for BAR %d\n", i);
}
}
}
}
return 0;
}
_______________________________________________
india mailing list
[email protected]
https://admin.fedoraproject.org/mailman/listinfo/india