Commit 27c92a48 authored by Alessandro Rubini's avatar Alessandro Rubini

major work on the nic driver

Part of this comes from work side by side
with Tomasz, who was greatly helpful with this.
parent 75faa35e
......@@ -22,6 +22,7 @@
#include <linux/io.h>
#include "wr-nic.h"
#include "nic-mem.h"
/* The remove function is used by probe, so it's not __devexit */
static int __devexit wrn_remove(struct platform_device *pdev)
......@@ -113,10 +114,14 @@ static int __devinit wrn_probe(struct platform_device *pdev)
/* Map our resource list and instantiate the shortcut pointers */
if ( (err = __wrn_map_resources(pdev)) )
goto out;
wrn->regs = wrn->bases[WRN_BLOCK_NIC];
wrn->txd = (void *)&wrn->regs->TX1_D1;
wrn->rxd = (void *)&wrn->regs->RX1_D1;
wrn->txd = ((void *)wrn->regs) + 0x80; /* was: TX1_D1 */
wrn->rxd = ((void *)wrn->regs) + 0x100; /* was: RX1_D1 */
wrn->databuf = (void *)wrn->regs + offsetof(struct NIC_WB, MEM);
printk("regs %p, txd %p, rxd %p, buffer %p\n",
wrn->regs, wrn->txd, wrn->rxd, wrn->databuf);
/* Register the interrupt handlers (not shared) */
for (i = 0; i < ARRAY_SIZE(irq_names); i++) {
......@@ -142,6 +147,7 @@ static int __devinit wrn_probe(struct platform_device *pdev)
ep = netdev_priv(netdev);
ep->wrn = wrn;
ep->ep_regs = wrn->bases[WRN_FIRST_EP + i];
//printk("ep %p, regs %i = %p\n", ep, i, ep->ep_regs);
ep->ep_number = i;
if (i < WRN_NR_UPLINK)
set_bit(WRN_EP_IS_UPLINK, &ep->ep_flags);
......@@ -155,9 +161,28 @@ static int __devinit wrn_probe(struct platform_device *pdev)
/* This endpoint went in properly */
wrn->dev[i] = netdev;
}
err = 0; /* no more endpoints, we succeeded. Enable the device */
writel(NIC_CR_RX_EN | NIC_CR_TX_EN, &wrn->regs->CR);
/* Now, prepare RX descriptors */
for (i = 0; i < WRN_NR_RXDESC; i++) {
struct wrn_rxd *rx;
int offset;
rx = wrn->rxd + i;
offset = __wrn_desc_offset(wrn, WRN_DDIR_RX, i);
writel( (2000 << 16) | offset, &rx->rx3);
writel(NIC_RX1_D1_EMPTY, &rx->rx1);
}
/*
* make sure all head/tail are 0 -- not needed here, but if we
* disable and then re-enable, this _is_ needed
*/
wrn->next_tx_head = wrn->next_tx_tail = wrn->next_rx = 0;
writel(NIC_CR_RX_EN | NIC_CR_TX_EN, &wrn->regs->CR);
writel(~0, (void *)wrn->regs + 0x24 /* EIC_IER */);
printk("imr: %08x\n", readl((void *)wrn->regs + 0x28 /* EIC_IMR */));
err = 0;
out:
if (err) {
/* Call the remove function to avoid duplicating code */
......
......@@ -20,32 +20,33 @@ int wrn_phase_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
struct wrn_phase_req phase_req;
struct wrn_ep *ep = netdev_priv(dev);
u32 dmsr;
s32 dmtd_phase;
s32 ph;
phase_req.phase = 0;
phase_req.ready = 0;
dmsr = readl(ep->ep_regs->DMSR);
if(dmsr & EP_DMSR_PS_RDY) {
dmtd_phase = EP_DMSR_PS_VAL_R(dmsr);
ph = EP_DMSR_PS_VAL_R(dmsr);
// sign-extend, fix the average if out of range due to jitter
if(dmtd_phase & 0x800000) dmtd_phase |= 0xff000000;
/* Sign-extend the 24-bit value */
if(ph & 0x800000)
ph |= 0xff << 24;
// calculate the average
dmtd_phase /= WRN_DMTD_AVG_SAMPLES;
/* Divide by nsamples (average) */
ph /= WRN_DMTD_AVG_SAMPLES;
if(dmtd_phase > WRN_DMTD_MAX_PHASE)
dmtd_phase -= WRN_DMTD_MAX_PHASE;
if(dmtd_phase < 0) dmtd_phase += WRN_DMTD_MAX_PHASE;
/* Put it back in the proper range */
ph = (ph + WRN_DMTD_MAX_PHASE) % WRN_DMTD_MAX_PHASE;
phase_req.phase = dmtd_phase;
phase_req.phase = ph;
phase_req.ready = 1;
} else {
phase_req.phase = 0;
phase_req.ready = 0;
}
return copy_to_user(rq->ifr_data, &phase_req, sizeof(phase_req)) ?
-EFAULT : 0;
if (copy_to_user(rq->ifr_data, &phase_req, sizeof(phase_req)))
return -EFAULT;
return 0;
}
int wrn_calib_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
......
......@@ -56,7 +56,8 @@ static void wrn_update_link_status(struct net_device *dev)
bmsr = wrn_phy_read(dev, 0, MII_BMSR);
bmcr = wrn_phy_read(dev, 0, MII_BMCR);
netdev_dbg(dev, "%s: read %x %x", __func__, bmsr, bmcr);
//netdev_dbg(dev, "%s: read %x %x", __func__, bmsr, bmcr);
//pr_debug("%s: read %x %x", __func__, bmsr, bmcr);
if (!mii_link_ok(&ep->mii)) {
/* No link, currently */
......@@ -131,7 +132,7 @@ int wrn_ep_open(struct net_device *dev)
writel(0
| EP_RFCR_QMODE_W(0x3) /* unqualified port */
| EP_RFCR_PRIO_VAL_W(4), /* some mid priority */
ep->ep_regs->RFCR);
&ep->ep_regs->RFCR);
writel(0, &ep->ep_regs->TSCR); /* no stamps */
writel(0
......@@ -139,7 +140,7 @@ int wrn_ep_open(struct net_device *dev)
| EP_ECR_RST_CNT
| EP_ECR_TX_EN_FRA
| EP_ECR_RX_EN_FRA,
ep->ep_regs->ECR);
&ep->ep_regs->ECR);
/* Prepare the timer for link-up notifications */
setup_timer(&ep->ep_link_timer, wrn_ep_check_link, timerarg);
......@@ -151,6 +152,7 @@ int wrn_ep_close(struct net_device *dev)
{
struct wrn_ep *ep = netdev_priv(dev);
writel(0, &ep->ep_regs->ECR);
del_timer_sync(&ep->ep_link_timer);
return 0;
}
......@@ -164,7 +166,7 @@ int wrn_ep_close(struct net_device *dev)
static void __wrn_endpoint_shutdown(struct wrn_ep *ep)
{
/* Not much to do it seems */
writel(0, ep->ep_regs->ECR); /* disable it all */
writel(0, &ep->ep_regs->ECR); /* disable it all */
}
int wrn_endpoint_probe(struct net_device *dev)
......@@ -182,7 +184,7 @@ int wrn_endpoint_probe(struct net_device *dev)
dev_alloc_name(dev, "wrd%d");
/* Check whether the ep has been sinthetized or not */
val = readl(ep->ep_regs->IDCODE);
val = readl(&ep->ep_regs->IDCODE);
if (val != WRN_EP_MAGIC) {
pr_info(DRV_NAME "EP%i (%s) has not been sintethized\n",
ep->ep_number, dev->name);
......
......@@ -70,7 +70,7 @@ int __init wrn_init(void)
platform_device_register(&wrn_device);
platform_driver_register(&wrn_driver);
return -EAGAIN;
return 0;
}
void __exit wrn_exit(void)
......
......@@ -19,6 +19,7 @@
#include <asm/unaligned.h>
#include "wr-nic.h"
#include "nic-mem.h"
/*
* The following functions are the standard network device operations.
......@@ -30,7 +31,7 @@ static int wrn_open(struct net_device *dev)
struct wrn_ep *ep = netdev_priv(dev);
/* This is "open" just for an endpoint. The nic hw is already on */
netdev_dbg(dev, "%s\n", __func__);
//netdev_dbg(dev, "%s\n", __func__);
if (!is_valid_ether_addr(dev->dev_addr))
return -EADDRNOTAVAIL;
......@@ -71,44 +72,71 @@ static int wrn_set_mac_address(struct net_device *dev, void* vaddr)
struct sockaddr *addr = vaddr;
u32 val;
netdev_dbg(dev, "%s\n", __func__);
//netdev_dbg(dev, "%s\n", __func__);
if (!is_valid_ether_addr(addr->sa_data)) {
netdev_dbg(dev, "%s: invalid\n", __func__);
//netdev_dbg(dev, "%s: invalid\n", __func__);
return -EADDRNOTAVAIL;
}
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
val = __get_unaligned_le((u32 *)dev->dev_addr+0);
writel(val, ep->ep_regs->MACL);
val = __get_unaligned_le((u16 *)dev->dev_addr+4);
writel(val, ep->ep_regs->MACH);
/* MACH gets the first two bytes, MACL the rest */
val = get_unaligned_be16(dev->dev_addr);
writel(val, &ep->ep_regs->MACH);
val = get_unaligned_be32(dev->dev_addr+2);
writel(val, &ep->ep_regs->MACL);
return 0;
}
/* Next descriptor */
static int __wrn_next_desc(int i)
{
return (i+1) % WRN_NR_DESC;
}
/* This is called with the lock taken */
static int __wrn_alloc_tx_desc(struct wrn_dev *wrn)
{
int ret, i = 0;
do {
/* First increment the position */
wrn->next_txdesc++;
if (unlikely(wrn->next_txdesc >= WRN_NR_TXDESC))
wrn->next_txdesc = 0;
/* then check if it's available */
ret = test_and_set_bit(wrn->next_txdesc, &wrn->tx_mask);
if (!ret)
return wrn->next_txdesc;
} while (++i < WRN_NR_TXDESC);
return -ENOMEM;
int ret = wrn->next_tx_head;
struct wrn_txd __iomem *tx;
tx = wrn->txd + ret;
/* Check if it's available */
if (readl(&tx->tx1) & NIC_TX1_D1_READY) {
pr_debug("%s: not free %i\n", __func__, ret);
return -ENOMEM;
}
wrn->next_tx_head = __wrn_next_desc(ret);
return ret;
}
static void __wrn_tx_desc(struct wrn_dev *wrn, int desc,
void *data, int len)
/* Actual transmission over a single endpoint */
static void __wrn_tx_desc(struct wrn_ep *ep, int desc,
void *data, int len, int id)
{
/* FIXME: tx desc */
struct wrn_dev *wrn = ep->wrn;
int offset = __wrn_desc_offset(wrn, WRN_DDIR_TX, desc);
u32 *ptr = __wrn_desc_mem(wrn, WRN_DDIR_TX, desc);
struct wrn_txd __iomem *tx = wrn->txd + desc;
/* data */
printk("%s: %i -- data %p, len %i ", __func__, __LINE__,
data, len);
printk("-- desc %i (tx %p)\n", desc, tx);
__wrn_copy_out(ptr, data, len);
/* TX register 3: mask of endpoints (FIXME: broadcast) */
writel(ep->ep_number, &tx->tx3);
/* TX register 2: ofset and length */
writel(offset | (len << 16), &tx->tx2);
/* TX register 1: id and masks */
writel(NIC_TX1_D1_PAD_E | NIC_TX1_D1_READY | (id << 16),
&tx->tx1);
}
......@@ -116,10 +144,10 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct wrn_ep *ep = netdev_priv(dev);
struct wrn_dev *wrn = ep->wrn;
union skb_shared_tx *shtx = skb_tx(skb);
//union skb_shared_tx *shtx = skb_tx(skb);
unsigned long flags;
int desc;
u16 tx_oob = 0;
int id;
void *data;
unsigned len;
......@@ -129,22 +157,25 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
return -EMSGSIZE;
}
/* Allocate a descriptor (start from last allocated) */
/* Allocate a descriptor and id (start from last allocated) */
spin_lock_irqsave(&wrn->lock, flags);
desc = __wrn_alloc_tx_desc(wrn);
id = wrn->id++;
spin_unlock_irqrestore(&wrn->lock, flags);
if (desc < 0) /* error */
return desc;
data = skb->data;
len = skb->len;
spin_lock_irqsave(&ep->lock, flags);
//spin_lock_irqsave(&ep->lock, flags);
wrn->skb_desc[desc] = skb; /* Save for tx irq and stamping */
netif_stop_queue(dev); /* Queue is stopped until tx is over */
//netif_stop_queue(dev); /* Queue stopped until tx is over (FIXME?) */
if(test_bit(WRN_EP_STAMPING_TX, &ep->ep_flags)) {
/* FIXME: the hw tx stamping */
#if 0
#if 0 /* FIXME: the hw tx stamping */
struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb);
shtx->in_progress = 1;
*(u16 *) hwts = tx_oob = nic->tx_hwtstamp_oob;
......@@ -152,20 +183,23 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
nic->tx_hwtstamp_oob ++;
if(nic->tx_hwtstamp_oob == 60000)
nic->tx_hwtstamp_oob = 1;
} else {
tx_oob = 0;
#endif
}
/* Mark the owner of this descriptor */
wrn->skb_desc[desc] = skb;
/* This both copies the data to the descriptr and fires tx */
__wrn_tx_desc(wrn, desc, data, len);
printk("%s: %i\n", __func__, __LINE__);
__wrn_tx_desc(ep, desc, data, len, id);
printk("%s: %i\n", __func__, __LINE__);
/* We are done, this is trivial maiintainance*/
ep->stats.tx_packets++;
ep->stats.tx_bytes += len;
dev->trans_start = jiffies;
spin_unlock_irqrestore(&ep->lock, flags);
//spin_unlock_irqrestore(&ep->lock, flags);
return 0;
}
......@@ -221,10 +255,113 @@ int wrn_netops_init(struct net_device *dev)
return 0;
}
irqreturn_t wrn_interrupt(int irq, void *dev_id)
/*
* From this onwards, it's all about interrupt management
*/
static void __wrn_rx_descriptor(struct wrn_dev *wrn, int desc)
{
/* FIXME -- interrupt */
struct net_device *dev;
struct wrn_endpoint *ep;
struct sk_buff *skb;
struct wrn_rxd __iomem *rx;
u32 r1, r2, r3;
int epnum, off, len;
rx = wrn->rxd + desc;
r1 = readl(&rx->rx1);
r2 = readl(&rx->rx2);
r3 = readl(&rx->rx3);
pr_debug("%s: %i: %08x %08x %08x\n", __func__, desc, r1, r2, r3);
/* So, this descriptor is not empty. Get the port (ep) */
epnum = NIC_RX1_D1_PORT_R(r1);
dev = wrn->dev[epnum];
ep = netdev_priv(dev);
/* FIXME: rx timestamp */
/* Data and length */
off = NIC_RX1_D3_OFFSET_R(r3);
len = NIC_RX1_D3_LEN_R(r3);
skb = netdev_alloc_skb(dev, len + 16 /* FIXME: real size for rx */);
/* FIXME: handle allocation failure */
skb_reserve(skb, 2);
__wrn_copy_in(skb_put(skb, len), wrn->databuf + off, len);
writel(NIC_RX1_D1_EMPTY, &rx->rx1);
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_UNNECESSARY;
/* FIXME: these stats don't go to the right place */
dev->last_rx = jiffies;
dev->stats.rx_packets++;
dev->stats.rx_bytes += len;
printk("%i\n", __LINE__);
netif_receive_skb(skb);
}
/* FIXME: check status register (BNA, REC) */
static void wrn_rx_interrupt(struct wrn_dev *wrn)
{
int desc;
struct wrn_rxd __iomem *rx;
u32 reg;
while (1) {
desc = wrn->next_rx;
rx = wrn->rxd + desc;
reg = readl(&rx->rx1);
if (reg & NIC_RX1_D1_EMPTY)
return;
__wrn_rx_descriptor(wrn, desc);
wrn->next_rx = __wrn_next_desc(desc);
}
}
static void wrn_tx_interrupt(struct wrn_dev *wrn)
{
struct wrn_txd *tx;
struct sk_buff *skb;
u32 reg;
int i;
/* Loop using our talil until one is not sent */
while ( (i = wrn->next_tx_tail) != wrn->next_tx_head) {
/* Check if this is txdone */
tx = wrn->txd + i;
reg = readl(&tx->tx1);
if (reg & NIC_TX1_D1_READY)
return; /* no more */
skb = wrn->skb_desc[i];
/* FIXME: get the stamp from the fifo */
dev_kfree_skb_irq(skb);
wrn->skb_desc[i] = 0;
wrn->next_tx_tail = __wrn_next_desc(i);
}
}
irqreturn_t wrn_interrupt(int irq, void *dev_id)
{
struct wrn_dev *wrn = dev_id;
struct NIC_WB *regs = wrn->regs;
u32 i, irqs;
irqs = readl((void *)regs + 0x2c /*EIC_ISR */);
i = readl(&regs->SR);
pr_debug("%s: irqs 0x%x, sr 0x%x\n", __func__, irqs, i);
if (irqs & NIC_EIC_ISR_TXERR) {
pr_err("%s: TX error\n", __func__); /* FIXME */
writel(NIC_EIC_ISR_TXERR, (void *)regs + 0x2c);
}
if (irqs & NIC_EIC_ISR_TCOMP) {
pr_debug("%s: TX complete\n", __func__);
wrn_tx_interrupt(wrn);
writel(NIC_EIC_ISR_TCOMP, (void *)regs + 0x2c);
}
if (irqs & NIC_EIC_ISR_RCOMP) {
pr_debug("%s: RX complete\n", __func__);
wrn_rx_interrupt(wrn);
writel(NIC_EIC_ISR_RCOMP, (void *)regs + 0x2c);
}
return IRQ_HANDLED;
}
/*
* hardware-specific definitions for the White Rabbit NIC
*
* Copyright (C) 2010 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __WR_NIC_HARDWARE_H__
#define __WR_NIC_HARDWARE_H__
......@@ -5,8 +15,12 @@
#include <mach/at91sam9263.h>
/* The interrupt is one of those managed by our WRVIC device */
#define WRN_IRQ_MAIN 192 /* First vic-managed irq */
#define WRN_IRQ_TSTAMP 193 /* FIXME: interrupt numbers */
#define WRN_IRQ_BASE 192
#define WRN_IRQ_PPSG (WRN_IRQ_BASE + 0)
#define WRN_IRQ_NIC (WRN_IRQ_BASE + 1)
#define WRN_IRQ_RTU (WRN_IRQ_BASE + 2)
#define WRN_IRQ_RTUT (WRN_IRQ_BASE + 3)
#define WRN_IRQ_TSTAMP (WRN_IRQ_BASE + 4)
/* This is the base address of all the FPGA regions (EBI1, CS0) */
#define FPGA_BASE_ADDRESS 0x70000000
......@@ -54,7 +68,9 @@ enum fpga_blocks {
#define __FPGA_BASE_TO_NR(add) (((add) - FPGA_BASE_ADDRESS) / FPGA_BLOCK_SIZE)
/* 8 tx and 8 rx descriptors */
#define WRN_NR_DESC 8
#define WRN_NR_DESC 8
#define WRN_NR_TXDESC WRN_NR_DESC
#define WRN_NR_RXDESC WRN_NR_DESC
/* Magic number for endpoint */
#define WRN_EP_MAGIC 0xcafebabe
......@@ -69,29 +85,27 @@ enum fpga_blocks {
#include "../wbgen-regs/nic-regs.h"
#include "../wbgen-regs/tstamp-regs.h"
/* To make thins easier, define the descriptor structures, for tx and rx */
struct wrn_desc_tx {
/*
* To make thins easier, define the descriptor structures, for tx and rx
* Use functions in nic-mem.h to get pointes to them
*/
struct wrn_txd {
uint32_t tx1;
uint32_t tx2;
uint32_t tx3;
uint32_t unused;
};
struct wrn_desc_rx {
struct wrn_rxd {
uint32_t rx1;
uint32_t rx2;
uint32_t rx3;
uint32_t unused;
};
/* Some macros to extract fields from descriptors -- FIXME*/
/* Some more constants */
#define WRN_MTU 1540
/* The number of descriptors is used to look in wrn bitmasks (max is 32) */
#define WRN_NR_TXDESC 8
#define WRN_NR_RXDESC 8
#define WRN_DDATA_OFFSET 2 /* data in descriptors is offset by that much */
#endif /* __WR_NIC_HARDWARE_H__ */
/*
* This file hosts memory-specific inlines, separated for easier review
*
* Copyright (C) 2010 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "wr-nic.h"
#include <asm/unaligned.h>
/* Descriptor direction, used to locate descriptror data memory */
enum wrn_ddir {
WRN_DDIR_RX,
WRN_DDIR_TX
};
/* We place the descriptor memory in fixed positions (2kB each) */
static inline int __wrn_desc_offset(struct wrn_dev *wrn,
enum wrn_ddir dir, int nr)
{
if (dir == WRN_DDIR_RX) nr += WRN_NR_TXDESC;
return 0x800 * nr;
}
static inline u32 __iomem *__wrn_desc_mem(struct wrn_dev *wrn,
enum wrn_ddir dir, int nr)
{
/* note: this is a void pointer, but then we return a u32 ptr */
void __iomem *ptr = wrn->databuf;
return ptr + __wrn_desc_offset(wrn, dir, nr);
}
/* The two copy functions take arguments in the same order as memcpy */
static inline void __wrn_copy_out(u32 __iomem *to, void *from, int size)
{
u32 i;
from -= WRN_DDATA_OFFSET;
while (size > 0) {
i = get_unaligned_le32(from);
writel(i, to);
to++; from += sizeof(i);
size -= sizeof(i);
}
}
static inline void __wrn_copy_in(void *to, u32 __iomem *from, int size)
{
u32 i;
to -= WRN_DDATA_OFFSET;
printk("%s: %i %p <= %p %i\n", __func__, __LINE__, to, from, size);
while (size > 0) {
i = readl(from);
put_unaligned_le32(i, to);
to += sizeof(i); from++;
size -= sizeof(i);
}
}
......@@ -30,7 +30,7 @@ int wrn_tstamp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (copy_from_user(&config, rq->ifr_data, sizeof(config)))
return -EFAULT;
netdev_dbg(dev, "%s: tx type %i, rx filter %i\n", __func__,
if (0) netdev_dbg(dev, "%s: tx type %i, rx filter %i\n", __func__,
config.tx_type, config.rx_filter);
switch (config.tx_type) {
......
......@@ -25,13 +25,24 @@
/*
* Interrupt information should be hidden in resource lists,
* but the looping code would be hairy). So let's define three
* but the looping code would be hairy. So let's define three
* arrays of the same size, and code loops over these
*/
#define WRN_IRQ_NUMBERS {WRN_IRQ_MAIN, WRN_IRQ_TSTAMP}
#define WRN_IRQ_NAMES {"wr-nic", "wr-tstamp"}
#define WRN_IRQ_HANDLERS {wrn_interrupt, wrn_tstamp_interrupt}
#if 0
#define WRN_IRQ_NUMBERS \
{WRN_IRQ_PPSG, WRN_IRQ_NIC, WRN_IRQ_RTU, WRN_IRQ_RTUT, WRN_IRQ_TSTAMP}
#define WRN_IRQ_NAMES \
{"wr-ppsg", "wr-nic", "wr-rtu", "wr-rtut", "wr-tstamp"}
#define WRN_IRQ_HANDLERS \
{NULL, wrn_interrupt, NULL, NULL, wrn_tstamp_interrupt}
#endif
/* Temporarily, one handler only */
#define WRN_IRQ_NUMBERS {WRN_IRQ_NIC}
#define WRN_IRQ_NAMES {"wr-nic"}
#define WRN_IRQ_HANDLERS {wrn_interrupt}
struct wrn_ep; /* Defined later */
/*
* This is the main data structure for our NIC device. As for locking,
* the rule is that _either_ the wrn _or_ the endpoint is locked. Not both.
......@@ -42,16 +53,17 @@ struct wrn_dev {
struct NIC_WB __iomem *regs; /* shorthand for NIC-block registers */
spinlock_t lock;
struct wrn_d_tx __iomem *txd;
unsigned long tx_mask; /* descriptors in use */
struct wrn_d_rx __iomem *rxd;
unsigned long rx_mask; /* descriptors in use */
int next_txdesc;
struct wrn_txd __iomem *txd;
struct wrn_rxd __iomem *rxd;
void __iomem *databuf; /* void to ease pointer arith */
int next_tx_head, next_tx_tail;
int next_rx;
/* For TX descriptors, we must keep track of the ownwes */
/* For TX descriptors, we must keep track of the ownwer */
struct sk_buff *skb_desc[WRN_NR_TXDESC];
int id;
struct net_device *dev[WRN_NR_ENDPOINTS]; /* FIXME: unused */
struct net_device *dev[WRN_NR_ENDPOINTS];
/* FIXME: all dev fields must be verified */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment