diff options
author | Baruch Siach <baruch@tkos.co.il> | 2010-05-17 20:45:48 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-17 20:45:48 -0400 |
commit | 380fefb2ddabd4cd5f14dbe090481f0544e65078 (patch) | |
tree | ddfc9380df76bfc85eee7eeb978a649a4b2383c3 /drivers/net/dm9000.c | |
parent | 5476b8b22589fe118f3c228d71406455002b79b1 (diff) |
dm9000: fix "BUG: spinlock recursion"
dm9000_set_rx_csum and dm9000_hash_table are called from atomic context (in
dm9000_init_dm9000), and from non-atomic context (via ethtool_ops and
net_device_ops respectively). This causes a spinlock recursion BUG. Fix this by
renaming these functions to *_unlocked for the atomic context, and make the
original functions locking wrappers for use in the non-atomic context.
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/dm9000.c')
-rw-r--r-- | drivers/net/dm9000.c | 38 |
1 files changed, 27 insertions, 11 deletions
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 254b6f724c60..abcc838e18af 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c | |||
@@ -476,17 +476,13 @@ static uint32_t dm9000_get_rx_csum(struct net_device *dev) | |||
476 | return dm->rx_csum; | 476 | return dm->rx_csum; |
477 | } | 477 | } |
478 | 478 | ||
479 | static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data) | 479 | static int dm9000_set_rx_csum_unlocked(struct net_device *dev, uint32_t data) |
480 | { | 480 | { |
481 | board_info_t *dm = to_dm9000_board(dev); | 481 | board_info_t *dm = to_dm9000_board(dev); |
482 | unsigned long flags; | ||
483 | 482 | ||
484 | if (dm->can_csum) { | 483 | if (dm->can_csum) { |
485 | dm->rx_csum = data; | 484 | dm->rx_csum = data; |
486 | |||
487 | spin_lock_irqsave(&dm->lock, flags); | ||
488 | iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0); | 485 | iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0); |
489 | spin_unlock_irqrestore(&dm->lock, flags); | ||
490 | 486 | ||
491 | return 0; | 487 | return 0; |
492 | } | 488 | } |
@@ -494,6 +490,19 @@ static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data) | |||
494 | return -EOPNOTSUPP; | 490 | return -EOPNOTSUPP; |
495 | } | 491 | } |
496 | 492 | ||
493 | static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data) | ||
494 | { | ||
495 | board_info_t *dm = to_dm9000_board(dev); | ||
496 | unsigned long flags; | ||
497 | int ret; | ||
498 | |||
499 | spin_lock_irqsave(&dm->lock, flags); | ||
500 | ret = dm9000_set_rx_csum_unlocked(dev, data); | ||
501 | spin_unlock_irqrestore(&dm->lock, flags); | ||
502 | |||
503 | return ret; | ||
504 | } | ||
505 | |||
497 | static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data) | 506 | static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data) |
498 | { | 507 | { |
499 | board_info_t *dm = to_dm9000_board(dev); | 508 | board_info_t *dm = to_dm9000_board(dev); |
@@ -722,7 +731,7 @@ static unsigned char dm9000_type_to_char(enum dm9000_type type) | |||
722 | * Set DM9000 multicast address | 731 | * Set DM9000 multicast address |
723 | */ | 732 | */ |
724 | static void | 733 | static void |
725 | dm9000_hash_table(struct net_device *dev) | 734 | dm9000_hash_table_unlocked(struct net_device *dev) |
726 | { | 735 | { |
727 | board_info_t *db = netdev_priv(dev); | 736 | board_info_t *db = netdev_priv(dev); |
728 | struct netdev_hw_addr *ha; | 737 | struct netdev_hw_addr *ha; |
@@ -730,12 +739,9 @@ dm9000_hash_table(struct net_device *dev) | |||
730 | u32 hash_val; | 739 | u32 hash_val; |
731 | u16 hash_table[4]; | 740 | u16 hash_table[4]; |
732 | u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN; | 741 | u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN; |
733 | unsigned long flags; | ||
734 | 742 | ||
735 | dm9000_dbg(db, 1, "entering %s\n", __func__); | 743 | dm9000_dbg(db, 1, "entering %s\n", __func__); |
736 | 744 | ||
737 | spin_lock_irqsave(&db->lock, flags); | ||
738 | |||
739 | for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++) | 745 | for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++) |
740 | iow(db, oft, dev->dev_addr[i]); | 746 | iow(db, oft, dev->dev_addr[i]); |
741 | 747 | ||
@@ -765,6 +771,16 @@ dm9000_hash_table(struct net_device *dev) | |||
765 | } | 771 | } |
766 | 772 | ||
767 | iow(db, DM9000_RCR, rcr); | 773 | iow(db, DM9000_RCR, rcr); |
774 | } | ||
775 | |||
776 | static void | ||
777 | dm9000_hash_table(struct net_device *dev) | ||
778 | { | ||
779 | board_info_t *db = netdev_priv(dev); | ||
780 | unsigned long flags; | ||
781 | |||
782 | spin_lock_irqsave(&db->lock, flags); | ||
783 | dm9000_hash_table_unlocked(dev); | ||
768 | spin_unlock_irqrestore(&db->lock, flags); | 784 | spin_unlock_irqrestore(&db->lock, flags); |
769 | } | 785 | } |
770 | 786 | ||
@@ -784,7 +800,7 @@ dm9000_init_dm9000(struct net_device *dev) | |||
784 | db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ | 800 | db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ |
785 | 801 | ||
786 | /* Checksum mode */ | 802 | /* Checksum mode */ |
787 | dm9000_set_rx_csum(dev, db->rx_csum); | 803 | dm9000_set_rx_csum_unlocked(dev, db->rx_csum); |
788 | 804 | ||
789 | /* GPIO0 on pre-activate PHY */ | 805 | /* GPIO0 on pre-activate PHY */ |
790 | iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */ | 806 | iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */ |
@@ -811,7 +827,7 @@ dm9000_init_dm9000(struct net_device *dev) | |||
811 | iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */ | 827 | iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */ |
812 | 828 | ||
813 | /* Set address filter table */ | 829 | /* Set address filter table */ |
814 | dm9000_hash_table(dev); | 830 | dm9000_hash_table_unlocked(dev); |
815 | 831 | ||
816 | imr = IMR_PAR | IMR_PTM | IMR_PRM; | 832 | imr = IMR_PAR | IMR_PTM | IMR_PRM; |
817 | if (db->type != TYPE_DM9000E) | 833 | if (db->type != TYPE_DM9000E) |