diff options
Diffstat (limited to 'drivers/net/ethernet/sun')
-rw-r--r-- | drivers/net/ethernet/sun/cassini.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/sun/niu.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/sun/sungem.c | 34 | ||||
-rw-r--r-- | drivers/net/ethernet/sun/sunvnet.c | 75 | ||||
-rw-r--r-- | drivers/net/ethernet/sun/sunvnet.h | 4 |
5 files changed, 93 insertions, 26 deletions
diff --git a/drivers/net/ethernet/sun/cassini.c b/drivers/net/ethernet/sun/cassini.c index 37f87ff28f03..02d370e58110 100644 --- a/drivers/net/ethernet/sun/cassini.c +++ b/drivers/net/ethernet/sun/cassini.c @@ -4962,7 +4962,7 @@ static int cas_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_cmd |= PCI_COMMAND_PARITY; pci_write_config_word(pdev, PCI_COMMAND, pci_cmd); if (pci_try_set_mwi(pdev)) - pr_warning("Could not enable MWI for %s\n", pci_name(pdev)); + pr_warn("Could not enable MWI for %s\n", pci_name(pdev)); cas_program_bridge(pdev); diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c index 8216be46540f..904fd1ab5f6e 100644 --- a/drivers/net/ethernet/sun/niu.c +++ b/drivers/net/ethernet/sun/niu.c @@ -8717,8 +8717,8 @@ static void niu_divide_channels(struct niu_parent *parent, parent->txchan_per_port[i] = 1; } if (tot_rx < NIU_NUM_RXCHAN || tot_tx < NIU_NUM_TXCHAN) { - pr_warning("niu%d: Driver bug, wasted channels, RX[%d] TX[%d]\n", - parent->index, tot_rx, tot_tx); + pr_warn("niu%d: Driver bug, wasted channels, RX[%d] TX[%d]\n", + parent->index, tot_rx, tot_tx); } } diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c index f7415b6bf141..fef5dec2cffe 100644 --- a/drivers/net/ethernet/sun/sungem.c +++ b/drivers/net/ethernet/sun/sungem.c @@ -115,7 +115,7 @@ static const struct pci_device_id gem_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, gem_pci_tbl); -static u16 __phy_read(struct gem *gp, int phy_addr, int reg) +static u16 __sungem_phy_read(struct gem *gp, int phy_addr, int reg) { u32 cmd; int limit = 10000; @@ -141,18 +141,18 @@ static u16 __phy_read(struct gem *gp, int phy_addr, int reg) return cmd & MIF_FRAME_DATA; } -static inline int _phy_read(struct net_device *dev, int mii_id, int reg) +static inline int _sungem_phy_read(struct net_device *dev, int mii_id, int reg) { struct gem *gp = netdev_priv(dev); - return __phy_read(gp, mii_id, reg); + return __sungem_phy_read(gp, mii_id, reg); } -static inline u16 phy_read(struct gem *gp, int reg) +static inline u16 sungem_phy_read(struct gem *gp, int reg) { - return __phy_read(gp, gp->mii_phy_addr, reg); + return __sungem_phy_read(gp, gp->mii_phy_addr, reg); } -static void __phy_write(struct gem *gp, int phy_addr, int reg, u16 val) +static void __sungem_phy_write(struct gem *gp, int phy_addr, int reg, u16 val) { u32 cmd; int limit = 10000; @@ -174,15 +174,15 @@ static void __phy_write(struct gem *gp, int phy_addr, int reg, u16 val) } } -static inline void _phy_write(struct net_device *dev, int mii_id, int reg, int val) +static inline void _sungem_phy_write(struct net_device *dev, int mii_id, int reg, int val) { struct gem *gp = netdev_priv(dev); - __phy_write(gp, mii_id, reg, val & 0xffff); + __sungem_phy_write(gp, mii_id, reg, val & 0xffff); } -static inline void phy_write(struct gem *gp, int reg, u16 val) +static inline void sungem_phy_write(struct gem *gp, int reg, u16 val) { - __phy_write(gp, gp->mii_phy_addr, reg, val); + __sungem_phy_write(gp, gp->mii_phy_addr, reg, val); } static inline void gem_enable_ints(struct gem *gp) @@ -1687,9 +1687,9 @@ static void gem_init_phy(struct gem *gp) /* Some PHYs used by apple have problem getting back to us, * we do an additional reset here */ - phy_write(gp, MII_BMCR, BMCR_RESET); + sungem_phy_write(gp, MII_BMCR, BMCR_RESET); msleep(20); - if (phy_read(gp, MII_BMCR) != 0xffff) + if (sungem_phy_read(gp, MII_BMCR) != 0xffff) break; if (i == 2) netdev_warn(gp->dev, "GMAC PHY not responding !\n"); @@ -2012,7 +2012,7 @@ static int gem_check_invariants(struct gem *gp) for (i = 0; i < 32; i++) { gp->mii_phy_addr = i; - if (phy_read(gp, MII_BMCR) != 0xffff) + if (sungem_phy_read(gp, MII_BMCR) != 0xffff) break; } if (i == 32) { @@ -2696,13 +2696,13 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* Fallthrough... */ case SIOCGMIIREG: /* Read MII PHY register. */ - data->val_out = __phy_read(gp, data->phy_id & 0x1f, + data->val_out = __sungem_phy_read(gp, data->phy_id & 0x1f, data->reg_num & 0x1f); rc = 0; break; case SIOCSMIIREG: /* Write MII PHY register. */ - __phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f, + __sungem_phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); rc = 0; break; @@ -2933,8 +2933,8 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* Fill up the mii_phy structure (even if we won't use it) */ gp->phy_mii.dev = dev; - gp->phy_mii.mdio_read = _phy_read; - gp->phy_mii.mdio_write = _phy_write; + gp->phy_mii.mdio_read = _sungem_phy_read; + gp->phy_mii.mdio_write = _sungem_phy_write; #ifdef CONFIG_PPC_PMAC gp->phy_mii.platform_data = gp->of_node; #endif diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index f67539650c38..edb860947da4 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -37,6 +37,8 @@ MODULE_VERSION(DRV_MODULE_VERSION); */ #define VNET_MAX_RETRIES 10 +static int __vnet_tx_trigger(struct vnet_port *port, u32 start); + /* Ordered from largest major to lowest */ static struct vio_version vnet_versions[] = { { .major = 1, .minor = 0 }, @@ -283,10 +285,18 @@ static int vnet_send_ack(struct vnet_port *port, struct vio_dring_state *dr, port->raddr[0], port->raddr[1], port->raddr[2], port->raddr[3], port->raddr[4], port->raddr[5]); - err = -ECONNRESET; + break; } } while (err == -EAGAIN); + if (err <= 0 && vio_dring_state == VIO_DRING_STOPPED) { + port->stop_rx_idx = end; + port->stop_rx = true; + } else { + port->stop_rx_idx = 0; + port->stop_rx = false; + } + return err; } @@ -451,7 +461,7 @@ static int vnet_ack(struct vnet_port *port, void *msgbuf) struct net_device *dev; struct vnet *vp; u32 end; - + struct vio_net_desc *desc; if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA)) return 0; @@ -459,7 +469,24 @@ static int vnet_ack(struct vnet_port *port, void *msgbuf) if (unlikely(!idx_is_pending(dr, end))) return 0; + /* sync for race conditions with vnet_start_xmit() and tell xmit it + * is time to send a trigger. + */ dr->cons = next_idx(end, dr); + desc = vio_dring_entry(dr, dr->cons); + if (desc->hdr.state == VIO_DESC_READY && port->start_cons) { + /* vnet_start_xmit() just populated this dring but missed + * sending the "start" LDC message to the consumer. + * Send a "start" trigger on its behalf. + */ + if (__vnet_tx_trigger(port, dr->cons) > 0) + port->start_cons = false; + else + port->start_cons = true; + } else { + port->start_cons = true; + } + vp = port->vp; dev = vp->dev; @@ -537,7 +564,7 @@ static void vnet_event(void *arg, int event) } if (unlikely(event != LDC_EVENT_DATA_READY)) { - pr_warning("Unexpected LDC event %d\n", event); + pr_warn("Unexpected LDC event %d\n", event); spin_unlock_irqrestore(&vio->lock, flags); return; } @@ -600,7 +627,7 @@ static void vnet_event(void *arg, int event) local_irq_restore(flags); } -static int __vnet_tx_trigger(struct vnet_port *port) +static int __vnet_tx_trigger(struct vnet_port *port, u32 start) { struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; struct vio_dring_data hdr = { @@ -611,12 +638,21 @@ static int __vnet_tx_trigger(struct vnet_port *port) .sid = vio_send_sid(&port->vio), }, .dring_ident = dr->ident, - .start_idx = dr->prod, + .start_idx = start, .end_idx = (u32) -1, }; int err, delay; int retries = 0; + if (port->stop_rx) { + err = vnet_send_ack(port, + &port->vio.drings[VIO_DRIVER_RX_RING], + port->stop_rx_idx, -1, + VIO_DRING_STOPPED); + if (err <= 0) + return err; + } + hdr.seq = dr->snd_nxt; delay = 1; do { @@ -737,7 +773,30 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) d->hdr.state = VIO_DESC_READY; - err = __vnet_tx_trigger(port); + /* Exactly one ldc "start" trigger (for dr->cons) needs to be sent + * to notify the consumer that some descriptors are READY. + * After that "start" trigger, no additional triggers are needed until + * a DRING_STOPPED is received from the consumer. The dr->cons field + * (set up by vnet_ack()) has the value of the next dring index + * that has not yet been ack-ed. We send a "start" trigger here + * if, and only if, start_cons is true (reset it afterward). Conversely, + * vnet_ack() should check if the dring corresponding to cons + * is marked READY, but start_cons was false. + * If so, vnet_ack() should send out the missed "start" trigger. + * + * Note that the wmb() above makes sure the cookies et al. are + * not globally visible before the VIO_DESC_READY, and that the + * stores are ordered correctly by the compiler. The consumer will + * not proceed until the VIO_DESC_READY is visible assuring that + * the consumer does not observe anything related to descriptors + * out of order. The HV trap from the LDC start trigger is the + * producer to consumer announcement that work is available to the + * consumer + */ + if (!port->start_cons) + goto ldc_start_done; /* previous trigger suffices */ + + err = __vnet_tx_trigger(port, dr->cons); if (unlikely(err < 0)) { netdev_info(dev, "TX trigger error %d\n", err); d->hdr.state = VIO_DESC_FREE; @@ -745,6 +804,9 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) goto out_dropped_unlock; } +ldc_start_done: + port->start_cons = false; + dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; @@ -1038,6 +1100,7 @@ static int vnet_port_alloc_tx_bufs(struct vnet_port *port) (sizeof(struct ldc_trans_cookie) * 2)); dr->num_entries = VNET_TX_RING_SIZE; dr->prod = dr->cons = 0; + port->start_cons = true; /* need an initial trigger */ dr->pending = VNET_TX_RING_SIZE; dr->ncookies = ncookies; diff --git a/drivers/net/ethernet/sun/sunvnet.h b/drivers/net/ethernet/sun/sunvnet.h index de5c2c64996f..da4933750d06 100644 --- a/drivers/net/ethernet/sun/sunvnet.h +++ b/drivers/net/ethernet/sun/sunvnet.h @@ -40,6 +40,10 @@ struct vnet_port { struct vnet_tx_entry tx_bufs[VNET_TX_RING_SIZE]; struct list_head list; + + u32 stop_rx_idx; + bool stop_rx; + bool start_cons; }; static inline struct vnet_port *to_vnet_port(struct vio_driver_state *vio) |