From 3598b57be449a2ee9178e5c511bdb1a8aaccba20 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Sun, 29 Jan 2006 01:31:13 +0100 Subject: [PATCH 1/8] 8139cp: trim ring_info Fat removal: the mapping address is available from the Rx/Tx descriptors. Signed-off-by: Francois Romieu --- drivers/net/8139cp.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 1428bb7715af..8f5d77923c7d 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -316,7 +316,6 @@ struct cp_desc { struct ring_info { struct sk_buff *skb; - dma_addr_t mapping; u32 len; }; @@ -551,7 +550,7 @@ static int cp_rx_poll (struct net_device *dev, int *budget) break; len = (status & 0x1fff) - 4; - mapping = cp->rx_skb[rx_tail].mapping; + mapping = le64_to_cpu(desc->addr); if ((status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag)) { /* we don't support incoming fragmented frames. @@ -595,10 +594,8 @@ static int cp_rx_poll (struct net_device *dev, int *budget) skb_put(skb, len); - mapping = - cp->rx_skb[rx_tail].mapping = - pci_map_single(cp->pdev, new_skb->data, - buflen, PCI_DMA_FROMDEVICE); + mapping = pci_map_single(cp->pdev, new_skb->data, buflen, + PCI_DMA_FROMDEVICE); cp->rx_skb[rx_tail].skb = new_skb; cp_rx_skb(cp, skb, desc); @@ -717,18 +714,19 @@ static void cp_tx (struct cp_private *cp) unsigned tx_tail = cp->tx_tail; while (tx_tail != tx_head) { + struct cp_desc *txd = cp->tx_ring + tx_tail; struct sk_buff *skb; u32 status; rmb(); - status = le32_to_cpu(cp->tx_ring[tx_tail].opts1); + status = le32_to_cpu(txd->opts1); if (status & DescOwn) break; skb = cp->tx_skb[tx_tail].skb; BUG_ON(!skb); - pci_unmap_single(cp->pdev, cp->tx_skb[tx_tail].mapping, + pci_unmap_single(cp->pdev, le64_to_cpu(txd->addr), cp->tx_skb[tx_tail].len, PCI_DMA_TODEVICE); if (status & LastFrag) { @@ -827,7 +825,6 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) wmb(); cp->tx_skb[entry].skb = skb; - cp->tx_skb[entry].mapping = mapping; cp->tx_skb[entry].len = len; entry = NEXT_TX(entry); } else { @@ -845,7 +842,6 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) first_mapping = pci_map_single(cp->pdev, skb->data, first_len, PCI_DMA_TODEVICE); cp->tx_skb[entry].skb = skb; - cp->tx_skb[entry].mapping = first_mapping; cp->tx_skb[entry].len = first_len; entry = NEXT_TX(entry); @@ -888,7 +884,6 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) wmb(); cp->tx_skb[entry].skb = skb; - cp->tx_skb[entry].mapping = mapping; cp->tx_skb[entry].len = len; entry = NEXT_TX(entry); } @@ -1091,6 +1086,7 @@ static int cp_refill_rx (struct cp_private *cp) for (i = 0; i < CP_RX_RING_SIZE; i++) { struct sk_buff *skb; + dma_addr_t mapping; skb = dev_alloc_skb(cp->rx_buf_sz + RX_OFFSET); if (!skb) @@ -1099,12 +1095,12 @@ static int cp_refill_rx (struct cp_private *cp) skb->dev = cp->dev; skb_reserve(skb, RX_OFFSET); - cp->rx_skb[i].mapping = pci_map_single(cp->pdev, - skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE); + mapping = pci_map_single(cp->pdev, skb->data, cp->rx_buf_sz, + PCI_DMA_FROMDEVICE); cp->rx_skb[i].skb = skb; cp->rx_ring[i].opts2 = 0; - cp->rx_ring[i].addr = cpu_to_le64(cp->rx_skb[i].mapping); + cp->rx_ring[i].addr = cpu_to_le64(mapping); if (i == (CP_RX_RING_SIZE - 1)) cp->rx_ring[i].opts1 = cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz); @@ -1152,11 +1148,13 @@ static int cp_alloc_rings (struct cp_private *cp) static void cp_clean_rings (struct cp_private *cp) { + struct cp_desc *desc; unsigned i; for (i = 0; i < CP_RX_RING_SIZE; i++) { if (cp->rx_skb[i].skb) { - pci_unmap_single(cp->pdev, cp->rx_skb[i].mapping, + desc = cp->rx_ring + i; + pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr), cp->rx_buf_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb(cp->rx_skb[i].skb); } @@ -1166,9 +1164,10 @@ static void cp_clean_rings (struct cp_private *cp) if (cp->tx_skb[i].skb) { struct sk_buff *skb = cp->tx_skb[i].skb; - pci_unmap_single(cp->pdev, cp->tx_skb[i].mapping, + desc = cp->tx_ring + i; + pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr), cp->tx_skb[i].len, PCI_DMA_TODEVICE); - if (le32_to_cpu(cp->tx_ring[i].opts1) & LastFrag) + if (le32_to_cpu(desc->opts1) & LastFrag) dev_kfree_skb(skb); cp->net_stats.tx_dropped++; } From c48e9399e895834f26dff9149de1930ba18a0d6c Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Sun, 29 Jan 2006 01:30:48 +0100 Subject: [PATCH 2/8] 8139cp: remove gratuitous indirection dev is an argument of the current function. Signed-off-by: Francois Romieu --- drivers/net/8139cp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 8f5d77923c7d..ae9bb7511d90 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -571,7 +571,7 @@ static int cp_rx_poll (struct net_device *dev, int *budget) if (netif_msg_rx_status(cp)) printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d\n", - cp->dev->name, rx_tail, status, len); + dev->name, rx_tail, status, len); buflen = cp->rx_buf_sz + RX_OFFSET; new_skb = dev_alloc_skb (buflen); @@ -581,7 +581,7 @@ static int cp_rx_poll (struct net_device *dev, int *budget) } skb_reserve(new_skb, RX_OFFSET); - new_skb->dev = cp->dev; + new_skb->dev = dev; pci_unmap_single(cp->pdev, mapping, buflen, PCI_DMA_FROMDEVICE); From 0ba894d420b845667e2981c2147af974a755fba2 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Mon, 14 Aug 2006 19:55:07 +0200 Subject: [PATCH 3/8] 8139cp: ring_info removal for the receive path The ring_info.len field is not used at all. cp_private.rx_skb is turned into an array of sk_buff *. Signed-off-by: Francois Romieu --- drivers/net/8139cp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index ae9bb7511d90..072568120e48 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -354,7 +354,7 @@ struct cp_private { unsigned rx_tail ____cacheline_aligned; struct cp_desc *rx_ring; - struct ring_info rx_skb[CP_RX_RING_SIZE]; + struct sk_buff *rx_skb[CP_RX_RING_SIZE]; unsigned rx_buf_sz; unsigned tx_head ____cacheline_aligned; @@ -541,7 +541,7 @@ static int cp_rx_poll (struct net_device *dev, int *budget) struct cp_desc *desc; unsigned buflen; - skb = cp->rx_skb[rx_tail].skb; + skb = cp->rx_skb[rx_tail]; BUG_ON(!skb); desc = &cp->rx_ring[rx_tail]; @@ -596,7 +596,7 @@ static int cp_rx_poll (struct net_device *dev, int *budget) mapping = pci_map_single(cp->pdev, new_skb->data, buflen, PCI_DMA_FROMDEVICE); - cp->rx_skb[rx_tail].skb = new_skb; + cp->rx_skb[rx_tail] = new_skb; cp_rx_skb(cp, skb, desc); rx++; @@ -1097,7 +1097,7 @@ static int cp_refill_rx (struct cp_private *cp) mapping = pci_map_single(cp->pdev, skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE); - cp->rx_skb[i].skb = skb; + cp->rx_skb[i] = skb; cp->rx_ring[i].opts2 = 0; cp->rx_ring[i].addr = cpu_to_le64(mapping); @@ -1152,11 +1152,11 @@ static void cp_clean_rings (struct cp_private *cp) unsigned i; for (i = 0; i < CP_RX_RING_SIZE; i++) { - if (cp->rx_skb[i].skb) { + if (cp->rx_skb[i]) { desc = cp->rx_ring + i; pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr), cp->rx_buf_sz, PCI_DMA_FROMDEVICE); - dev_kfree_skb(cp->rx_skb[i].skb); + dev_kfree_skb(cp->rx_skb[i]); } } @@ -1176,7 +1176,7 @@ static void cp_clean_rings (struct cp_private *cp) memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE); memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE); - memset(&cp->rx_skb, 0, sizeof(struct ring_info) * CP_RX_RING_SIZE); + memset(cp->rx_skb, 0, sizeof(struct sk_buff *) * CP_RX_RING_SIZE); memset(&cp->tx_skb, 0, sizeof(struct ring_info) * CP_TX_RING_SIZE); } From d03d376dd29cae53bf70a21a0c26b306abe37326 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Sun, 29 Jan 2006 01:31:36 +0100 Subject: [PATCH 4/8] 8139cp: sync the device private data with its r8169 counterpart struct cp_private is reorganized to be more easily compared between the r8169 and the 8139cp drivers. The alignment should not be impacted. Signed-off-by: Francois Romieu --- drivers/net/8139cp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 072568120e48..9aef517d7502 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -352,23 +352,23 @@ struct cp_private { struct net_device_stats net_stats; struct cp_extra_stats cp_stats; - unsigned rx_tail ____cacheline_aligned; + unsigned rx_head ____cacheline_aligned; + unsigned rx_tail; struct cp_desc *rx_ring; struct sk_buff *rx_skb[CP_RX_RING_SIZE]; - unsigned rx_buf_sz; unsigned tx_head ____cacheline_aligned; unsigned tx_tail; - struct cp_desc *tx_ring; struct ring_info tx_skb[CP_TX_RING_SIZE]; - dma_addr_t ring_dma; + + unsigned rx_buf_sz; + unsigned wol_enabled : 1; /* Is Wake-on-LAN enabled? */ #if CP_VLAN_TAG_USED struct vlan_group *vlgrp; #endif - - unsigned int wol_enabled : 1; /* Is Wake-on-LAN enabled? */ + dma_addr_t ring_dma; struct mii_if_info mii_if; }; From e68970e7543815133224f79a858e7c9e0c42f4de Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Tue, 15 Aug 2006 16:22:27 +0200 Subject: [PATCH 5/8] 8139cp: removal of useless BUG_ON() check netdev_priv() will provide a nice oops a few lines before the BUG_ON() check. Signed-off-by: Francois Romieu --- drivers/net/8139cp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 9aef517d7502..94ab3c31e7e1 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -2009,7 +2009,6 @@ static void cp_remove_one (struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct cp_private *cp = netdev_priv(dev); - BUG_ON(!dev); unregister_netdev(dev); iounmap(cp->regs); if (cp->wol_enabled) From 7668a4945ba0e17a61e535a6c67aa64a319a03b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Romieu?= Date: Tue, 15 Aug 2006 20:10:57 +0200 Subject: [PATCH 6/8] 8139cp: pci_get_drvdata(pdev) can not be NULL in suspend handler 1) pci_set_drvdata() is used in cp_{init/remove}_one to initialize/reset driver_data to the relevant value (resp. net_device * and NULL). 2) each of the 3 relevant functions is issued under (device *)->sem: 2.1) pci_unregister_driver -> driver_unregister -> bus_remove_driver -> driver_detach (takes (device *)->sem) -> __device_release_driver(dev) -> dev->bus-remove(dev) (== pci_device_remove) -> drv->remove(pdev) (== cp_remove_one) [...] pci_dev->driver = NULL; 2.2) pci_register_driver -> __pci_register_driver -> driver_register -> bus_add_driver -> driver_attach -> __driver_attach (takes (device *)->sem) -> driver_probe_device(drv, dev) -> dev->bus->probe(dev) (== pci_device_probe) -> _pci_device_probe(drv, pci_dev) -> pci_call_probe(drv, pci_dev, id) -> drv->probe(dev, id) (== cp_init_one) [...] pci_dev->driver = drv; 2.3) suspend_device (takes (device *)->sem) -> dev->bus->suspend(dev) (== pci_device_suspend) checking for drv = pci_dev->driver != NULL [...] -> drv->suspend(pci_dev, state) (== cp_suspend) dev->sem and the state of pci_dev->driver provide the expected result. St Mary's day was a bit rainy here. Signed-off-by: Francois Romieu --- drivers/net/8139cp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 94ab3c31e7e1..a123d28113cd 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -2023,14 +2023,12 @@ static void cp_remove_one (struct pci_dev *pdev) #ifdef CONFIG_PM static int cp_suspend (struct pci_dev *pdev, pm_message_t state) { - struct net_device *dev; - struct cp_private *cp; + struct net_device *dev = pci_get_drvdata(pdev); + struct cp_private *cp = netdev_priv(dev); unsigned long flags; - dev = pci_get_drvdata (pdev); - cp = netdev_priv(dev); - - if (!dev || !netif_running (dev)) return 0; + if (!netif_running(dev)) + return 0; netif_device_detach (dev); netif_stop_queue (dev); From cccb20d3a9b7c6d4b6e1b52ee02814e6094aaa12 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Wed, 16 Aug 2006 13:07:18 +0200 Subject: [PATCH 7/8] 8139cp: use PCI_DEVICE() to shorten the PCI device table Signed-off-by: Francois Romieu --- drivers/net/8139cp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index a123d28113cd..bbdaa18879ab 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -406,10 +406,8 @@ static int cp_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data); static struct pci_device_id cp_pci_tbl[] = { - { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - { PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139), }, + { PCI_DEVICE(PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322), }, { }, }; MODULE_DEVICE_TABLE(pci, cp_pci_tbl); From 48907e39890590792c58272604cfb34ad1d80054 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Sun, 10 Sep 2006 23:33:44 +0200 Subject: [PATCH 8/8] 8139cp: ring_info removal for the transmit path As long as the descriptor fits on a single cacheline, the change should be almost free. Now ring_info is not used at all. Remove it. Signed-off-by: Francois Romieu --- drivers/net/8139cp.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index bbdaa18879ab..c3b8400bdc3f 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -314,11 +314,6 @@ struct cp_desc { u64 addr; }; -struct ring_info { - struct sk_buff *skb; - u32 len; -}; - struct cp_dma_stats { u64 tx_ok; u64 rx_ok; @@ -360,7 +355,7 @@ struct cp_private { unsigned tx_head ____cacheline_aligned; unsigned tx_tail; struct cp_desc *tx_ring; - struct ring_info tx_skb[CP_TX_RING_SIZE]; + struct sk_buff *tx_skb[CP_TX_RING_SIZE]; unsigned rx_buf_sz; unsigned wol_enabled : 1; /* Is Wake-on-LAN enabled? */ @@ -721,11 +716,12 @@ static void cp_tx (struct cp_private *cp) if (status & DescOwn) break; - skb = cp->tx_skb[tx_tail].skb; + skb = cp->tx_skb[tx_tail]; BUG_ON(!skb); pci_unmap_single(cp->pdev, le64_to_cpu(txd->addr), - cp->tx_skb[tx_tail].len, PCI_DMA_TODEVICE); + le32_to_cpu(txd->opts1) & 0xffff, + PCI_DMA_TODEVICE); if (status & LastFrag) { if (status & (TxError | TxFIFOUnder)) { @@ -752,7 +748,7 @@ static void cp_tx (struct cp_private *cp) dev_kfree_skb_irq(skb); } - cp->tx_skb[tx_tail].skb = NULL; + cp->tx_skb[tx_tail] = NULL; tx_tail = NEXT_TX(tx_tail); } @@ -822,8 +818,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) txd->opts1 = cpu_to_le32(flags); wmb(); - cp->tx_skb[entry].skb = skb; - cp->tx_skb[entry].len = len; + cp->tx_skb[entry] = skb; entry = NEXT_TX(entry); } else { struct cp_desc *txd; @@ -839,8 +834,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) first_len = skb_headlen(skb); first_mapping = pci_map_single(cp->pdev, skb->data, first_len, PCI_DMA_TODEVICE); - cp->tx_skb[entry].skb = skb; - cp->tx_skb[entry].len = first_len; + cp->tx_skb[entry] = skb; entry = NEXT_TX(entry); for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { @@ -881,8 +875,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) txd->opts1 = cpu_to_le32(ctrl); wmb(); - cp->tx_skb[entry].skb = skb; - cp->tx_skb[entry].len = len; + cp->tx_skb[entry] = skb; entry = NEXT_TX(entry); } @@ -1159,12 +1152,13 @@ static void cp_clean_rings (struct cp_private *cp) } for (i = 0; i < CP_TX_RING_SIZE; i++) { - if (cp->tx_skb[i].skb) { - struct sk_buff *skb = cp->tx_skb[i].skb; + if (cp->tx_skb[i]) { + struct sk_buff *skb = cp->tx_skb[i]; desc = cp->tx_ring + i; pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr), - cp->tx_skb[i].len, PCI_DMA_TODEVICE); + le32_to_cpu(desc->opts1) & 0xffff, + PCI_DMA_TODEVICE); if (le32_to_cpu(desc->opts1) & LastFrag) dev_kfree_skb(skb); cp->net_stats.tx_dropped++; @@ -1175,7 +1169,7 @@ static void cp_clean_rings (struct cp_private *cp) memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE); memset(cp->rx_skb, 0, sizeof(struct sk_buff *) * CP_RX_RING_SIZE); - memset(&cp->tx_skb, 0, sizeof(struct ring_info) * CP_TX_RING_SIZE); + memset(cp->tx_skb, 0, sizeof(struct sk_buff *) * CP_TX_RING_SIZE); } static void cp_free_rings (struct cp_private *cp)