diff options
author | Linas Vepstas <linas@austin.ibm.com> | 2006-12-13 16:06:59 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-02-05 16:58:43 -0500 |
commit | d4ed8f8d1fb7d59eb63d2eada9a32c2f8c3795e2 (patch) | |
tree | 5deb53b975439ce61e40bee57259c2d113df598a | |
parent | 834324687d08e0f67b167934cb56406aa98ff8c6 (diff) |
Spidernet DMA coalescing
The current driver code performs 512 DMA mappings of a bunch of
32-byte ring descriptor structures. This is silly, as they are
all in contiguous memory. This patch changes the code to
dma_map_coherent() each rx/tx ring as a whole.
Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
Cc: James K Lewis <jklewis@us.ibm.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/net/spider_net.c | 103 | ||||
-rw-r--r-- | drivers/net/spider_net.h | 17 | ||||
-rw-r--r-- | drivers/net/spider_net_ethtool.c | 4 |
3 files changed, 54 insertions, 70 deletions
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 8ea2fc1b96cb..8c8381cbce0a 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c | |||
@@ -280,72 +280,67 @@ spider_net_free_chain(struct spider_net_card *card, | |||
280 | { | 280 | { |
281 | struct spider_net_descr *descr; | 281 | struct spider_net_descr *descr; |
282 | 282 | ||
283 | for (descr = chain->tail; !descr->bus_addr; descr = descr->next) { | 283 | descr = chain->ring; |
284 | pci_unmap_single(card->pdev, descr->bus_addr, | 284 | do { |
285 | SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL); | ||
286 | descr->bus_addr = 0; | 285 | descr->bus_addr = 0; |
287 | } | 286 | descr->next_descr_addr = 0; |
287 | descr = descr->next; | ||
288 | } while (descr != chain->ring); | ||
289 | |||
290 | dma_free_coherent(&card->pdev->dev, chain->num_desc, | ||
291 | chain->ring, chain->dma_addr); | ||
288 | } | 292 | } |
289 | 293 | ||
290 | /** | 294 | /** |
291 | * spider_net_init_chain - links descriptor chain | 295 | * spider_net_init_chain - alloc and link descriptor chain |
292 | * @card: card structure | 296 | * @card: card structure |
293 | * @chain: address of chain | 297 | * @chain: address of chain |
294 | * @start_descr: address of descriptor array | ||
295 | * @no: number of descriptors | ||
296 | * | 298 | * |
297 | * we manage a circular list that mirrors the hardware structure, | 299 | * We manage a circular list that mirrors the hardware structure, |
298 | * except that the hardware uses bus addresses. | 300 | * except that the hardware uses bus addresses. |
299 | * | 301 | * |
300 | * returns 0 on success, <0 on failure | 302 | * Returns 0 on success, <0 on failure |
301 | */ | 303 | */ |
302 | static int | 304 | static int |
303 | spider_net_init_chain(struct spider_net_card *card, | 305 | spider_net_init_chain(struct spider_net_card *card, |
304 | struct spider_net_descr_chain *chain, | 306 | struct spider_net_descr_chain *chain) |
305 | struct spider_net_descr *start_descr, | ||
306 | int no) | ||
307 | { | 307 | { |
308 | int i; | 308 | int i; |
309 | struct spider_net_descr *descr; | 309 | struct spider_net_descr *descr; |
310 | dma_addr_t buf; | 310 | dma_addr_t buf; |
311 | size_t alloc_size; | ||
311 | 312 | ||
312 | descr = start_descr; | 313 | alloc_size = chain->num_desc * sizeof (struct spider_net_descr); |
313 | memset(descr, 0, sizeof(*descr) * no); | ||
314 | 314 | ||
315 | /* set up the hardware pointers in each descriptor */ | 315 | chain->ring = dma_alloc_coherent(&card->pdev->dev, alloc_size, |
316 | for (i=0; i<no; i++, descr++) { | 316 | &chain->dma_addr, GFP_KERNEL); |
317 | descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; | ||
318 | 317 | ||
319 | buf = pci_map_single(card->pdev, descr, | 318 | if (!chain->ring) |
320 | SPIDER_NET_DESCR_SIZE, | 319 | return -ENOMEM; |
321 | PCI_DMA_BIDIRECTIONAL); | ||
322 | 320 | ||
323 | if (pci_dma_mapping_error(buf)) | 321 | descr = chain->ring; |
324 | goto iommu_error; | 322 | memset(descr, 0, alloc_size); |
323 | |||
324 | /* Set up the hardware pointers in each descriptor */ | ||
325 | buf = chain->dma_addr; | ||
326 | for (i=0; i < chain->num_desc; i++, descr++) { | ||
327 | descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; | ||
325 | 328 | ||
326 | descr->bus_addr = buf; | 329 | descr->bus_addr = buf; |
330 | descr->next_descr_addr = 0; | ||
327 | descr->next = descr + 1; | 331 | descr->next = descr + 1; |
328 | descr->prev = descr - 1; | 332 | descr->prev = descr - 1; |
329 | 333 | ||
334 | buf += sizeof(struct spider_net_descr); | ||
330 | } | 335 | } |
331 | /* do actual circular list */ | 336 | /* do actual circular list */ |
332 | (descr-1)->next = start_descr; | 337 | (descr-1)->next = chain->ring; |
333 | start_descr->prev = descr-1; | 338 | chain->ring->prev = descr-1; |
334 | 339 | ||
335 | spin_lock_init(&chain->lock); | 340 | spin_lock_init(&chain->lock); |
336 | chain->head = start_descr; | 341 | chain->head = chain->ring; |
337 | chain->tail = start_descr; | 342 | chain->tail = chain->ring; |
338 | |||
339 | return 0; | 343 | return 0; |
340 | |||
341 | iommu_error: | ||
342 | descr = start_descr; | ||
343 | for (i=0; i < no; i++, descr++) | ||
344 | if (descr->bus_addr) | ||
345 | pci_unmap_single(card->pdev, descr->bus_addr, | ||
346 | SPIDER_NET_DESCR_SIZE, | ||
347 | PCI_DMA_BIDIRECTIONAL); | ||
348 | return -ENOMEM; | ||
349 | } | 344 | } |
350 | 345 | ||
351 | /** | 346 | /** |
@@ -707,7 +702,7 @@ spider_net_set_low_watermark(struct spider_net_card *card) | |||
707 | } | 702 | } |
708 | 703 | ||
709 | /* If TX queue is short, don't even bother with interrupts */ | 704 | /* If TX queue is short, don't even bother with interrupts */ |
710 | if (cnt < card->num_tx_desc/4) | 705 | if (cnt < card->tx_chain.num_desc/4) |
711 | return cnt; | 706 | return cnt; |
712 | 707 | ||
713 | /* Set low-watermark 3/4th's of the way into the queue. */ | 708 | /* Set low-watermark 3/4th's of the way into the queue. */ |
@@ -1652,26 +1647,25 @@ spider_net_open(struct net_device *netdev) | |||
1652 | { | 1647 | { |
1653 | struct spider_net_card *card = netdev_priv(netdev); | 1648 | struct spider_net_card *card = netdev_priv(netdev); |
1654 | struct spider_net_descr *descr; | 1649 | struct spider_net_descr *descr; |
1655 | int i, result; | 1650 | int result; |
1656 | 1651 | ||
1657 | result = -ENOMEM; | 1652 | result = spider_net_init_chain(card, &card->tx_chain); |
1658 | if (spider_net_init_chain(card, &card->tx_chain, card->descr, | 1653 | if (result) |
1659 | card->num_tx_desc)) | ||
1660 | goto alloc_tx_failed; | 1654 | goto alloc_tx_failed; |
1661 | |||
1662 | card->low_watermark = NULL; | 1655 | card->low_watermark = NULL; |
1663 | 1656 | ||
1664 | /* rx_chain is after tx_chain, so offset is descr + tx_count */ | 1657 | result = spider_net_init_chain(card, &card->rx_chain); |
1665 | if (spider_net_init_chain(card, &card->rx_chain, | 1658 | if (result) |
1666 | card->descr + card->num_tx_desc, | ||
1667 | card->num_rx_desc)) | ||
1668 | goto alloc_rx_failed; | 1659 | goto alloc_rx_failed; |
1669 | 1660 | ||
1670 | descr = card->rx_chain.head; | 1661 | /* Make a ring of of bus addresses */ |
1671 | for (i=0; i < card->num_rx_desc; i++, descr++) | 1662 | descr = card->rx_chain.ring; |
1663 | do { | ||
1672 | descr->next_descr_addr = descr->next->bus_addr; | 1664 | descr->next_descr_addr = descr->next->bus_addr; |
1665 | descr = descr->next; | ||
1666 | } while (descr != card->rx_chain.ring); | ||
1673 | 1667 | ||
1674 | /* allocate rx skbs */ | 1668 | /* Allocate rx skbs */ |
1675 | if (spider_net_alloc_rx_skbs(card)) | 1669 | if (spider_net_alloc_rx_skbs(card)) |
1676 | goto alloc_skbs_failed; | 1670 | goto alloc_skbs_failed; |
1677 | 1671 | ||
@@ -1924,6 +1918,7 @@ spider_net_stop(struct net_device *netdev) | |||
1924 | 1918 | ||
1925 | /* release chains */ | 1919 | /* release chains */ |
1926 | spider_net_release_tx_chain(card, 1); | 1920 | spider_net_release_tx_chain(card, 1); |
1921 | spider_net_free_rx_chain_contents(card); | ||
1927 | 1922 | ||
1928 | spider_net_free_rx_chain_contents(card); | 1923 | spider_net_free_rx_chain_contents(card); |
1929 | 1924 | ||
@@ -2057,8 +2052,8 @@ spider_net_setup_netdev(struct spider_net_card *card) | |||
2057 | 2052 | ||
2058 | card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; | 2053 | card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; |
2059 | 2054 | ||
2060 | card->num_tx_desc = tx_descriptors; | 2055 | card->tx_chain.num_desc = tx_descriptors; |
2061 | card->num_rx_desc = rx_descriptors; | 2056 | card->rx_chain.num_desc = rx_descriptors; |
2062 | 2057 | ||
2063 | spider_net_setup_netdev_ops(netdev); | 2058 | spider_net_setup_netdev_ops(netdev); |
2064 | 2059 | ||
@@ -2107,12 +2102,8 @@ spider_net_alloc_card(void) | |||
2107 | { | 2102 | { |
2108 | struct net_device *netdev; | 2103 | struct net_device *netdev; |
2109 | struct spider_net_card *card; | 2104 | struct spider_net_card *card; |
2110 | size_t alloc_size; | ||
2111 | 2105 | ||
2112 | alloc_size = sizeof (*card) + | 2106 | netdev = alloc_etherdev(sizeof(struct spider_net_card)); |
2113 | sizeof (struct spider_net_descr) * rx_descriptors + | ||
2114 | sizeof (struct spider_net_descr) * tx_descriptors; | ||
2115 | netdev = alloc_etherdev(alloc_size); | ||
2116 | if (!netdev) | 2107 | if (!netdev) |
2117 | return NULL; | 2108 | return NULL; |
2118 | 2109 | ||
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 3e196df29790..4b76ef9524d1 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h | |||
@@ -378,6 +378,9 @@ struct spider_net_descr_chain { | |||
378 | spinlock_t lock; | 378 | spinlock_t lock; |
379 | struct spider_net_descr *head; | 379 | struct spider_net_descr *head; |
380 | struct spider_net_descr *tail; | 380 | struct spider_net_descr *tail; |
381 | struct spider_net_descr *ring; | ||
382 | int num_desc; | ||
383 | dma_addr_t dma_addr; | ||
381 | }; | 384 | }; |
382 | 385 | ||
383 | /* descriptor data_status bits */ | 386 | /* descriptor data_status bits */ |
@@ -397,8 +400,6 @@ struct spider_net_descr_chain { | |||
397 | * 701b8000 would be correct, but every packets gets that flag */ | 400 | * 701b8000 would be correct, but every packets gets that flag */ |
398 | #define SPIDER_NET_DESTROY_RX_FLAGS 0x700b8000 | 401 | #define SPIDER_NET_DESTROY_RX_FLAGS 0x700b8000 |
399 | 402 | ||
400 | #define SPIDER_NET_DESCR_SIZE 32 | ||
401 | |||
402 | /* this will be bigger some time */ | 403 | /* this will be bigger some time */ |
403 | struct spider_net_options { | 404 | struct spider_net_options { |
404 | int rx_csum; /* for rx: if 0 ip_summed=NONE, | 405 | int rx_csum; /* for rx: if 0 ip_summed=NONE, |
@@ -441,25 +442,17 @@ struct spider_net_card { | |||
441 | struct spider_net_descr_chain rx_chain; | 442 | struct spider_net_descr_chain rx_chain; |
442 | struct spider_net_descr *low_watermark; | 443 | struct spider_net_descr *low_watermark; |
443 | 444 | ||
444 | struct net_device_stats netdev_stats; | ||
445 | |||
446 | struct spider_net_options options; | ||
447 | |||
448 | spinlock_t intmask_lock; | ||
449 | struct tasklet_struct rxram_full_tl; | 445 | struct tasklet_struct rxram_full_tl; |
450 | struct timer_list tx_timer; | 446 | struct timer_list tx_timer; |
451 | |||
452 | struct work_struct tx_timeout_task; | 447 | struct work_struct tx_timeout_task; |
453 | atomic_t tx_timeout_task_counter; | 448 | atomic_t tx_timeout_task_counter; |
454 | wait_queue_head_t waitq; | 449 | wait_queue_head_t waitq; |
455 | 450 | ||
456 | /* for ethtool */ | 451 | /* for ethtool */ |
457 | int msg_enable; | 452 | int msg_enable; |
458 | int num_rx_desc; | 453 | struct net_device_stats netdev_stats; |
459 | int num_tx_desc; | ||
460 | struct spider_net_extra_stats spider_stats; | 454 | struct spider_net_extra_stats spider_stats; |
461 | 455 | struct spider_net_options options; | |
462 | struct spider_net_descr descr[0]; | ||
463 | }; | 456 | }; |
464 | 457 | ||
465 | #define pr_err(fmt,arg...) \ | 458 | #define pr_err(fmt,arg...) \ |
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 91b995102915..6bcf03fc89be 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c | |||
@@ -158,9 +158,9 @@ spider_net_ethtool_get_ringparam(struct net_device *netdev, | |||
158 | struct spider_net_card *card = netdev->priv; | 158 | struct spider_net_card *card = netdev->priv; |
159 | 159 | ||
160 | ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX; | 160 | ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX; |
161 | ering->tx_pending = card->num_tx_desc; | 161 | ering->tx_pending = card->tx_chain.num_desc; |
162 | ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX; | 162 | ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX; |
163 | ering->rx_pending = card->num_rx_desc; | 163 | ering->rx_pending = card->rx_chain.num_desc; |
164 | } | 164 | } |
165 | 165 | ||
166 | static int spider_net_get_stats_count(struct net_device *netdev) | 166 | static int spider_net_get_stats_count(struct net_device *netdev) |