From 05fcd31cc472c5da6416d3bc2ab25599bbb9331f Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Wed, 28 Jun 2017 18:32:18 +0200 Subject: [PATCH 1/4] arcnet: add err_skb package for package status feedback We need to track the status of our queued packages. This way the driving process knows if failed packages need to be retransmitted. For this purpose we queue the transferred/failed packages back into the err_skb message queue added with some status information. Signed-off-by: Michael Grzeschik Signed-off-by: David S. Miller --- drivers/net/arcnet/arcdevice.h | 4 ++ drivers/net/arcnet/arcnet.c | 74 +++++++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/drivers/net/arcnet/arcdevice.h b/drivers/net/arcnet/arcdevice.h index 20bfb9ba83ea..cbb4f8566bbe 100644 --- a/drivers/net/arcnet/arcdevice.h +++ b/drivers/net/arcnet/arcdevice.h @@ -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 diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 62ee439d5882..d87f4da29f11 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -51,6 +51,7 @@ #include #include #include +#include #include @@ -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); From ede07a1fc7d70adfb290cfdace391295897023cb Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Wed, 28 Jun 2017 18:32:19 +0200 Subject: [PATCH 2/4] arcnet: com20020-pci: add attribute to readback backplane status We add the sysfs interface the read back the backplane status of the interface. Signed-off-by: Michael Grzeschik Signed-off-by: David S. Miller --- drivers/net/arcnet/com20020-pci.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 239de38fbd6a..dec300cac55f 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -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; From 52ab12e4f99437a046962e6486b0efded52846af Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Wed, 28 Jun 2017 18:32:20 +0200 Subject: [PATCH 3/4] arcnet: com20020-pci: handle backplane mode depending on card type We read the backplane mode of each subcard from bits 2 and 3 of the misc register. Signed-off-by: Michael Grzeschik Signed-off-by: David S. Miller --- drivers/net/arcnet/com20020-pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index dec300cac55f..f5854ab7dc32 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -199,6 +199,8 @@ static int com20020pci_probe(struct pci_dev *pdev, lp->timeout = timeout; lp->hw.owner = THIS_MODULE; + lp->backplane = (inb(priv->misc) >> (2 + i)) & 0x1; + /* Get the dev_id from the PLX rotary coder */ if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15)) dev->dev_id = 0xc; From a356ab1c3d46513067dddf9484c9f05e10279312 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Wed, 28 Jun 2017 18:32:21 +0200 Subject: [PATCH 4/4] arcnet: com20020-pci: add support for PCIFB2 card We add support for the PCIFB2 card from EAE. Beside other cards, this card has the backplane mode enabled by default. Signed-off-by: Michael Grzeschik Signed-off-by: David S. Miller --- drivers/net/arcnet/com20020-pci.c | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index f5854ab7dc32..24deb88a37f0 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -201,6 +201,9 @@ static int com20020pci_probe(struct pci_dev *pdev, 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; @@ -385,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, @@ -530,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,