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: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2017-06-29 15:26:14 -04:00
commit 8ac6e2a3b8
3 changed files with 126 additions and 10 deletions

View File

@ -269,6 +269,10 @@ struct arcnet_local {
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
* which can be used for either sending or receiving. The new dynamic

View File

@ -51,6 +51,7 @@
#include <net/arp.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/errqueue.h>
#include <linux/leds.h>
@ -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 *dev;
@ -401,6 +448,7 @@ struct net_device *alloc_arcdev(const char *name)
if (dev) {
struct arcnet_local *lp = netdev_priv(dev);
lp->dev = dev;
spin_lock_init(&lp->lock);
init_timer(&lp->timer);
lp->timer.data = (unsigned long) dev;
@ -436,6 +484,9 @@ int arcnet_open(struct net_device *dev)
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");
/* 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)
netif_stop_queue(dev);
netif_carrier_off(dev);
tasklet_kill(&lp->reply_tasklet);
/* flush TX and disable RX */
lp->hw.intmask(dev, 0);
lp->hw.command(dev, NOTXcmd); /* stop transmit */
@ -635,13 +688,13 @@ netdev_tx_t arcnet_send_packet(struct sk_buff *skb,
txbuf = -1;
if (txbuf != -1) {
lp->outgoing.skb = skb;
if (proto->prepare_tx(dev, pkt, skb->len, txbuf) &&
!proto->ack_tx) {
/* done right away and we don't want to acknowledge
* the package later - forget about it now
*/
dev->stats.tx_bytes += skb->len;
dev_kfree_skb(skb);
} else {
/* do it the 'split' way */
lp->outgoing.proto = proto;
@ -842,8 +895,16 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id)
/* a transmit finished, and we're interested in it. */
if ((status & lp->intmask & TXFREEflag) || lp->timed_out) {
int ackstatus;
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",
status);
@ -866,18 +927,11 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id)
if (lp->outgoing.proto &&
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
->ack_tx(dev, ackstatus);
}
lp->reply_status = ackstatus;
tasklet_hi_schedule(&lp->reply_tasklet);
}
if (lp->cur_tx != -1)
release_arcbuf(dev, lp->cur_tx);

View File

@ -93,6 +93,27 @@ static void led_recon_set(struct led_classdev *led_cdev,
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 int com20020pci_probe(struct pci_dev *pdev,
@ -168,6 +189,7 @@ static int com20020pci_probe(struct pci_dev *pdev,
dev->base_addr = ioaddr;
dev->dev_addr[0] = node;
dev->sysfs_groups[0] = &com20020_state_group;
dev->irq = pdev->irq;
lp->card_name = "PCI COM20020";
lp->card_flags = ci->flags;
@ -177,6 +199,11 @@ static int com20020pci_probe(struct pci_dev *pdev,
lp->timeout = timeout;
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 */
if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15))
dev->dev_id = 0xc;
@ -361,6 +388,31 @@ static struct com20020_pci_card_info card_info_eae_ma1 = {
.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[] = {
{
0x1571, 0xa001,
@ -506,6 +558,12 @@ static const struct pci_device_id com20020pci_id_table[] = {
0, 0,
(kernel_ulong_t)&card_info_eae_ma1
},
{
0x10B5, 0x9050,
0x10B5, 0x3294,
0, 0,
(kernel_ulong_t)&card_info_eae_fb2
},
{
0x14BA, 0x6000,
PCI_ANY_ID, PCI_ANY_ID,