diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-08 14:57:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-08 14:57:17 -0400 |
commit | 9028780a3e6d2c3dd940e89b377765cca008b6df (patch) | |
tree | 1e72fceedcb72b65e8851d0a56586a699e09ad2e /drivers/net/pasemi_mac.c | |
parent | 5335a40be6867eff986a31bcd8fc82a5cb1e16bb (diff) | |
parent | e824f7836de25b1c2f659a2412d32227f1f68bcb (diff) |
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6: (40 commits)
[netdrvr] atl1: fix build
pasemi_mac: Use local-mac-address instead of mac-address if available
pasemi_mac: PHY support
pasemi_mac: Add msglevel support and "debug" module param
pasemi_mac: Logic cleanup / rx performance improvements
pasemi_mac: Minor cleanup / define fixes
pasemi_mac: Add SKB reuse / copy-break
pasemi_mac: Timer and interrupt fixes
pasemi_mac: Abstract and fix up interrupt restart routines
pasemi_mac: Move the IRQ mapping from the PCI layer to the driver
tc35815: Remove unnecessary skb->dev assignment
drivers/net/dm9000: Convert to generic boolean
AT91RM9200 Ethernet: Fix multicast addressing
AT91RM9200 Ethernet: Support additional PHYs
PCMCIA-NETDEV : xirc2ps_cs: bugfix of multicast code
sky2: re-enable 88E8056 for most motherboards
MIPS: Drop unnecessary CONFIG_ISA from RBTX49XX
ne: MIPS: Use platform_driver for ne on RBTX49XX
ne: Add NEEDS_PORTLIST to control ISA auto-probe
ne: Misc fixes for platform driver.
...
Fix conflict in drivers/net/pasemi_mac.c (get_property() got renamed to
of_get_property()) manually.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/net/pasemi_mac.c')
-rw-r--r-- | drivers/net/pasemi_mac.c | 404 |
1 files changed, 311 insertions, 93 deletions
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 07eb9b24a97f..bc7f3dee6e5b 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c | |||
@@ -33,6 +33,8 @@ | |||
33 | #include <linux/tcp.h> | 33 | #include <linux/tcp.h> |
34 | #include <net/checksum.h> | 34 | #include <net/checksum.h> |
35 | 35 | ||
36 | #include <asm/irq.h> | ||
37 | |||
36 | #include "pasemi_mac.h" | 38 | #include "pasemi_mac.h" |
37 | 39 | ||
38 | 40 | ||
@@ -51,6 +53,16 @@ | |||
51 | #define RX_RING_SIZE 512 | 53 | #define RX_RING_SIZE 512 |
52 | #define TX_RING_SIZE 512 | 54 | #define TX_RING_SIZE 512 |
53 | 55 | ||
56 | #define DEFAULT_MSG_ENABLE \ | ||
57 | (NETIF_MSG_DRV | \ | ||
58 | NETIF_MSG_PROBE | \ | ||
59 | NETIF_MSG_LINK | \ | ||
60 | NETIF_MSG_TIMER | \ | ||
61 | NETIF_MSG_IFDOWN | \ | ||
62 | NETIF_MSG_IFUP | \ | ||
63 | NETIF_MSG_RX_ERR | \ | ||
64 | NETIF_MSG_TX_ERR) | ||
65 | |||
54 | #define TX_DESC(mac, num) ((mac)->tx->desc[(num) & (TX_RING_SIZE-1)]) | 66 | #define TX_DESC(mac, num) ((mac)->tx->desc[(num) & (TX_RING_SIZE-1)]) |
55 | #define TX_DESC_INFO(mac, num) ((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)]) | 67 | #define TX_DESC_INFO(mac, num) ((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)]) |
56 | #define RX_DESC(mac, num) ((mac)->rx->desc[(num) & (RX_RING_SIZE-1)]) | 68 | #define RX_DESC(mac, num) ((mac)->rx->desc[(num) & (RX_RING_SIZE-1)]) |
@@ -59,11 +71,13 @@ | |||
59 | 71 | ||
60 | #define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ | 72 | #define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ |
61 | 73 | ||
62 | /* XXXOJN these should come out of the device tree some day */ | 74 | MODULE_LICENSE("GPL"); |
63 | #define PAS_DMA_CAP_BASE 0xe00d0040 | 75 | MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>"); |
64 | #define PAS_DMA_CAP_SIZE 0x100 | 76 | MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver"); |
65 | #define PAS_DMA_COM_BASE 0xe00d0100 | 77 | |
66 | #define PAS_DMA_COM_SIZE 0x100 | 78 | static int debug = -1; /* -1 == use DEFAULT_MSG_ENABLE as value */ |
79 | module_param(debug, int, 0); | ||
80 | MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value"); | ||
67 | 81 | ||
68 | static struct pasdma_status *dma_status; | 82 | static struct pasdma_status *dma_status; |
69 | 83 | ||
@@ -80,7 +94,12 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac) | |||
80 | return -ENOENT; | 94 | return -ENOENT; |
81 | } | 95 | } |
82 | 96 | ||
83 | maddr = of_get_property(dn, "mac-address", NULL); | 97 | maddr = of_get_property(dn, "local-mac-address", NULL); |
98 | |||
99 | /* Fall back to mac-address for older firmware */ | ||
100 | if (maddr == NULL) | ||
101 | maddr = of_get_property(dn, "mac-address", NULL); | ||
102 | |||
84 | if (maddr == NULL) { | 103 | if (maddr == NULL) { |
85 | dev_warn(&pdev->dev, | 104 | dev_warn(&pdev->dev, |
86 | "no mac address in device tree, not configuring\n"); | 105 | "no mac address in device tree, not configuring\n"); |
@@ -277,8 +296,8 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev) | |||
277 | for (i = 0; i < RX_RING_SIZE; i++) { | 296 | for (i = 0; i < RX_RING_SIZE; i++) { |
278 | info = &RX_DESC_INFO(mac, i); | 297 | info = &RX_DESC_INFO(mac, i); |
279 | dp = &RX_DESC(mac, i); | 298 | dp = &RX_DESC(mac, i); |
280 | if (info->dma) { | 299 | if (info->skb) { |
281 | if (info->skb) { | 300 | if (info->dma) { |
282 | pci_unmap_single(mac->dma_pdev, | 301 | pci_unmap_single(mac->dma_pdev, |
283 | info->dma, | 302 | info->dma, |
284 | info->skb->len, | 303 | info->skb->len, |
@@ -309,82 +328,120 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev) | |||
309 | struct pasemi_mac *mac = netdev_priv(dev); | 328 | struct pasemi_mac *mac = netdev_priv(dev); |
310 | unsigned int i; | 329 | unsigned int i; |
311 | int start = mac->rx->next_to_fill; | 330 | int start = mac->rx->next_to_fill; |
312 | unsigned int count; | 331 | unsigned int limit, count; |
313 | 332 | ||
314 | count = (mac->rx->next_to_clean + RX_RING_SIZE - | 333 | limit = (mac->rx->next_to_clean + RX_RING_SIZE - |
315 | mac->rx->next_to_fill) & (RX_RING_SIZE - 1); | 334 | mac->rx->next_to_fill) & (RX_RING_SIZE - 1); |
316 | 335 | ||
317 | /* Check to see if we're doing first-time setup */ | 336 | /* Check to see if we're doing first-time setup */ |
318 | if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0)) | 337 | if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0)) |
319 | count = RX_RING_SIZE; | 338 | limit = RX_RING_SIZE; |
320 | 339 | ||
321 | if (count <= 0) | 340 | if (limit <= 0) |
322 | return; | 341 | return; |
323 | 342 | ||
324 | for (i = start; i < start + count; i++) { | 343 | i = start; |
344 | for (count = limit; count; count--) { | ||
325 | struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i); | 345 | struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i); |
326 | u64 *buff = &RX_BUFF(mac, i); | 346 | u64 *buff = &RX_BUFF(mac, i); |
327 | struct sk_buff *skb; | 347 | struct sk_buff *skb; |
328 | dma_addr_t dma; | 348 | dma_addr_t dma; |
329 | 349 | ||
330 | skb = dev_alloc_skb(BUF_SIZE); | 350 | /* skb might still be in there for recycle on short receives */ |
351 | if (info->skb) | ||
352 | skb = info->skb; | ||
353 | else | ||
354 | skb = dev_alloc_skb(BUF_SIZE); | ||
331 | 355 | ||
332 | if (!skb) { | 356 | if (unlikely(!skb)) |
333 | count = i - start; | ||
334 | break; | 357 | break; |
335 | } | ||
336 | 358 | ||
337 | dma = pci_map_single(mac->dma_pdev, skb->data, skb->len, | 359 | dma = pci_map_single(mac->dma_pdev, skb->data, skb->len, |
338 | PCI_DMA_FROMDEVICE); | 360 | PCI_DMA_FROMDEVICE); |
339 | 361 | ||
340 | if (dma_mapping_error(dma)) { | 362 | if (unlikely(dma_mapping_error(dma))) { |
341 | dev_kfree_skb_irq(info->skb); | 363 | dev_kfree_skb_irq(info->skb); |
342 | count = i - start; | ||
343 | break; | 364 | break; |
344 | } | 365 | } |
345 | 366 | ||
346 | info->skb = skb; | 367 | info->skb = skb; |
347 | info->dma = dma; | 368 | info->dma = dma; |
348 | *buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma); | 369 | *buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma); |
370 | i++; | ||
349 | } | 371 | } |
350 | 372 | ||
351 | wmb(); | 373 | wmb(); |
352 | 374 | ||
353 | pci_write_config_dword(mac->dma_pdev, | 375 | pci_write_config_dword(mac->dma_pdev, |
354 | PAS_DMA_RXCHAN_INCR(mac->dma_rxch), | 376 | PAS_DMA_RXCHAN_INCR(mac->dma_rxch), |
355 | count); | 377 | limit - count); |
356 | pci_write_config_dword(mac->dma_pdev, | 378 | pci_write_config_dword(mac->dma_pdev, |
357 | PAS_DMA_RXINT_INCR(mac->dma_if), | 379 | PAS_DMA_RXINT_INCR(mac->dma_if), |
358 | count); | 380 | limit - count); |
359 | 381 | ||
360 | mac->rx->next_to_fill += count; | 382 | mac->rx->next_to_fill += limit - count; |
361 | } | 383 | } |
362 | 384 | ||
385 | static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac) | ||
386 | { | ||
387 | unsigned int reg, stat; | ||
388 | /* Re-enable packet count interrupts: finally | ||
389 | * ack the packet count interrupt we got in rx_intr. | ||
390 | */ | ||
391 | |||
392 | pci_read_config_dword(mac->iob_pdev, | ||
393 | PAS_IOB_DMA_RXCH_STAT(mac->dma_rxch), | ||
394 | &stat); | ||
395 | |||
396 | reg = PAS_IOB_DMA_RXCH_RESET_PCNT(stat & PAS_IOB_DMA_RXCH_STAT_CNTDEL_M) | ||
397 | | PAS_IOB_DMA_RXCH_RESET_PINTC; | ||
398 | |||
399 | pci_write_config_dword(mac->iob_pdev, | ||
400 | PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), | ||
401 | reg); | ||
402 | } | ||
403 | |||
404 | static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac) | ||
405 | { | ||
406 | unsigned int reg, stat; | ||
407 | |||
408 | /* Re-enable packet count interrupts */ | ||
409 | pci_read_config_dword(mac->iob_pdev, | ||
410 | PAS_IOB_DMA_TXCH_STAT(mac->dma_txch), &stat); | ||
411 | |||
412 | reg = PAS_IOB_DMA_TXCH_RESET_PCNT(stat & PAS_IOB_DMA_TXCH_STAT_CNTDEL_M) | ||
413 | | PAS_IOB_DMA_TXCH_RESET_PINTC; | ||
414 | |||
415 | pci_write_config_dword(mac->iob_pdev, | ||
416 | PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg); | ||
417 | } | ||
418 | |||
419 | |||
363 | static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) | 420 | static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) |
364 | { | 421 | { |
365 | unsigned int i; | 422 | unsigned int n; |
366 | int start, count; | 423 | int count; |
424 | struct pas_dma_xct_descr *dp; | ||
425 | struct pasemi_mac_buffer *info; | ||
426 | struct sk_buff *skb; | ||
427 | unsigned int i, len; | ||
428 | u64 macrx; | ||
429 | dma_addr_t dma; | ||
367 | 430 | ||
368 | spin_lock(&mac->rx->lock); | 431 | spin_lock(&mac->rx->lock); |
369 | 432 | ||
370 | start = mac->rx->next_to_clean; | 433 | n = mac->rx->next_to_clean; |
371 | count = 0; | ||
372 | 434 | ||
373 | for (i = start; i < (start + RX_RING_SIZE) && count < limit; i++) { | 435 | for (count = limit; count; count--) { |
374 | struct pas_dma_xct_descr *dp; | ||
375 | struct pasemi_mac_buffer *info; | ||
376 | struct sk_buff *skb; | ||
377 | unsigned int j, len; | ||
378 | dma_addr_t dma; | ||
379 | 436 | ||
380 | rmb(); | 437 | rmb(); |
381 | 438 | ||
382 | dp = &RX_DESC(mac, i); | 439 | dp = &RX_DESC(mac, n); |
440 | macrx = dp->macrx; | ||
383 | 441 | ||
384 | if (!(dp->macrx & XCT_MACRX_O)) | 442 | if (!(macrx & XCT_MACRX_O)) |
385 | break; | 443 | break; |
386 | 444 | ||
387 | count++; | ||
388 | 445 | ||
389 | info = NULL; | 446 | info = NULL; |
390 | 447 | ||
@@ -396,29 +453,42 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) | |||
396 | */ | 453 | */ |
397 | 454 | ||
398 | dma = (dp->ptr & XCT_PTR_ADDR_M); | 455 | dma = (dp->ptr & XCT_PTR_ADDR_M); |
399 | for (j = start; j < (start + RX_RING_SIZE); j++) { | 456 | for (i = n; i < (n + RX_RING_SIZE); i++) { |
400 | info = &RX_DESC_INFO(mac, j); | 457 | info = &RX_DESC_INFO(mac, i); |
401 | if (info->dma == dma) | 458 | if (info->dma == dma) |
402 | break; | 459 | break; |
403 | } | 460 | } |
404 | 461 | ||
405 | BUG_ON(!info); | 462 | skb = info->skb; |
406 | BUG_ON(info->dma != dma); | 463 | info->dma = 0; |
407 | 464 | ||
408 | pci_unmap_single(mac->dma_pdev, info->dma, info->skb->len, | 465 | pci_unmap_single(mac->dma_pdev, dma, skb->len, |
409 | PCI_DMA_FROMDEVICE); | 466 | PCI_DMA_FROMDEVICE); |
410 | 467 | ||
411 | skb = info->skb; | 468 | len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S; |
412 | 469 | ||
413 | len = (dp->macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S; | 470 | if (len < 256) { |
471 | struct sk_buff *new_skb = | ||
472 | netdev_alloc_skb(mac->netdev, len + NET_IP_ALIGN); | ||
473 | if (new_skb) { | ||
474 | skb_reserve(new_skb, NET_IP_ALIGN); | ||
475 | memcpy(new_skb->data - NET_IP_ALIGN, | ||
476 | skb->data - NET_IP_ALIGN, | ||
477 | len + NET_IP_ALIGN); | ||
478 | /* save the skb in buffer_info as good */ | ||
479 | skb = new_skb; | ||
480 | } | ||
481 | /* else just continue with the old one */ | ||
482 | } else | ||
483 | info->skb = NULL; | ||
414 | 484 | ||
415 | skb_put(skb, len); | 485 | skb_put(skb, len); |
416 | 486 | ||
417 | skb->protocol = eth_type_trans(skb, mac->netdev); | 487 | skb->protocol = eth_type_trans(skb, mac->netdev); |
418 | 488 | ||
419 | if ((dp->macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) { | 489 | if ((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) { |
420 | skb->ip_summed = CHECKSUM_COMPLETE; | 490 | skb->ip_summed = CHECKSUM_COMPLETE; |
421 | skb->csum = (dp->macrx & XCT_MACRX_CSUM_M) >> | 491 | skb->csum = (macrx & XCT_MACRX_CSUM_M) >> |
422 | XCT_MACRX_CSUM_S; | 492 | XCT_MACRX_CSUM_S; |
423 | } else | 493 | } else |
424 | skb->ip_summed = CHECKSUM_NONE; | 494 | skb->ip_summed = CHECKSUM_NONE; |
@@ -428,13 +498,13 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) | |||
428 | 498 | ||
429 | netif_receive_skb(skb); | 499 | netif_receive_skb(skb); |
430 | 500 | ||
431 | info->dma = 0; | ||
432 | info->skb = NULL; | ||
433 | dp->ptr = 0; | 501 | dp->ptr = 0; |
434 | dp->macrx = 0; | 502 | dp->macrx = 0; |
503 | |||
504 | n++; | ||
435 | } | 505 | } |
436 | 506 | ||
437 | mac->rx->next_to_clean += count; | 507 | mac->rx->next_to_clean += limit - count; |
438 | pasemi_mac_replenish_rx_ring(mac->netdev); | 508 | pasemi_mac_replenish_rx_ring(mac->netdev); |
439 | 509 | ||
440 | spin_unlock(&mac->rx->lock); | 510 | spin_unlock(&mac->rx->lock); |
@@ -476,6 +546,8 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac) | |||
476 | mac->tx->next_to_clean += count; | 546 | mac->tx->next_to_clean += count; |
477 | spin_unlock_irqrestore(&mac->tx->lock, flags); | 547 | spin_unlock_irqrestore(&mac->tx->lock, flags); |
478 | 548 | ||
549 | netif_wake_queue(mac->netdev); | ||
550 | |||
479 | return count; | 551 | return count; |
480 | } | 552 | } |
481 | 553 | ||
@@ -486,18 +558,28 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) | |||
486 | struct pasemi_mac *mac = netdev_priv(dev); | 558 | struct pasemi_mac *mac = netdev_priv(dev); |
487 | unsigned int reg; | 559 | unsigned int reg; |
488 | 560 | ||
489 | if (!(*mac->rx_status & PAS_STATUS_INT)) | 561 | if (!(*mac->rx_status & PAS_STATUS_CAUSE_M)) |
490 | return IRQ_NONE; | 562 | return IRQ_NONE; |
491 | 563 | ||
492 | netif_rx_schedule(dev); | 564 | if (*mac->rx_status & PAS_STATUS_ERROR) |
493 | pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, | 565 | printk("rx_status reported error\n"); |
494 | PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0)); | 566 | |
567 | /* Don't reset packet count so it won't fire again but clear | ||
568 | * all others. | ||
569 | */ | ||
570 | |||
571 | pci_read_config_dword(mac->dma_pdev, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), ®); | ||
495 | 572 | ||
496 | reg = PAS_IOB_DMA_RXCH_RESET_PINTC | PAS_IOB_DMA_RXCH_RESET_SINTC | | 573 | reg = 0; |
497 | PAS_IOB_DMA_RXCH_RESET_DINTC; | 574 | if (*mac->rx_status & PAS_STATUS_SOFT) |
575 | reg |= PAS_IOB_DMA_RXCH_RESET_SINTC; | ||
576 | if (*mac->rx_status & PAS_STATUS_ERROR) | ||
577 | reg |= PAS_IOB_DMA_RXCH_RESET_DINTC; | ||
498 | if (*mac->rx_status & PAS_STATUS_TIMER) | 578 | if (*mac->rx_status & PAS_STATUS_TIMER) |
499 | reg |= PAS_IOB_DMA_RXCH_RESET_TINTC; | 579 | reg |= PAS_IOB_DMA_RXCH_RESET_TINTC; |
500 | 580 | ||
581 | netif_rx_schedule(dev); | ||
582 | |||
501 | pci_write_config_dword(mac->iob_pdev, | 583 | pci_write_config_dword(mac->iob_pdev, |
502 | PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); | 584 | PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); |
503 | 585 | ||
@@ -510,31 +592,137 @@ static irqreturn_t pasemi_mac_tx_intr(int irq, void *data) | |||
510 | struct net_device *dev = data; | 592 | struct net_device *dev = data; |
511 | struct pasemi_mac *mac = netdev_priv(dev); | 593 | struct pasemi_mac *mac = netdev_priv(dev); |
512 | unsigned int reg; | 594 | unsigned int reg; |
513 | int was_full; | ||
514 | 595 | ||
515 | was_full = mac->tx->next_to_clean - mac->tx->next_to_use == TX_RING_SIZE; | 596 | if (!(*mac->tx_status & PAS_STATUS_CAUSE_M)) |
516 | |||
517 | if (!(*mac->tx_status & PAS_STATUS_INT)) | ||
518 | return IRQ_NONE; | 597 | return IRQ_NONE; |
519 | 598 | ||
520 | pasemi_mac_clean_tx(mac); | 599 | pasemi_mac_clean_tx(mac); |
521 | 600 | ||
522 | reg = PAS_IOB_DMA_TXCH_RESET_PINTC | PAS_IOB_DMA_TXCH_RESET_SINTC; | 601 | reg = PAS_IOB_DMA_TXCH_RESET_PINTC; |
523 | if (*mac->tx_status & PAS_STATUS_TIMER) | 602 | |
524 | reg |= PAS_IOB_DMA_TXCH_RESET_TINTC; | 603 | if (*mac->tx_status & PAS_STATUS_SOFT) |
604 | reg |= PAS_IOB_DMA_TXCH_RESET_SINTC; | ||
605 | if (*mac->tx_status & PAS_STATUS_ERROR) | ||
606 | reg |= PAS_IOB_DMA_TXCH_RESET_DINTC; | ||
525 | 607 | ||
526 | pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), | 608 | pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), |
527 | reg); | 609 | reg); |
528 | 610 | ||
529 | if (was_full) | ||
530 | netif_wake_queue(dev); | ||
531 | |||
532 | return IRQ_HANDLED; | 611 | return IRQ_HANDLED; |
533 | } | 612 | } |
534 | 613 | ||
614 | static void pasemi_adjust_link(struct net_device *dev) | ||
615 | { | ||
616 | struct pasemi_mac *mac = netdev_priv(dev); | ||
617 | int msg; | ||
618 | unsigned int flags; | ||
619 | unsigned int new_flags; | ||
620 | |||
621 | if (!mac->phydev->link) { | ||
622 | /* If no link, MAC speed settings don't matter. Just report | ||
623 | * link down and return. | ||
624 | */ | ||
625 | if (mac->link && netif_msg_link(mac)) | ||
626 | printk(KERN_INFO "%s: Link is down.\n", dev->name); | ||
627 | |||
628 | netif_carrier_off(dev); | ||
629 | mac->link = 0; | ||
630 | |||
631 | return; | ||
632 | } else | ||
633 | netif_carrier_on(dev); | ||
634 | |||
635 | pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags); | ||
636 | new_flags = flags & ~(PAS_MAC_CFG_PCFG_HD | PAS_MAC_CFG_PCFG_SPD_M | | ||
637 | PAS_MAC_CFG_PCFG_TSR_M); | ||
638 | |||
639 | if (!mac->phydev->duplex) | ||
640 | new_flags |= PAS_MAC_CFG_PCFG_HD; | ||
641 | |||
642 | switch (mac->phydev->speed) { | ||
643 | case 1000: | ||
644 | new_flags |= PAS_MAC_CFG_PCFG_SPD_1G | | ||
645 | PAS_MAC_CFG_PCFG_TSR_1G; | ||
646 | break; | ||
647 | case 100: | ||
648 | new_flags |= PAS_MAC_CFG_PCFG_SPD_100M | | ||
649 | PAS_MAC_CFG_PCFG_TSR_100M; | ||
650 | break; | ||
651 | case 10: | ||
652 | new_flags |= PAS_MAC_CFG_PCFG_SPD_10M | | ||
653 | PAS_MAC_CFG_PCFG_TSR_10M; | ||
654 | break; | ||
655 | default: | ||
656 | printk("Unsupported speed %d\n", mac->phydev->speed); | ||
657 | } | ||
658 | |||
659 | /* Print on link or speed/duplex change */ | ||
660 | msg = mac->link != mac->phydev->link || flags != new_flags; | ||
661 | |||
662 | mac->duplex = mac->phydev->duplex; | ||
663 | mac->speed = mac->phydev->speed; | ||
664 | mac->link = mac->phydev->link; | ||
665 | |||
666 | if (new_flags != flags) | ||
667 | pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, new_flags); | ||
668 | |||
669 | if (msg && netif_msg_link(mac)) | ||
670 | printk(KERN_INFO "%s: Link is up at %d Mbps, %s duplex.\n", | ||
671 | dev->name, mac->speed, mac->duplex ? "full" : "half"); | ||
672 | } | ||
673 | |||
674 | static int pasemi_mac_phy_init(struct net_device *dev) | ||
675 | { | ||
676 | struct pasemi_mac *mac = netdev_priv(dev); | ||
677 | struct device_node *dn, *phy_dn; | ||
678 | struct phy_device *phydev; | ||
679 | unsigned int phy_id; | ||
680 | const phandle *ph; | ||
681 | const unsigned int *prop; | ||
682 | struct resource r; | ||
683 | int ret; | ||
684 | |||
685 | dn = pci_device_to_OF_node(mac->pdev); | ||
686 | ph = of_get_property(dn, "phy-handle", NULL); | ||
687 | if (!ph) | ||
688 | return -ENODEV; | ||
689 | phy_dn = of_find_node_by_phandle(*ph); | ||
690 | |||
691 | prop = of_get_property(phy_dn, "reg", NULL); | ||
692 | ret = of_address_to_resource(phy_dn->parent, 0, &r); | ||
693 | if (ret) | ||
694 | goto err; | ||
695 | |||
696 | phy_id = *prop; | ||
697 | snprintf(mac->phy_id, BUS_ID_SIZE, PHY_ID_FMT, (int)r.start, phy_id); | ||
698 | |||
699 | of_node_put(phy_dn); | ||
700 | |||
701 | mac->link = 0; | ||
702 | mac->speed = 0; | ||
703 | mac->duplex = -1; | ||
704 | |||
705 | phydev = phy_connect(dev, mac->phy_id, &pasemi_adjust_link, 0, PHY_INTERFACE_MODE_SGMII); | ||
706 | |||
707 | if (IS_ERR(phydev)) { | ||
708 | printk(KERN_ERR "%s: Could not attach to phy\n", dev->name); | ||
709 | return PTR_ERR(phydev); | ||
710 | } | ||
711 | |||
712 | mac->phydev = phydev; | ||
713 | |||
714 | return 0; | ||
715 | |||
716 | err: | ||
717 | of_node_put(phy_dn); | ||
718 | return -ENODEV; | ||
719 | } | ||
720 | |||
721 | |||
535 | static int pasemi_mac_open(struct net_device *dev) | 722 | static int pasemi_mac_open(struct net_device *dev) |
536 | { | 723 | { |
537 | struct pasemi_mac *mac = netdev_priv(dev); | 724 | struct pasemi_mac *mac = netdev_priv(dev); |
725 | int base_irq; | ||
538 | unsigned int flags; | 726 | unsigned int flags; |
539 | int ret; | 727 | int ret; |
540 | 728 | ||
@@ -558,10 +746,18 @@ static int pasemi_mac_open(struct net_device *dev) | |||
558 | flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; | 746 | flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; |
559 | 747 | ||
560 | pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch), | 748 | pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch), |
561 | PAS_IOB_DMA_RXCH_CFG_CNTTH(30)); | 749 | PAS_IOB_DMA_RXCH_CFG_CNTTH(1)); |
562 | 750 | ||
751 | pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch), | ||
752 | PAS_IOB_DMA_TXCH_CFG_CNTTH(32)); | ||
753 | |||
754 | /* Clear out any residual packet count state from firmware */ | ||
755 | pasemi_mac_restart_rx_intr(mac); | ||
756 | pasemi_mac_restart_tx_intr(mac); | ||
757 | |||
758 | /* 0xffffff is max value, about 16ms */ | ||
563 | pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, | 759 | pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, |
564 | PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000)); | 760 | PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff)); |
565 | 761 | ||
566 | pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags); | 762 | pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags); |
567 | 763 | ||
@@ -595,31 +791,50 @@ static int pasemi_mac_open(struct net_device *dev) | |||
595 | 791 | ||
596 | pasemi_mac_replenish_rx_ring(dev); | 792 | pasemi_mac_replenish_rx_ring(dev); |
597 | 793 | ||
794 | ret = pasemi_mac_phy_init(dev); | ||
795 | /* Some configs don't have PHYs (XAUI etc), so don't complain about | ||
796 | * failed init due to -ENODEV. | ||
797 | */ | ||
798 | if (ret && ret != -ENODEV) | ||
799 | dev_warn(&mac->pdev->dev, "phy init failed: %d\n", ret); | ||
800 | |||
598 | netif_start_queue(dev); | 801 | netif_start_queue(dev); |
599 | netif_poll_enable(dev); | 802 | netif_poll_enable(dev); |
600 | 803 | ||
601 | ret = request_irq(mac->dma_pdev->irq + mac->dma_txch, | 804 | /* Interrupts are a bit different for our DMA controller: While |
602 | &pasemi_mac_tx_intr, IRQF_DISABLED, | 805 | * it's got one a regular PCI device header, the interrupt there |
806 | * is really the base of the range it's using. Each tx and rx | ||
807 | * channel has it's own interrupt source. | ||
808 | */ | ||
809 | |||
810 | base_irq = virq_to_hw(mac->dma_pdev->irq); | ||
811 | |||
812 | mac->tx_irq = irq_create_mapping(NULL, base_irq + mac->dma_txch); | ||
813 | mac->rx_irq = irq_create_mapping(NULL, base_irq + 20 + mac->dma_txch); | ||
814 | |||
815 | ret = request_irq(mac->tx_irq, &pasemi_mac_tx_intr, IRQF_DISABLED, | ||
603 | mac->tx->irq_name, dev); | 816 | mac->tx->irq_name, dev); |
604 | if (ret) { | 817 | if (ret) { |
605 | dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n", | 818 | dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n", |
606 | mac->dma_pdev->irq + mac->dma_txch, ret); | 819 | base_irq + mac->dma_txch, ret); |
607 | goto out_tx_int; | 820 | goto out_tx_int; |
608 | } | 821 | } |
609 | 822 | ||
610 | ret = request_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, | 823 | ret = request_irq(mac->rx_irq, &pasemi_mac_rx_intr, IRQF_DISABLED, |
611 | &pasemi_mac_rx_intr, IRQF_DISABLED, | ||
612 | mac->rx->irq_name, dev); | 824 | mac->rx->irq_name, dev); |
613 | if (ret) { | 825 | if (ret) { |
614 | dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n", | 826 | dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n", |
615 | mac->dma_pdev->irq + 20 + mac->dma_rxch, ret); | 827 | base_irq + 20 + mac->dma_rxch, ret); |
616 | goto out_rx_int; | 828 | goto out_rx_int; |
617 | } | 829 | } |
618 | 830 | ||
831 | if (mac->phydev) | ||
832 | phy_start(mac->phydev); | ||
833 | |||
619 | return 0; | 834 | return 0; |
620 | 835 | ||
621 | out_rx_int: | 836 | out_rx_int: |
622 | free_irq(mac->dma_pdev->irq + mac->dma_txch, dev); | 837 | free_irq(mac->tx_irq, dev); |
623 | out_tx_int: | 838 | out_tx_int: |
624 | netif_poll_disable(dev); | 839 | netif_poll_disable(dev); |
625 | netif_stop_queue(dev); | 840 | netif_stop_queue(dev); |
@@ -639,6 +854,11 @@ static int pasemi_mac_close(struct net_device *dev) | |||
639 | unsigned int stat; | 854 | unsigned int stat; |
640 | int retries; | 855 | int retries; |
641 | 856 | ||
857 | if (mac->phydev) { | ||
858 | phy_stop(mac->phydev); | ||
859 | phy_disconnect(mac->phydev); | ||
860 | } | ||
861 | |||
642 | netif_stop_queue(dev); | 862 | netif_stop_queue(dev); |
643 | 863 | ||
644 | /* Clean out any pending buffers */ | 864 | /* Clean out any pending buffers */ |
@@ -660,40 +880,37 @@ static int pasemi_mac_close(struct net_device *dev) | |||
660 | pci_read_config_dword(mac->dma_pdev, | 880 | pci_read_config_dword(mac->dma_pdev, |
661 | PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), | 881 | PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), |
662 | &stat); | 882 | &stat); |
663 | if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT) | 883 | if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) |
664 | break; | 884 | break; |
665 | cond_resched(); | 885 | cond_resched(); |
666 | } | 886 | } |
667 | 887 | ||
668 | if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) { | 888 | if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT) |
669 | dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n"); | 889 | dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n"); |
670 | } | ||
671 | 890 | ||
672 | for (retries = 0; retries < MAX_RETRIES; retries++) { | 891 | for (retries = 0; retries < MAX_RETRIES; retries++) { |
673 | pci_read_config_dword(mac->dma_pdev, | 892 | pci_read_config_dword(mac->dma_pdev, |
674 | PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), | 893 | PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), |
675 | &stat); | 894 | &stat); |
676 | if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT) | 895 | if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) |
677 | break; | 896 | break; |
678 | cond_resched(); | 897 | cond_resched(); |
679 | } | 898 | } |
680 | 899 | ||
681 | if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) { | 900 | if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT) |
682 | dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n"); | 901 | dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n"); |
683 | } | ||
684 | 902 | ||
685 | for (retries = 0; retries < MAX_RETRIES; retries++) { | 903 | for (retries = 0; retries < MAX_RETRIES; retries++) { |
686 | pci_read_config_dword(mac->dma_pdev, | 904 | pci_read_config_dword(mac->dma_pdev, |
687 | PAS_DMA_RXINT_RCMDSTA(mac->dma_if), | 905 | PAS_DMA_RXINT_RCMDSTA(mac->dma_if), |
688 | &stat); | 906 | &stat); |
689 | if (stat & PAS_DMA_RXINT_RCMDSTA_ACT) | 907 | if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) |
690 | break; | 908 | break; |
691 | cond_resched(); | 909 | cond_resched(); |
692 | } | 910 | } |
693 | 911 | ||
694 | if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) { | 912 | if (stat & PAS_DMA_RXINT_RCMDSTA_ACT) |
695 | dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n"); | 913 | dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n"); |
696 | } | ||
697 | 914 | ||
698 | /* Then, disable the channel. This must be done separately from | 915 | /* Then, disable the channel. This must be done separately from |
699 | * stopping, since you can't disable when active. | 916 | * stopping, since you can't disable when active. |
@@ -706,8 +923,8 @@ static int pasemi_mac_close(struct net_device *dev) | |||
706 | pci_write_config_dword(mac->dma_pdev, | 923 | pci_write_config_dword(mac->dma_pdev, |
707 | PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0); | 924 | PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0); |
708 | 925 | ||
709 | free_irq(mac->dma_pdev->irq + mac->dma_txch, dev); | 926 | free_irq(mac->tx_irq, dev); |
710 | free_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, dev); | 927 | free_irq(mac->rx_irq, dev); |
711 | 928 | ||
712 | /* Free resources */ | 929 | /* Free resources */ |
713 | pasemi_mac_free_rx_resources(dev); | 930 | pasemi_mac_free_rx_resources(dev); |
@@ -802,6 +1019,7 @@ static struct net_device_stats *pasemi_mac_get_stats(struct net_device *dev) | |||
802 | return &mac->stats; | 1019 | return &mac->stats; |
803 | } | 1020 | } |
804 | 1021 | ||
1022 | |||
805 | static void pasemi_mac_set_rx_mode(struct net_device *dev) | 1023 | static void pasemi_mac_set_rx_mode(struct net_device *dev) |
806 | { | 1024 | { |
807 | struct pasemi_mac *mac = netdev_priv(dev); | 1025 | struct pasemi_mac *mac = netdev_priv(dev); |
@@ -826,18 +1044,17 @@ static int pasemi_mac_poll(struct net_device *dev, int *budget) | |||
826 | 1044 | ||
827 | pkts = pasemi_mac_clean_rx(mac, limit); | 1045 | pkts = pasemi_mac_clean_rx(mac, limit); |
828 | 1046 | ||
1047 | dev->quota -= pkts; | ||
1048 | *budget -= pkts; | ||
1049 | |||
829 | if (pkts < limit) { | 1050 | if (pkts < limit) { |
830 | /* all done, no more packets present */ | 1051 | /* all done, no more packets present */ |
831 | netif_rx_complete(dev); | 1052 | netif_rx_complete(dev); |
832 | 1053 | ||
833 | /* re-enable receive interrupts */ | 1054 | pasemi_mac_restart_rx_intr(mac); |
834 | pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, | ||
835 | PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000)); | ||
836 | return 0; | 1055 | return 0; |
837 | } else { | 1056 | } else { |
838 | /* used up our quantum, so reschedule */ | 1057 | /* used up our quantum, so reschedule */ |
839 | dev->quota -= pkts; | ||
840 | *budget -= pkts; | ||
841 | return 1; | 1058 | return 1; |
842 | } | 1059 | } |
843 | } | 1060 | } |
@@ -937,6 +1154,11 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
937 | mac->rx_status = &dma_status->rx_sta[mac->dma_rxch]; | 1154 | mac->rx_status = &dma_status->rx_sta[mac->dma_rxch]; |
938 | mac->tx_status = &dma_status->tx_sta[mac->dma_txch]; | 1155 | mac->tx_status = &dma_status->tx_sta[mac->dma_txch]; |
939 | 1156 | ||
1157 | mac->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); | ||
1158 | |||
1159 | /* Enable most messages by default */ | ||
1160 | mac->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; | ||
1161 | |||
940 | err = register_netdev(dev); | 1162 | err = register_netdev(dev); |
941 | 1163 | ||
942 | if (err) { | 1164 | if (err) { |
@@ -1011,9 +1233,5 @@ int pasemi_mac_init_module(void) | |||
1011 | return pci_register_driver(&pasemi_mac_driver); | 1233 | return pci_register_driver(&pasemi_mac_driver); |
1012 | } | 1234 | } |
1013 | 1235 | ||
1014 | MODULE_LICENSE("GPL"); | ||
1015 | MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>"); | ||
1016 | MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver"); | ||
1017 | |||
1018 | module_init(pasemi_mac_init_module); | 1236 | module_init(pasemi_mac_init_module); |
1019 | module_exit(pasemi_mac_cleanup_module); | 1237 | module_exit(pasemi_mac_cleanup_module); |