Commit 8ac6e2a3 authored by David S. Miller's avatar David S. Miller

Merge branch 'arcnet-features'

Michael Grzeschik says:

====================
arcnet: Collection of latest features

Here we sum up the latest features to improve the arcnet framework. One
patch is used to get feedback from the transfer queue about failed xfers
by adding the err_skb message queue. Beside that we improve the
backplane status that can be read by the PCI-based cards and offer that
status via an extra sysfs attribute. In the last patch we add another
card type PCIFB2.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 65344ba9 a356ab1c
...@@ -269,6 +269,10 @@ struct arcnet_local { ...@@ -269,6 +269,10 @@ struct arcnet_local {
struct timer_list timer; struct timer_list timer;
struct net_device *dev;
int reply_status;
struct tasklet_struct reply_tasklet;
/* /*
* Buffer management: an ARCnet card has 4 x 512-byte buffers, each of * Buffer management: an ARCnet card has 4 x 512-byte buffers, each of
* which can be used for either sending or receiving. The new dynamic * which can be used for either sending or receiving. The new dynamic
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#include <net/arp.h> #include <net/arp.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/errqueue.h>
#include <linux/leds.h> #include <linux/leds.h>
...@@ -391,6 +392,52 @@ static void arcnet_timer(unsigned long data) ...@@ -391,6 +392,52 @@ static void arcnet_timer(unsigned long data)
} }
} }
static void arcnet_reply_tasklet(unsigned long data)
{
struct arcnet_local *lp = (struct arcnet_local *)data;
struct sk_buff *ackskb, *skb;
struct sock_exterr_skb *serr;
struct sock *sk;
int ret;
local_irq_disable();
skb = lp->outgoing.skb;
if (!skb || !skb->sk) {
local_irq_enable();
return;
}
sock_hold(skb->sk);
sk = skb->sk;
ackskb = skb_clone_sk(skb);
sock_put(skb->sk);
if (!ackskb) {
local_irq_enable();
return;
}
serr = SKB_EXT_ERR(ackskb);
memset(serr, 0, sizeof(*serr));
serr->ee.ee_errno = ENOMSG;
serr->ee.ee_origin = SO_EE_ORIGIN_TXSTATUS;
serr->ee.ee_data = skb_shinfo(skb)->tskey;
serr->ee.ee_info = lp->reply_status;
/* finally erasing outgoing skb */
dev_kfree_skb(lp->outgoing.skb);
lp->outgoing.skb = NULL;
ackskb->dev = lp->dev;
ret = sock_queue_err_skb(sk, ackskb);
if (ret)
kfree_skb(ackskb);
local_irq_enable();
};
struct net_device *alloc_arcdev(const char *name) struct net_device *alloc_arcdev(const char *name)
{ {
struct net_device *dev; struct net_device *dev;
...@@ -401,6 +448,7 @@ struct net_device *alloc_arcdev(const char *name) ...@@ -401,6 +448,7 @@ struct net_device *alloc_arcdev(const char *name)
if (dev) { if (dev) {
struct arcnet_local *lp = netdev_priv(dev); struct arcnet_local *lp = netdev_priv(dev);
lp->dev = dev;
spin_lock_init(&lp->lock); spin_lock_init(&lp->lock);
init_timer(&lp->timer); init_timer(&lp->timer);
lp->timer.data = (unsigned long) dev; lp->timer.data = (unsigned long) dev;
...@@ -436,6 +484,9 @@ int arcnet_open(struct net_device *dev) ...@@ -436,6 +484,9 @@ int arcnet_open(struct net_device *dev)
arc_cont(D_PROTO, "\n"); arc_cont(D_PROTO, "\n");
} }
tasklet_init(&lp->reply_tasklet, arcnet_reply_tasklet,
(unsigned long)lp);
arc_printk(D_INIT, dev, "arcnet_open: resetting card.\n"); arc_printk(D_INIT, dev, "arcnet_open: resetting card.\n");
/* try to put the card in a defined state - if it fails the first /* try to put the card in a defined state - if it fails the first
...@@ -527,6 +578,8 @@ int arcnet_close(struct net_device *dev) ...@@ -527,6 +578,8 @@ int arcnet_close(struct net_device *dev)
netif_stop_queue(dev); netif_stop_queue(dev);
netif_carrier_off(dev); netif_carrier_off(dev);
tasklet_kill(&lp->reply_tasklet);
/* flush TX and disable RX */ /* flush TX and disable RX */
lp->hw.intmask(dev, 0); lp->hw.intmask(dev, 0);
lp->hw.command(dev, NOTXcmd); /* stop transmit */ lp->hw.command(dev, NOTXcmd); /* stop transmit */
...@@ -635,13 +688,13 @@ netdev_tx_t arcnet_send_packet(struct sk_buff *skb, ...@@ -635,13 +688,13 @@ netdev_tx_t arcnet_send_packet(struct sk_buff *skb,
txbuf = -1; txbuf = -1;
if (txbuf != -1) { if (txbuf != -1) {
lp->outgoing.skb = skb;
if (proto->prepare_tx(dev, pkt, skb->len, txbuf) && if (proto->prepare_tx(dev, pkt, skb->len, txbuf) &&
!proto->ack_tx) { !proto->ack_tx) {
/* done right away and we don't want to acknowledge /* done right away and we don't want to acknowledge
* the package later - forget about it now * the package later - forget about it now
*/ */
dev->stats.tx_bytes += skb->len; dev->stats.tx_bytes += skb->len;
dev_kfree_skb(skb);
} else { } else {
/* do it the 'split' way */ /* do it the 'split' way */
lp->outgoing.proto = proto; lp->outgoing.proto = proto;
...@@ -842,8 +895,16 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) ...@@ -842,8 +895,16 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id)
/* a transmit finished, and we're interested in it. */ /* a transmit finished, and we're interested in it. */
if ((status & lp->intmask & TXFREEflag) || lp->timed_out) { if ((status & lp->intmask & TXFREEflag) || lp->timed_out) {
int ackstatus;
lp->intmask &= ~(TXFREEflag | EXCNAKflag); lp->intmask &= ~(TXFREEflag | EXCNAKflag);
if (status & TXACKflag)
ackstatus = 2;
else if (lp->excnak_pending)
ackstatus = 1;
else
ackstatus = 0;
arc_printk(D_DURING, dev, "TX IRQ (stat=%Xh)\n", arc_printk(D_DURING, dev, "TX IRQ (stat=%Xh)\n",
status); status);
...@@ -866,18 +927,11 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) ...@@ -866,18 +927,11 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id)
if (lp->outgoing.proto && if (lp->outgoing.proto &&
lp->outgoing.proto->ack_tx) { lp->outgoing.proto->ack_tx) {
int ackstatus;
if (status & TXACKflag)
ackstatus = 2;
else if (lp->excnak_pending)
ackstatus = 1;
else
ackstatus = 0;
lp->outgoing.proto lp->outgoing.proto
->ack_tx(dev, ackstatus); ->ack_tx(dev, ackstatus);
} }
lp->reply_status = ackstatus;
tasklet_hi_schedule(&lp->reply_tasklet);
} }
if (lp->cur_tx != -1) if (lp->cur_tx != -1)
release_arcbuf(dev, lp->cur_tx); release_arcbuf(dev, lp->cur_tx);
......
...@@ -93,6 +93,27 @@ static void led_recon_set(struct led_classdev *led_cdev, ...@@ -93,6 +93,27 @@ static void led_recon_set(struct led_classdev *led_cdev,
outb(!!value, priv->misc + ci->leds[card->index].red); outb(!!value, priv->misc + ci->leds[card->index].red);
} }
static ssize_t backplane_mode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct net_device *net_dev = to_net_dev(dev);
struct arcnet_local *lp = netdev_priv(net_dev);
return sprintf(buf, "%s\n", lp->backplane ? "true" : "false");
}
static DEVICE_ATTR_RO(backplane_mode);
static struct attribute *com20020_state_attrs[] = {
&dev_attr_backplane_mode.attr,
NULL,
};
static struct attribute_group com20020_state_group = {
.name = NULL,
.attrs = com20020_state_attrs,
};
static void com20020pci_remove(struct pci_dev *pdev); static void com20020pci_remove(struct pci_dev *pdev);
static int com20020pci_probe(struct pci_dev *pdev, static int com20020pci_probe(struct pci_dev *pdev,
...@@ -168,6 +189,7 @@ static int com20020pci_probe(struct pci_dev *pdev, ...@@ -168,6 +189,7 @@ static int com20020pci_probe(struct pci_dev *pdev,
dev->base_addr = ioaddr; dev->base_addr = ioaddr;
dev->dev_addr[0] = node; dev->dev_addr[0] = node;
dev->sysfs_groups[0] = &com20020_state_group;
dev->irq = pdev->irq; dev->irq = pdev->irq;
lp->card_name = "PCI COM20020"; lp->card_name = "PCI COM20020";
lp->card_flags = ci->flags; lp->card_flags = ci->flags;
...@@ -177,6 +199,11 @@ static int com20020pci_probe(struct pci_dev *pdev, ...@@ -177,6 +199,11 @@ static int com20020pci_probe(struct pci_dev *pdev,
lp->timeout = timeout; lp->timeout = timeout;
lp->hw.owner = THIS_MODULE; lp->hw.owner = THIS_MODULE;
lp->backplane = (inb(priv->misc) >> (2 + i)) & 0x1;
if (!strncmp(ci->name, "EAE PLX-PCI FB2", 15))
lp->backplane = 1;
/* Get the dev_id from the PLX rotary coder */ /* Get the dev_id from the PLX rotary coder */
if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15)) if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15))
dev->dev_id = 0xc; dev->dev_id = 0xc;
...@@ -361,6 +388,31 @@ static struct com20020_pci_card_info card_info_eae_ma1 = { ...@@ -361,6 +388,31 @@ static struct com20020_pci_card_info card_info_eae_ma1 = {
.flags = ARC_CAN_10MBIT, .flags = ARC_CAN_10MBIT,
}; };
static struct com20020_pci_card_info card_info_eae_fb2 = {
.name = "EAE PLX-PCI FB2",
.devcount = 1,
.chan_map_tbl = {
{
.bar = 2,
.offset = 0x00,
.size = 0x08,
},
},
.misc_map = {
.bar = 2,
.offset = 0x10,
.size = 0x04,
},
.leds = {
{
.green = 0x0,
.red = 0x1,
},
},
.rotary = 0x0,
.flags = ARC_CAN_10MBIT,
};
static const struct pci_device_id com20020pci_id_table[] = { static const struct pci_device_id com20020pci_id_table[] = {
{ {
0x1571, 0xa001, 0x1571, 0xa001,
...@@ -506,6 +558,12 @@ static const struct pci_device_id com20020pci_id_table[] = { ...@@ -506,6 +558,12 @@ static const struct pci_device_id com20020pci_id_table[] = {
0, 0, 0, 0,
(kernel_ulong_t)&card_info_eae_ma1 (kernel_ulong_t)&card_info_eae_ma1
}, },
{
0x10B5, 0x9050,
0x10B5, 0x3294,
0, 0,
(kernel_ulong_t)&card_info_eae_fb2
},
{ {
0x14BA, 0x6000, 0x14BA, 0x6000,
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
......
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