diff options
author | Michael Buesch <mbuesch@freenet.de> | 2006-02-12 10:47:44 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2006-03-27 11:18:32 -0500 |
commit | 77db31ea4322f2dd12dc814d6664ae96517604c0 (patch) | |
tree | 358519550cf715249ba836d06eb651d1fdf86079 /drivers/net | |
parent | 5c57807afcc28a6b8fb579ef2c79e49f0b688425 (diff) |
[PATCH] bcm43xx: Partially fix PIO code. Add Kconfig option for PIO or DMA mode (or both).
Signed-off-by: Michael Buesch <mbuesch@freenet.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/Kconfig | 18 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/Kconfig | 57 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/Makefile | 6 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx.h | 29 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_dma.h | 46 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_main.c | 69 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 383 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_pio.h | 78 |
8 files changed, 438 insertions, 248 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 3b1363c97191..5c4d7b4ece5e 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -500,23 +500,7 @@ config PRISM54 | |||
500 | will be called prism54.ko. | 500 | will be called prism54.ko. |
501 | 501 | ||
502 | source "drivers/net/wireless/hostap/Kconfig" | 502 | source "drivers/net/wireless/hostap/Kconfig" |
503 | 503 | source "drivers/net/wireless/bcm43xx/Kconfig" | |
504 | config BCM43XX | ||
505 | tristate "Broadcom BCM43xx wireless support" | ||
506 | depends on PCI && IEEE80211 && NET_RADIO && IEEE80211_SOFTMAC && EXPERIMENTAL | ||
507 | select FW_LOADER | ||
508 | ---help--- | ||
509 | This is an experimental driver for the Broadcom 43xx wireless chip, | ||
510 | found in the Apple Airport Extreme and various other devices. | ||
511 | |||
512 | config BCM43XX_DEBUG | ||
513 | bool "Broadcom BCM43xx debugging (RECOMMENDED)" | ||
514 | depends on BCM43XX | ||
515 | default y | ||
516 | ---help--- | ||
517 | Broadcom 43xx debugging messages. | ||
518 | Say Y, because the driver is still very experimental and | ||
519 | this will help you get it running. | ||
520 | 504 | ||
521 | # yes, this works even when no drivers are selected | 505 | # yes, this works even when no drivers are selected |
522 | config NET_WIRELESS | 506 | config NET_WIRELESS |
diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig new file mode 100644 index 000000000000..d8d23155ee3c --- /dev/null +++ b/drivers/net/wireless/bcm43xx/Kconfig | |||
@@ -0,0 +1,57 @@ | |||
1 | config BCM43XX | ||
2 | tristate "Broadcom BCM43xx wireless support" | ||
3 | depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL | ||
4 | select FW_LOADER | ||
5 | ---help--- | ||
6 | This is an experimental driver for the Broadcom 43xx wireless chip, | ||
7 | found in the Apple Airport Extreme and various other devices. | ||
8 | |||
9 | config BCM43XX_DEBUG | ||
10 | bool "Broadcom BCM43xx debugging (RECOMMENDED)" | ||
11 | depends on BCM43XX | ||
12 | default y | ||
13 | ---help--- | ||
14 | Broadcom 43xx debugging messages. | ||
15 | Say Y, because the driver is still very experimental and | ||
16 | this will help you get it running. | ||
17 | |||
18 | config BCM43XX_DMA | ||
19 | bool | ||
20 | config BCM43XX_PIO | ||
21 | bool | ||
22 | |||
23 | choice | ||
24 | prompt "BCM43xx data transfer mode" | ||
25 | depends on BCM43XX | ||
26 | default BCM43XX_DMA_AND_PIO | ||
27 | |||
28 | config BCM43XX_DMA_AND_PIO_MODE | ||
29 | bool "DMA + PIO" | ||
30 | select BCM43XX_DMA | ||
31 | select BCM43XX_PIO | ||
32 | ---help--- | ||
33 | Include both, Direct Memory Access (DMA) and Programmed I/O (PIO) | ||
34 | data transfer modes. | ||
35 | The actually used mode is selectable through the module | ||
36 | parameter "pio". If the module parameter is pio=0, DMA is used. | ||
37 | Otherwise PIO is used. DMA is default. | ||
38 | |||
39 | If unsure, choose this option. | ||
40 | |||
41 | config BCM43XX_DMA_MODE | ||
42 | bool "DMA (Direct Memory Access) only" | ||
43 | select BCM43XX_DMA | ||
44 | ---help--- | ||
45 | Only include Direct Memory Access (DMA). | ||
46 | This reduces the size of the driver module, by omitting the PIO code. | ||
47 | |||
48 | config BCM43XX_PIO_MODE | ||
49 | bool "PIO (Programmed I/O) only" | ||
50 | select BCM43XX_PIO | ||
51 | ---help--- | ||
52 | Only include Programmed I/O (PIO). | ||
53 | This reduces the size of the driver module, by omitting the DMA code. | ||
54 | Please note that PIO transfers are slow (compared to DMA). | ||
55 | Only use PIO, if DMA does not work for you. | ||
56 | |||
57 | endchoice | ||
diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile index e025e9f052b2..c87c1525b39f 100644 --- a/drivers/net/wireless/bcm43xx/Makefile +++ b/drivers/net/wireless/bcm43xx/Makefile | |||
@@ -1,9 +1,11 @@ | |||
1 | obj-$(CONFIG_BCM43XX) += bcm43xx.o | 1 | obj-$(CONFIG_BCM43XX) += bcm43xx.o |
2 | bcm43xx-obj-$(CONFIG_BCM43XX_DEBUG) += bcm43xx_debugfs.o | 2 | bcm43xx-obj-$(CONFIG_BCM43XX_DEBUG) += bcm43xx_debugfs.o |
3 | 3 | ||
4 | bcm43xx-objs := bcm43xx_main.o bcm43xx_dma.o \ | 4 | bcm43xx-obj-$(CONFIG_BCM43XX_DMA) += bcm43xx_dma.o |
5 | bcm43xx-obj-$(CONFIG_BCM43XX_PIO) += bcm43xx_pio.o | ||
6 | |||
7 | bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \ | ||
5 | bcm43xx_radio.o bcm43xx_phy.o \ | 8 | bcm43xx_radio.o bcm43xx_phy.o \ |
6 | bcm43xx_power.o bcm43xx_wx.o \ | 9 | bcm43xx_power.o bcm43xx_wx.o \ |
7 | bcm43xx_pio.o bcm43xx_ilt.o \ | ||
8 | bcm43xx_leds.o bcm43xx_ethtool.o \ | 10 | bcm43xx_leds.o bcm43xx_ethtool.o \ |
9 | $(bcm43xx-obj-y) | 11 | $(bcm43xx-obj-y) |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 981d563f5738..3d8ac7e952cc 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h | |||
@@ -639,7 +639,7 @@ struct bcm43xx_private { | |||
639 | u32 initialized:1, /* init_board() succeed */ | 639 | u32 initialized:1, /* init_board() succeed */ |
640 | was_initialized:1, /* for PCI suspend/resume. */ | 640 | was_initialized:1, /* for PCI suspend/resume. */ |
641 | shutting_down:1, /* free_board() in progress */ | 641 | shutting_down:1, /* free_board() in progress */ |
642 | pio_mode:1, /* PIO (if true), or DMA (if false) used. */ | 642 | __using_pio:1, /* Internal, use bcm43xx_using_pio(). */ |
643 | bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ | 643 | bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ |
644 | reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ | 644 | reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ |
645 | powersaving:1, /* TRUE if we are in PowerSaving mode. FALSE otherwise. */ | 645 | powersaving:1, /* TRUE if we are in PowerSaving mode. FALSE otherwise. */ |
@@ -749,6 +749,33 @@ struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) | |||
749 | return ieee80211softmac_priv(dev); | 749 | return ieee80211softmac_priv(dev); |
750 | } | 750 | } |
751 | 751 | ||
752 | |||
753 | /* Helper function, which returns a boolean. | ||
754 | * TRUE, if PIO is used; FALSE, if DMA is used. | ||
755 | */ | ||
756 | #if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO) | ||
757 | static inline | ||
758 | int bcm43xx_using_pio(struct bcm43xx_private *bcm) | ||
759 | { | ||
760 | return bcm->__using_pio; | ||
761 | } | ||
762 | #elif defined(CONFIG_BCM43XX_DMA) | ||
763 | static inline | ||
764 | int bcm43xx_using_pio(struct bcm43xx_private *bcm) | ||
765 | { | ||
766 | return 0; | ||
767 | } | ||
768 | #elif defined(CONFIG_BCM43XX_PIO) | ||
769 | static inline | ||
770 | int bcm43xx_using_pio(struct bcm43xx_private *bcm) | ||
771 | { | ||
772 | return 1; | ||
773 | } | ||
774 | #else | ||
775 | # error "Using neither DMA nor PIO? Confused..." | ||
776 | #endif | ||
777 | |||
778 | |||
752 | static inline | 779 | static inline |
753 | int bcm43xx_num_80211_cores(struct bcm43xx_private *bcm) | 780 | int bcm43xx_num_80211_cores(struct bcm43xx_private *bcm) |
754 | { | 781 | { |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h index 93e99d61f2e1..88ad34dff2f2 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h | |||
@@ -94,6 +94,10 @@ | |||
94 | #define BCM43xx_TXRESUME_PERCENT 50 | 94 | #define BCM43xx_TXRESUME_PERCENT 50 |
95 | 95 | ||
96 | 96 | ||
97 | |||
98 | #ifdef CONFIG_BCM43XX_DMA | ||
99 | |||
100 | |||
97 | struct sk_buff; | 101 | struct sk_buff; |
98 | struct bcm43xx_private; | 102 | struct bcm43xx_private; |
99 | struct bcm43xx_xmitstatus; | 103 | struct bcm43xx_xmitstatus; |
@@ -172,4 +176,46 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, | |||
172 | struct ieee80211_txb *txb); | 176 | struct ieee80211_txb *txb); |
173 | void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring); | 177 | void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring); |
174 | 178 | ||
179 | |||
180 | #else /* CONFIG_BCM43XX_DMA */ | ||
181 | |||
182 | |||
183 | static inline | ||
184 | int bcm43xx_dma_init(struct bcm43xx_private *bcm) | ||
185 | { | ||
186 | return 0; | ||
187 | } | ||
188 | static inline | ||
189 | void bcm43xx_dma_free(struct bcm43xx_private *bcm) | ||
190 | { | ||
191 | } | ||
192 | static inline | ||
193 | int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, | ||
194 | u16 dmacontroller_mmio_base) | ||
195 | { | ||
196 | return 0; | ||
197 | } | ||
198 | static inline | ||
199 | int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, | ||
200 | u16 dmacontroller_mmio_base) | ||
201 | { | ||
202 | return 0; | ||
203 | } | ||
204 | static inline | ||
205 | int bcm43xx_dma_tx(struct bcm43xx_private *bcm, | ||
206 | struct ieee80211_txb *txb) | ||
207 | { | ||
208 | return 0; | ||
209 | } | ||
210 | static inline | ||
211 | void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, | ||
212 | struct bcm43xx_xmitstatus *status) | ||
213 | { | ||
214 | } | ||
215 | static inline | ||
216 | void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) | ||
217 | { | ||
218 | } | ||
219 | |||
220 | #endif /* CONFIG_BCM43XX_DMA */ | ||
175 | #endif /* BCM43xx_DMA_H_ */ | 221 | #endif /* BCM43xx_DMA_H_ */ |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 4c4a2d71ca04..4e49da99818d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c | |||
@@ -62,10 +62,15 @@ MODULE_LICENSE("GPL"); | |||
62 | extern char *nvram_get(char *name); | 62 | extern char *nvram_get(char *name); |
63 | #endif | 63 | #endif |
64 | 64 | ||
65 | /* Module parameters */ | 65 | #if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO) |
66 | static int modparam_pio; | 66 | static int modparam_pio; |
67 | module_param_named(pio, modparam_pio, int, 0444); | 67 | module_param_named(pio, modparam_pio, int, 0444); |
68 | MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); | 68 | MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); |
69 | #elif defined(CONFIG_BCM43XX_DMA) | ||
70 | # define modparam_pio 0 | ||
71 | #elif defined(CONFIG_BCM43XX_PIO) | ||
72 | # define modparam_pio 1 | ||
73 | #endif | ||
69 | 74 | ||
70 | static int modparam_bad_frames_preempt; | 75 | static int modparam_bad_frames_preempt; |
71 | module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); | 76 | module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); |
@@ -1528,7 +1533,8 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy) | |||
1528 | { | 1533 | { |
1529 | u32 flags = 0x00040000; | 1534 | u32 flags = 0x00040000; |
1530 | 1535 | ||
1531 | if ((bcm43xx_core_enabled(bcm)) && (!bcm->pio_mode)) { | 1536 | if ((bcm43xx_core_enabled(bcm)) && |
1537 | !bcm43xx_using_pio(bcm)) { | ||
1532 | //FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here? | 1538 | //FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here? |
1533 | #ifndef CONFIG_BCM947XX | 1539 | #ifndef CONFIG_BCM947XX |
1534 | /* reset all used DMA controllers. */ | 1540 | /* reset all used DMA controllers. */ |
@@ -1635,7 +1641,7 @@ static inline void handle_irq_transmit_status(struct bcm43xx_private *bcm) | |||
1635 | } | 1641 | } |
1636 | //TODO: There are more (unknown) flags to test. see bcm43xx_main.h | 1642 | //TODO: There are more (unknown) flags to test. see bcm43xx_main.h |
1637 | 1643 | ||
1638 | if (bcm->pio_mode) | 1644 | if (bcm43xx_using_pio(bcm)) |
1639 | bcm43xx_pio_handle_xmitstatus(bcm, &stat); | 1645 | bcm43xx_pio_handle_xmitstatus(bcm, &stat); |
1640 | else | 1646 | else |
1641 | bcm43xx_dma_handle_xmitstatus(bcm, &stat); | 1647 | bcm43xx_dma_handle_xmitstatus(bcm, &stat); |
@@ -1933,7 +1939,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) | |||
1933 | assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE)); | 1939 | assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE)); |
1934 | assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE)); | 1940 | assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE)); |
1935 | if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) { | 1941 | if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) { |
1936 | if (bcm->pio_mode) | 1942 | if (bcm43xx_using_pio(bcm)) |
1937 | bcm43xx_pio_rx(bcm->current_core->pio->queue0); | 1943 | bcm43xx_pio_rx(bcm->current_core->pio->queue0); |
1938 | else | 1944 | else |
1939 | bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0); | 1945 | bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0); |
@@ -1941,7 +1947,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) | |||
1941 | } | 1947 | } |
1942 | if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { | 1948 | if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { |
1943 | if (likely(bcm->current_core->rev < 5)) { | 1949 | if (likely(bcm->current_core->rev < 5)) { |
1944 | if (bcm->pio_mode) | 1950 | if (bcm43xx_using_pio(bcm)) |
1945 | bcm43xx_pio_rx(bcm->current_core->pio->queue3); | 1951 | bcm43xx_pio_rx(bcm->current_core->pio->queue3); |
1946 | else | 1952 | else |
1947 | bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1); | 1953 | bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1); |
@@ -1999,7 +2005,7 @@ void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, | |||
1999 | bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) | 2005 | bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) |
2000 | & 0x0001dc00; | 2006 | & 0x0001dc00; |
2001 | 2007 | ||
2002 | if ((bcm->pio_mode) && | 2008 | if (bcm43xx_using_pio(bcm) && |
2003 | (bcm->current_core->rev < 3) && | 2009 | (bcm->current_core->rev < 3) && |
2004 | (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) { | 2010 | (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) { |
2005 | /* Apply a PIO specific workaround to the dma_reasons */ | 2011 | /* Apply a PIO specific workaround to the dma_reasons */ |
@@ -2624,7 +2630,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) | |||
2624 | value32 |= 0x100000; //FIXME: What's this? Is this correct? | 2630 | value32 |= 0x100000; //FIXME: What's this? Is this correct? |
2625 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); | 2631 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); |
2626 | 2632 | ||
2627 | if (bcm->pio_mode) { | 2633 | if (bcm43xx_using_pio(bcm)) { |
2628 | bcm43xx_write32(bcm, 0x0210, 0x00000100); | 2634 | bcm43xx_write32(bcm, 0x0210, 0x00000100); |
2629 | bcm43xx_write32(bcm, 0x0230, 0x00000100); | 2635 | bcm43xx_write32(bcm, 0x0230, 0x00000100); |
2630 | bcm43xx_write32(bcm, 0x0250, 0x00000100); | 2636 | bcm43xx_write32(bcm, 0x0250, 0x00000100); |
@@ -3123,15 +3129,12 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) | |||
3123 | if (bcm->current_core->rev >= 5) | 3129 | if (bcm->current_core->rev >= 5) |
3124 | bcm43xx_write16(bcm, 0x043C, 0x000C); | 3130 | bcm43xx_write16(bcm, 0x043C, 0x000C); |
3125 | 3131 | ||
3126 | if (!bcm->pio_mode) { | 3132 | if (bcm43xx_using_pio(bcm)) |
3127 | err = bcm43xx_dma_init(bcm); | ||
3128 | if (err) | ||
3129 | goto err_chip_cleanup; | ||
3130 | } else { | ||
3131 | err = bcm43xx_pio_init(bcm); | 3133 | err = bcm43xx_pio_init(bcm); |
3132 | if (err) | 3134 | else |
3133 | goto err_chip_cleanup; | 3135 | err = bcm43xx_dma_init(bcm); |
3134 | } | 3136 | if (err) |
3137 | goto err_chip_cleanup; | ||
3135 | bcm43xx_write16(bcm, 0x0612, 0x0050); | 3138 | bcm43xx_write16(bcm, 0x0612, 0x0050); |
3136 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); | 3139 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); |
3137 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); | 3140 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); |
@@ -4001,8 +4004,8 @@ static inline int bcm43xx_tx(struct bcm43xx_private *bcm, | |||
4001 | { | 4004 | { |
4002 | int err = -ENODEV; | 4005 | int err = -ENODEV; |
4003 | 4006 | ||
4004 | if (bcm->pio_mode) | 4007 | if (bcm43xx_using_pio(bcm)) |
4005 | err = bcm43xx_pio_transfer_txb(bcm, txb); | 4008 | err = bcm43xx_pio_tx(bcm, txb); |
4006 | else | 4009 | else |
4007 | err = bcm43xx_dma_tx(bcm, txb); | 4010 | err = bcm43xx_dma_tx(bcm, txb); |
4008 | 4011 | ||
@@ -4158,10 +4161,10 @@ static int bcm43xx_net_stop(struct net_device *net_dev) | |||
4158 | return 0; | 4161 | return 0; |
4159 | } | 4162 | } |
4160 | 4163 | ||
4161 | static void bcm43xx_init_private(struct bcm43xx_private *bcm, | 4164 | static int bcm43xx_init_private(struct bcm43xx_private *bcm, |
4162 | struct net_device *net_dev, | 4165 | struct net_device *net_dev, |
4163 | struct pci_dev *pci_dev, | 4166 | struct pci_dev *pci_dev, |
4164 | struct workqueue_struct *wq) | 4167 | struct workqueue_struct *wq) |
4165 | { | 4168 | { |
4166 | bcm->ieee = netdev_priv(net_dev); | 4169 | bcm->ieee = netdev_priv(net_dev); |
4167 | bcm->softmac = ieee80211_priv(net_dev); | 4170 | bcm->softmac = ieee80211_priv(net_dev); |
@@ -4190,13 +4193,17 @@ static void bcm43xx_init_private(struct bcm43xx_private *bcm, | |||
4190 | (unsigned long)bcm); | 4193 | (unsigned long)bcm); |
4191 | tasklet_disable_nosync(&bcm->isr_tasklet); | 4194 | tasklet_disable_nosync(&bcm->isr_tasklet); |
4192 | if (modparam_pio) { | 4195 | if (modparam_pio) { |
4193 | bcm->pio_mode = 1; | 4196 | bcm->__using_pio = 1; |
4194 | } else { | 4197 | } else { |
4195 | if (pci_set_dma_mask(pci_dev, DMA_30BIT_MASK) == 0) { | 4198 | if (pci_set_dma_mask(pci_dev, DMA_30BIT_MASK)) { |
4196 | bcm->pio_mode = 0; | 4199 | #ifdef CONFIG_BCM43XX_PIO |
4197 | } else { | ||
4198 | printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n"); | 4200 | printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n"); |
4199 | bcm->pio_mode = 1; | 4201 | bcm->__using_pio = 1; |
4202 | #else | ||
4203 | printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. " | ||
4204 | "Recompile the driver with PIO support, please.\n"); | ||
4205 | return -ENODEV; | ||
4206 | #endif /* CONFIG_BCM43XX_PIO */ | ||
4200 | } | 4207 | } |
4201 | } | 4208 | } |
4202 | bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD; | 4209 | bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD; |
@@ -4210,6 +4217,8 @@ static void bcm43xx_init_private(struct bcm43xx_private *bcm, | |||
4210 | bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr); | 4217 | bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr); |
4211 | bcm->ieee->set_security = bcm43xx_ieee80211_set_security; | 4218 | bcm->ieee->set_security = bcm43xx_ieee80211_set_security; |
4212 | bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit; | 4219 | bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit; |
4220 | |||
4221 | return 0; | ||
4213 | } | 4222 | } |
4214 | 4223 | ||
4215 | static int __devinit bcm43xx_init_one(struct pci_dev *pdev, | 4224 | static int __devinit bcm43xx_init_one(struct pci_dev *pdev, |
@@ -4261,7 +4270,9 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev, | |||
4261 | err = -ENOMEM; | 4270 | err = -ENOMEM; |
4262 | goto err_free_netdev; | 4271 | goto err_free_netdev; |
4263 | } | 4272 | } |
4264 | bcm43xx_init_private(bcm, net_dev, pdev, wq); | 4273 | err = bcm43xx_init_private(bcm, net_dev, pdev, wq); |
4274 | if (err) | ||
4275 | goto err_destroy_wq; | ||
4265 | 4276 | ||
4266 | pci_set_drvdata(pdev, net_dev); | 4277 | pci_set_drvdata(pdev, net_dev); |
4267 | 4278 | ||
@@ -4325,7 +4336,9 @@ static void bcm43xx_chip_reset(void *_bcm) | |||
4325 | bcm43xx_free_board(bcm); | 4336 | bcm43xx_free_board(bcm); |
4326 | bcm->firmware_norelease = 0; | 4337 | bcm->firmware_norelease = 0; |
4327 | bcm43xx_detach_board(bcm); | 4338 | bcm43xx_detach_board(bcm); |
4328 | bcm43xx_init_private(bcm, net_dev, pci_dev, wq); | 4339 | err = bcm43xx_init_private(bcm, net_dev, pci_dev, wq); |
4340 | if (err) | ||
4341 | goto failure; | ||
4329 | err = bcm43xx_attach_board(bcm); | 4342 | err = bcm43xx_attach_board(bcm); |
4330 | if (err) | 4343 | if (err) |
4331 | goto failure; | 4344 | goto failure; |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 9a55e9d00528..0bf4b3e26f9d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c | |||
@@ -30,81 +30,88 @@ | |||
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | 31 | ||
32 | 32 | ||
33 | static inline | 33 | static void tx_start(struct bcm43xx_pioqueue *queue) |
34 | u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue, | ||
35 | u16 offset) | ||
36 | { | 34 | { |
37 | return bcm43xx_read16(queue->bcm, queue->mmio_base + offset); | 35 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, |
36 | BCM43xx_PIO_TXCTL_INIT); | ||
38 | } | 37 | } |
39 | 38 | ||
40 | static inline | 39 | static void tx_octet(struct bcm43xx_pioqueue *queue, |
41 | void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue, | 40 | u8 octet) |
42 | u16 offset, u16 value) | ||
43 | { | 41 | { |
44 | bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value); | 42 | if (queue->need_workarounds) { |
43 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, | ||
44 | octet); | ||
45 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, | ||
46 | BCM43xx_PIO_TXCTL_WRITEHI); | ||
47 | } else { | ||
48 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, | ||
49 | BCM43xx_PIO_TXCTL_WRITEHI); | ||
50 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, | ||
51 | octet); | ||
52 | } | ||
45 | } | 53 | } |
46 | 54 | ||
47 | static inline | 55 | static u16 tx_get_next_word(struct bcm43xx_txhdr *txhdr, |
48 | void tx_start(struct bcm43xx_pioqueue *queue) | 56 | const u8 *packet, |
57 | unsigned int *pos) | ||
49 | { | 58 | { |
50 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_INIT); | 59 | const u8 *source; |
51 | } | 60 | unsigned int i = *pos; |
61 | u16 ret; | ||
52 | 62 | ||
53 | static inline | 63 | if (i < sizeof(*txhdr)) { |
54 | void tx_octet(struct bcm43xx_pioqueue *queue, | 64 | source = (const u8 *)txhdr; |
55 | u8 octet) | ||
56 | { | ||
57 | if (queue->bcm->current_core->rev < 3) { | ||
58 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, octet); | ||
59 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_WRITEHI); | ||
60 | } else { | 65 | } else { |
61 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_WRITEHI); | 66 | source = packet; |
62 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, octet); | 67 | i -= sizeof(*txhdr); |
63 | } | 68 | } |
69 | ret = le16_to_cpu( *((u16 *)(source + i)) ); | ||
70 | *pos += 2; | ||
71 | |||
72 | return ret; | ||
64 | } | 73 | } |
65 | 74 | ||
66 | static inline | 75 | static void tx_data(struct bcm43xx_pioqueue *queue, |
67 | void tx_data(struct bcm43xx_pioqueue *queue, | 76 | struct bcm43xx_txhdr *txhdr, |
68 | u8 *packet, | 77 | const u8 *packet, |
69 | unsigned int octets) | 78 | unsigned int octets) |
70 | { | 79 | { |
71 | u16 data; | 80 | u16 data; |
72 | unsigned int i = 0; | 81 | unsigned int i = 0; |
73 | 82 | ||
74 | if (queue->bcm->current_core->rev < 3) { | 83 | if (queue->need_workarounds) { |
75 | data = be16_to_cpu( *((u16 *)packet) ); | 84 | data = tx_get_next_word(txhdr, packet, &i); |
76 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); | 85 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); |
77 | i += 2; | ||
78 | } | 86 | } |
79 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, | 87 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, |
80 | BCM43xx_PIO_TXCTL_WRITELO | BCM43xx_PIO_TXCTL_WRITEHI); | 88 | BCM43xx_PIO_TXCTL_WRITELO | |
81 | for ( ; i < octets - 1; i += 2) { | 89 | BCM43xx_PIO_TXCTL_WRITEHI); |
82 | data = be16_to_cpu( *((u16 *)(packet + i)) ); | 90 | while (i < octets - 1) { |
91 | data = tx_get_next_word(txhdr, packet, &i); | ||
83 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); | 92 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); |
84 | } | 93 | } |
85 | if (octets % 2) | 94 | if (octets % 2) |
86 | tx_octet(queue, packet[octets - 1]); | 95 | tx_octet(queue, packet[octets - sizeof(*txhdr) - 1]); |
87 | } | 96 | } |
88 | 97 | ||
89 | static inline | 98 | static void tx_complete(struct bcm43xx_pioqueue *queue, |
90 | void tx_complete(struct bcm43xx_pioqueue *queue, | 99 | struct sk_buff *skb) |
91 | struct sk_buff *skb) | ||
92 | { | 100 | { |
93 | u16 data; | 101 | if (queue->need_workarounds) { |
94 | 102 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, | |
95 | if (queue->bcm->current_core->rev < 3) { | 103 | skb->data[skb->len - 1]); |
96 | data = be16_to_cpu( *((u16 *)(skb->data + skb->len - 2)) ); | ||
97 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); | ||
98 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, | 104 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, |
99 | BCM43xx_PIO_TXCTL_WRITEHI | BCM43xx_PIO_TXCTL_COMPLETE); | 105 | BCM43xx_PIO_TXCTL_WRITEHI | |
106 | BCM43xx_PIO_TXCTL_COMPLETE); | ||
100 | } else { | 107 | } else { |
101 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_COMPLETE); | 108 | bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, |
109 | BCM43xx_PIO_TXCTL_COMPLETE); | ||
102 | } | 110 | } |
103 | } | 111 | } |
104 | 112 | ||
105 | static inline | 113 | static u16 generate_cookie(struct bcm43xx_pioqueue *queue, |
106 | u16 generate_cookie(struct bcm43xx_pioqueue *queue, | 114 | int packetindex) |
107 | int packetindex) | ||
108 | { | 115 | { |
109 | u16 cookie = 0x0000; | 116 | u16 cookie = 0x0000; |
110 | 117 | ||
@@ -113,8 +120,6 @@ u16 generate_cookie(struct bcm43xx_pioqueue *queue, | |||
113 | * for the packet index (in the cache). | 120 | * for the packet index (in the cache). |
114 | */ | 121 | */ |
115 | switch (queue->mmio_base) { | 122 | switch (queue->mmio_base) { |
116 | default: | ||
117 | assert(0); | ||
118 | case BCM43xx_MMIO_PIO1_BASE: | 123 | case BCM43xx_MMIO_PIO1_BASE: |
119 | break; | 124 | break; |
120 | case BCM43xx_MMIO_PIO2_BASE: | 125 | case BCM43xx_MMIO_PIO2_BASE: |
@@ -126,6 +131,8 @@ u16 generate_cookie(struct bcm43xx_pioqueue *queue, | |||
126 | case BCM43xx_MMIO_PIO4_BASE: | 131 | case BCM43xx_MMIO_PIO4_BASE: |
127 | cookie = 0x3000; | 132 | cookie = 0x3000; |
128 | break; | 133 | break; |
134 | default: | ||
135 | assert(0); | ||
129 | } | 136 | } |
130 | assert(((u16)packetindex & 0xF000) == 0x0000); | 137 | assert(((u16)packetindex & 0xF000) == 0x0000); |
131 | cookie |= (u16)packetindex; | 138 | cookie |= (u16)packetindex; |
@@ -133,66 +140,75 @@ u16 generate_cookie(struct bcm43xx_pioqueue *queue, | |||
133 | return cookie; | 140 | return cookie; |
134 | } | 141 | } |
135 | 142 | ||
136 | static inline | 143 | static |
137 | struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm, | 144 | struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm, |
138 | u16 cookie, | 145 | u16 cookie, |
139 | struct bcm43xx_pio_txpacket **packet) | 146 | struct bcm43xx_pio_txpacket **packet) |
140 | { | 147 | { |
148 | struct bcm43xx_pio *pio = bcm->current_core->pio; | ||
141 | struct bcm43xx_pioqueue *queue = NULL; | 149 | struct bcm43xx_pioqueue *queue = NULL; |
142 | int packetindex; | 150 | int packetindex; |
143 | 151 | ||
144 | switch (cookie & 0xF000) { | 152 | switch (cookie & 0xF000) { |
145 | case 0x0000: | 153 | case 0x0000: |
146 | queue = bcm->current_core->pio->queue0; | 154 | queue = pio->queue0; |
147 | break; | 155 | break; |
148 | case 0x1000: | 156 | case 0x1000: |
149 | queue = bcm->current_core->pio->queue1; | 157 | queue = pio->queue1; |
150 | break; | 158 | break; |
151 | case 0x2000: | 159 | case 0x2000: |
152 | queue = bcm->current_core->pio->queue2; | 160 | queue = pio->queue2; |
153 | break; | 161 | break; |
154 | case 0x3000: | 162 | case 0x3000: |
155 | queue = bcm->current_core->pio->queue3; | 163 | queue = pio->queue3; |
156 | break; | 164 | break; |
157 | default: | 165 | default: |
158 | assert(0); | 166 | assert(0); |
159 | } | 167 | } |
160 | |||
161 | packetindex = (cookie & 0x0FFF); | 168 | packetindex = (cookie & 0x0FFF); |
162 | assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS); | 169 | assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS); |
163 | *packet = queue->__tx_packets_cache + packetindex; | 170 | *packet = &(queue->tx_packets_cache[packetindex]); |
164 | 171 | ||
165 | return queue; | 172 | return queue; |
166 | } | 173 | } |
167 | 174 | ||
168 | static inline | 175 | static void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue, |
169 | void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue, | 176 | struct sk_buff *skb, |
170 | struct sk_buff *skb, | 177 | struct bcm43xx_pio_txpacket *packet) |
171 | struct bcm43xx_pio_txpacket *packet) | ||
172 | { | 178 | { |
179 | struct bcm43xx_txhdr txhdr; | ||
173 | unsigned int octets; | 180 | unsigned int octets; |
174 | 181 | ||
175 | assert(skb_shinfo(skb)->nr_frags == 0); | 182 | assert(skb_shinfo(skb)->nr_frags == 0); |
176 | assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); | ||
177 | |||
178 | __skb_push(skb, sizeof(struct bcm43xx_txhdr)); | ||
179 | bcm43xx_generate_txhdr(queue->bcm, | 183 | bcm43xx_generate_txhdr(queue->bcm, |
180 | (struct bcm43xx_txhdr *)skb->data, | 184 | &txhdr, skb->data, skb->len, |
181 | skb->data + sizeof(struct bcm43xx_txhdr), | ||
182 | skb->len - sizeof(struct bcm43xx_txhdr), | ||
183 | (packet->xmitted_frags == 0), | 185 | (packet->xmitted_frags == 0), |
184 | generate_cookie(queue, pio_txpacket_getindex(packet))); | 186 | generate_cookie(queue, pio_txpacket_getindex(packet))); |
185 | 187 | ||
186 | tx_start(queue); | 188 | tx_start(queue); |
187 | octets = skb->len; | 189 | octets = skb->len + sizeof(txhdr); |
188 | if (queue->bcm->current_core->rev < 3) //FIXME: && this is the last packet in the queue. | 190 | if (queue->need_workarounds) |
189 | octets -= 2; | 191 | octets--; |
190 | tx_data(queue, (u8 *)skb->data, octets); | 192 | tx_data(queue, &txhdr, (u8 *)skb->data, octets); |
191 | tx_complete(queue, skb); | 193 | tx_complete(queue, skb); |
192 | } | 194 | } |
193 | 195 | ||
194 | static inline | 196 | static void free_txpacket(struct bcm43xx_pio_txpacket *packet, |
195 | int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) | 197 | int irq_context) |
198 | { | ||
199 | struct bcm43xx_pioqueue *queue = packet->queue; | ||
200 | |||
201 | ieee80211_txb_free(packet->txb); | ||
202 | list_move(&packet->list, &queue->txfree); | ||
203 | queue->nr_txfree++; | ||
204 | |||
205 | assert(queue->tx_devq_used >= packet->xmitted_octets); | ||
206 | assert(queue->tx_devq_packets >= packet->xmitted_frags); | ||
207 | queue->tx_devq_used -= packet->xmitted_octets; | ||
208 | queue->tx_devq_packets -= packet->xmitted_frags; | ||
209 | } | ||
210 | |||
211 | static int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) | ||
196 | { | 212 | { |
197 | struct bcm43xx_pioqueue *queue = packet->queue; | 213 | struct bcm43xx_pioqueue *queue = packet->queue; |
198 | struct ieee80211_txb *txb = packet->txb; | 214 | struct ieee80211_txb *txb = packet->txb; |
@@ -204,12 +220,11 @@ int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) | |||
204 | skb = txb->fragments[i]; | 220 | skb = txb->fragments[i]; |
205 | 221 | ||
206 | octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr); | 222 | octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr); |
207 | |||
208 | assert(queue->tx_devq_size >= octets); | 223 | assert(queue->tx_devq_size >= octets); |
209 | assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS); | 224 | assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS); |
210 | assert(queue->tx_devq_used <= queue->tx_devq_size); | 225 | assert(queue->tx_devq_used <= queue->tx_devq_size); |
211 | /* Check if there is sufficient free space on the device | 226 | /* Check if there is sufficient free space on the device |
212 | * TX queue. If not, return and let the TX-work-handler | 227 | * TX queue. If not, return and let the TX tasklet |
213 | * retry later. | 228 | * retry later. |
214 | */ | 229 | */ |
215 | if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS) | 230 | if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS) |
@@ -234,28 +249,15 @@ int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) | |||
234 | return 0; | 249 | return 0; |
235 | } | 250 | } |
236 | 251 | ||
237 | static void free_txpacket(struct bcm43xx_pio_txpacket *packet) | 252 | static void tx_tasklet(unsigned long d) |
238 | { | 253 | { |
239 | struct bcm43xx_pioqueue *queue = packet->queue; | 254 | struct bcm43xx_pioqueue *queue = (struct bcm43xx_pioqueue *)d; |
240 | 255 | struct bcm43xx_private *bcm = queue->bcm; | |
241 | ieee80211_txb_free(packet->txb); | ||
242 | |||
243 | list_move(&packet->list, &packet->queue->txfree); | ||
244 | |||
245 | assert(queue->tx_devq_used >= packet->xmitted_octets); | ||
246 | queue->tx_devq_used -= packet->xmitted_octets; | ||
247 | assert(queue->tx_devq_packets >= packet->xmitted_frags); | ||
248 | queue->tx_devq_packets -= packet->xmitted_frags; | ||
249 | } | ||
250 | |||
251 | static void txwork_handler(void *d) | ||
252 | { | ||
253 | struct bcm43xx_pioqueue *queue = d; | ||
254 | unsigned long flags; | 256 | unsigned long flags; |
255 | struct bcm43xx_pio_txpacket *packet, *tmp_packet; | 257 | struct bcm43xx_pio_txpacket *packet, *tmp_packet; |
256 | int err; | 258 | int err; |
257 | 259 | ||
258 | spin_lock_irqsave(&queue->txlock, flags); | 260 | spin_lock_irqsave(&bcm->lock, flags); |
259 | list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { | 261 | list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { |
260 | assert(packet->xmitted_frags < packet->txb->nr_frags); | 262 | assert(packet->xmitted_frags < packet->txb->nr_frags); |
261 | if (packet->xmitted_frags == 0) { | 263 | if (packet->xmitted_frags == 0) { |
@@ -270,22 +272,22 @@ static void txwork_handler(void *d) | |||
270 | skb = packet->txb->fragments[i]; | 272 | skb = packet->txb->fragments[i]; |
271 | if (unlikely(skb->len > queue->tx_devq_size)) { | 273 | if (unlikely(skb->len > queue->tx_devq_size)) { |
272 | dprintkl(KERN_ERR PFX "PIO TX device queue too small. " | 274 | dprintkl(KERN_ERR PFX "PIO TX device queue too small. " |
273 | "Dropping packet...\n"); | 275 | "Dropping packet.\n"); |
274 | free_txpacket(packet); | 276 | free_txpacket(packet, 1); |
275 | goto next_packet; | 277 | goto next_packet; |
276 | } | 278 | } |
277 | } | 279 | } |
278 | } | 280 | } |
279 | /* Now try to transmit the packet. | 281 | /* Try to transmit the packet. |
280 | * This may not completely succeed. | 282 | * This may not completely succeed. |
281 | */ | 283 | */ |
282 | err = pio_tx_packet(packet); | 284 | err = pio_tx_packet(packet); |
283 | if (err) | 285 | if (err) |
284 | break; | 286 | break; |
285 | next_packet: | 287 | next_packet: |
286 | continue; | 288 | continue; |
287 | } | 289 | } |
288 | spin_unlock_irqrestore(&queue->txlock, flags); | 290 | spin_unlock_irqrestore(&bcm->lock, flags); |
289 | } | 291 | } |
290 | 292 | ||
291 | static void setup_txqueues(struct bcm43xx_pioqueue *queue) | 293 | static void setup_txqueues(struct bcm43xx_pioqueue *queue) |
@@ -293,8 +295,9 @@ static void setup_txqueues(struct bcm43xx_pioqueue *queue) | |||
293 | struct bcm43xx_pio_txpacket *packet; | 295 | struct bcm43xx_pio_txpacket *packet; |
294 | int i; | 296 | int i; |
295 | 297 | ||
298 | queue->nr_txfree = BCM43xx_PIO_MAXTXPACKETS; | ||
296 | for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) { | 299 | for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) { |
297 | packet = queue->__tx_packets_cache + i; | 300 | packet = &(queue->tx_packets_cache[i]); |
298 | 301 | ||
299 | packet->queue = queue; | 302 | packet->queue = queue; |
300 | INIT_LIST_HEAD(&packet->list); | 303 | INIT_LIST_HEAD(&packet->list); |
@@ -311,19 +314,19 @@ struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm, | |||
311 | u32 value; | 314 | u32 value; |
312 | u16 qsize; | 315 | u16 qsize; |
313 | 316 | ||
314 | queue = kmalloc(sizeof(*queue), GFP_KERNEL); | 317 | queue = kzalloc(sizeof(*queue), GFP_KERNEL); |
315 | if (!queue) | 318 | if (!queue) |
316 | goto out; | 319 | goto out; |
317 | memset(queue, 0, sizeof(*queue)); | ||
318 | 320 | ||
319 | queue->bcm = bcm; | 321 | queue->bcm = bcm; |
320 | queue->mmio_base = pio_mmio_base; | 322 | queue->mmio_base = pio_mmio_base; |
323 | queue->need_workarounds = (bcm->current_core->rev < 3); | ||
321 | 324 | ||
322 | INIT_LIST_HEAD(&queue->txfree); | 325 | INIT_LIST_HEAD(&queue->txfree); |
323 | INIT_LIST_HEAD(&queue->txqueue); | 326 | INIT_LIST_HEAD(&queue->txqueue); |
324 | INIT_LIST_HEAD(&queue->txrunning); | 327 | INIT_LIST_HEAD(&queue->txrunning); |
325 | spin_lock_init(&queue->txlock); | 328 | tasklet_init(&queue->txtask, tx_tasklet, |
326 | INIT_WORK(&queue->txwork, txwork_handler, queue); | 329 | (unsigned long)queue); |
327 | 330 | ||
328 | value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); | 331 | value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); |
329 | value |= BCM43xx_SBF_XFER_REG_BYTESWAP; | 332 | value |= BCM43xx_SBF_XFER_REG_BYTESWAP; |
@@ -331,7 +334,7 @@ struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm, | |||
331 | 334 | ||
332 | qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE); | 335 | qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE); |
333 | if (qsize <= BCM43xx_PIO_TXQADJUST) { | 336 | if (qsize <= BCM43xx_PIO_TXQADJUST) { |
334 | printk(KERN_ERR PFX "PIO tx queue too small (%u)\n", qsize); | 337 | printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n", qsize); |
335 | goto err_freequeue; | 338 | goto err_freequeue; |
336 | } | 339 | } |
337 | qsize -= BCM43xx_PIO_TXQADJUST; | 340 | qsize -= BCM43xx_PIO_TXQADJUST; |
@@ -354,13 +357,12 @@ static void cancel_transfers(struct bcm43xx_pioqueue *queue) | |||
354 | 357 | ||
355 | netif_tx_disable(queue->bcm->net_dev); | 358 | netif_tx_disable(queue->bcm->net_dev); |
356 | assert(queue->bcm->shutting_down); | 359 | assert(queue->bcm->shutting_down); |
357 | cancel_delayed_work(&queue->txwork); | 360 | tasklet_disable(&queue->txtask); |
358 | flush_workqueue(queue->bcm->workqueue); | ||
359 | 361 | ||
360 | list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) | 362 | list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) |
361 | free_txpacket(packet); | 363 | free_txpacket(packet, 0); |
362 | list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) | 364 | list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) |
363 | free_txpacket(packet); | 365 | free_txpacket(packet, 0); |
364 | } | 366 | } |
365 | 367 | ||
366 | static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) | 368 | static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) |
@@ -374,40 +376,43 @@ static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) | |||
374 | 376 | ||
375 | void bcm43xx_pio_free(struct bcm43xx_private *bcm) | 377 | void bcm43xx_pio_free(struct bcm43xx_private *bcm) |
376 | { | 378 | { |
377 | bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue3); | 379 | struct bcm43xx_pio *pio = bcm->current_core->pio; |
378 | bcm->current_core->pio->queue3 = NULL; | 380 | |
379 | bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue2); | 381 | bcm43xx_destroy_pioqueue(pio->queue3); |
380 | bcm->current_core->pio->queue2 = NULL; | 382 | pio->queue3 = NULL; |
381 | bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue1); | 383 | bcm43xx_destroy_pioqueue(pio->queue2); |
382 | bcm->current_core->pio->queue1 = NULL; | 384 | pio->queue2 = NULL; |
383 | bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue0); | 385 | bcm43xx_destroy_pioqueue(pio->queue1); |
384 | bcm->current_core->pio->queue0 = NULL; | 386 | pio->queue1 = NULL; |
387 | bcm43xx_destroy_pioqueue(pio->queue0); | ||
388 | pio->queue0 = NULL; | ||
385 | } | 389 | } |
386 | 390 | ||
387 | int bcm43xx_pio_init(struct bcm43xx_private *bcm) | 391 | int bcm43xx_pio_init(struct bcm43xx_private *bcm) |
388 | { | 392 | { |
393 | struct bcm43xx_pio *pio = bcm->current_core->pio; | ||
389 | struct bcm43xx_pioqueue *queue; | 394 | struct bcm43xx_pioqueue *queue; |
390 | int err = -ENOMEM; | 395 | int err = -ENOMEM; |
391 | 396 | ||
392 | queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE); | 397 | queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE); |
393 | if (!queue) | 398 | if (!queue) |
394 | goto out; | 399 | goto out; |
395 | bcm->current_core->pio->queue0 = queue; | 400 | pio->queue0 = queue; |
396 | 401 | ||
397 | queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE); | 402 | queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE); |
398 | if (!queue) | 403 | if (!queue) |
399 | goto err_destroy0; | 404 | goto err_destroy0; |
400 | bcm->current_core->pio->queue1 = queue; | 405 | pio->queue1 = queue; |
401 | 406 | ||
402 | queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE); | 407 | queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE); |
403 | if (!queue) | 408 | if (!queue) |
404 | goto err_destroy1; | 409 | goto err_destroy1; |
405 | bcm->current_core->pio->queue2 = queue; | 410 | pio->queue2 = queue; |
406 | 411 | ||
407 | queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE); | 412 | queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE); |
408 | if (!queue) | 413 | if (!queue) |
409 | goto err_destroy2; | 414 | goto err_destroy2; |
410 | bcm->current_core->pio->queue3 = queue; | 415 | pio->queue3 = queue; |
411 | 416 | ||
412 | if (bcm->current_core->rev < 3) | 417 | if (bcm->current_core->rev < 3) |
413 | bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND; | 418 | bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND; |
@@ -418,41 +423,38 @@ out: | |||
418 | return err; | 423 | return err; |
419 | 424 | ||
420 | err_destroy2: | 425 | err_destroy2: |
421 | bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue2); | 426 | bcm43xx_destroy_pioqueue(pio->queue2); |
422 | bcm->current_core->pio->queue2 = NULL; | 427 | pio->queue2 = NULL; |
423 | err_destroy1: | 428 | err_destroy1: |
424 | bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue1); | 429 | bcm43xx_destroy_pioqueue(pio->queue1); |
425 | bcm->current_core->pio->queue1 = NULL; | 430 | pio->queue1 = NULL; |
426 | err_destroy0: | 431 | err_destroy0: |
427 | bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue0); | 432 | bcm43xx_destroy_pioqueue(pio->queue0); |
428 | bcm->current_core->pio->queue0 = NULL; | 433 | pio->queue0 = NULL; |
429 | goto out; | 434 | goto out; |
430 | } | 435 | } |
431 | 436 | ||
432 | static inline | 437 | int bcm43xx_pio_tx(struct bcm43xx_private *bcm, |
433 | int pio_transfer_txb(struct bcm43xx_pioqueue *queue, | 438 | struct ieee80211_txb *txb) |
434 | struct ieee80211_txb *txb) | ||
435 | { | 439 | { |
440 | struct bcm43xx_pioqueue *queue = bcm->current_core->pio->queue1; | ||
436 | struct bcm43xx_pio_txpacket *packet; | 441 | struct bcm43xx_pio_txpacket *packet; |
437 | unsigned long flags; | ||
438 | u16 tmp; | 442 | u16 tmp; |
439 | 443 | ||
440 | spin_lock_irqsave(&queue->txlock, flags); | ||
441 | assert(!queue->tx_suspended); | 444 | assert(!queue->tx_suspended); |
442 | assert(!list_empty(&queue->txfree)); | 445 | assert(!list_empty(&queue->txfree)); |
443 | 446 | ||
444 | tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL); | 447 | tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL); |
445 | if (tmp & BCM43xx_PIO_TXCTL_SUSPEND) { | 448 | if (tmp & BCM43xx_PIO_TXCTL_SUSPEND) |
446 | spin_unlock_irqrestore(&queue->txlock, flags); | ||
447 | return -EBUSY; | 449 | return -EBUSY; |
448 | } | ||
449 | 450 | ||
450 | packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list); | 451 | packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list); |
451 | |||
452 | packet->txb = txb; | 452 | packet->txb = txb; |
453 | list_move_tail(&packet->list, &queue->txqueue); | ||
454 | packet->xmitted_octets = 0; | ||
455 | packet->xmitted_frags = 0; | 453 | packet->xmitted_frags = 0; |
454 | packet->xmitted_octets = 0; | ||
455 | list_move_tail(&packet->list, &queue->txqueue); | ||
456 | queue->nr_txfree--; | ||
457 | assert(queue->nr_txfree < BCM43xx_PIO_MAXTXPACKETS); | ||
456 | 458 | ||
457 | /* Suspend TX, if we are out of packets in the "free" queue. */ | 459 | /* Suspend TX, if we are out of packets in the "free" queue. */ |
458 | if (unlikely(list_empty(&queue->txfree))) { | 460 | if (unlikely(list_empty(&queue->txfree))) { |
@@ -460,69 +462,66 @@ int pio_transfer_txb(struct bcm43xx_pioqueue *queue, | |||
460 | queue->tx_suspended = 1; | 462 | queue->tx_suspended = 1; |
461 | } | 463 | } |
462 | 464 | ||
463 | spin_unlock_irqrestore(&queue->txlock, flags); | 465 | tasklet_schedule(&queue->txtask); |
464 | queue_work(queue->bcm->workqueue, &queue->txwork); | ||
465 | 466 | ||
466 | return 0; | 467 | return 0; |
467 | } | 468 | } |
468 | 469 | ||
469 | int fastcall bcm43xx_pio_transfer_txb(struct bcm43xx_private *bcm, | 470 | void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, |
470 | struct ieee80211_txb *txb) | 471 | struct bcm43xx_xmitstatus *status) |
471 | { | ||
472 | return pio_transfer_txb(bcm->current_core->pio->queue1, txb); | ||
473 | } | ||
474 | |||
475 | void fastcall | ||
476 | bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, | ||
477 | struct bcm43xx_xmitstatus *status) | ||
478 | { | 472 | { |
479 | struct bcm43xx_pioqueue *queue; | 473 | struct bcm43xx_pioqueue *queue; |
480 | struct bcm43xx_pio_txpacket *packet; | 474 | struct bcm43xx_pio_txpacket *packet; |
481 | unsigned long flags; | ||
482 | 475 | ||
483 | queue = parse_cookie(bcm, status->cookie, &packet); | 476 | queue = parse_cookie(bcm, status->cookie, &packet); |
484 | assert(queue); | 477 | assert(queue); |
485 | spin_lock_irqsave(&queue->txlock, flags); | 478 | //TODO |
486 | free_txpacket(packet); | 479 | if (!queue) |
480 | return; | ||
481 | free_txpacket(packet, 1); | ||
487 | if (unlikely(queue->tx_suspended)) { | 482 | if (unlikely(queue->tx_suspended)) { |
488 | queue->tx_suspended = 0; | 483 | queue->tx_suspended = 0; |
489 | netif_wake_queue(queue->bcm->net_dev); | 484 | netif_wake_queue(queue->bcm->net_dev); |
490 | } | 485 | } |
491 | 486 | /* If there are packets on the txqueue, poke the tasklet. */ | |
492 | /* If there are packets on the txqueue, | 487 | if (!list_empty(&queue->txqueue)) |
493 | * start the work handler again. | 488 | tasklet_schedule(&queue->txtask); |
494 | */ | ||
495 | if (!list_empty(&queue->txqueue)) { | ||
496 | queue_work(queue->bcm->workqueue, | ||
497 | &queue->txwork); | ||
498 | } | ||
499 | spin_unlock_irqrestore(&queue->txlock, flags); | ||
500 | } | 489 | } |
501 | 490 | ||
502 | static void pio_rx_error(struct bcm43xx_pioqueue *queue, | 491 | static void pio_rx_error(struct bcm43xx_pioqueue *queue, |
492 | int clear_buffers, | ||
503 | const char *error) | 493 | const char *error) |
504 | { | 494 | { |
505 | printk("PIO RX error: %s\n", error); | 495 | int i; |
506 | bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_READY); | 496 | |
497 | printkl("PIO RX error: %s\n", error); | ||
498 | bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, | ||
499 | BCM43xx_PIO_RXCTL_READY); | ||
500 | if (clear_buffers) { | ||
501 | assert(queue->mmio_base == BCM43xx_MMIO_PIO1_BASE); | ||
502 | for (i = 0; i < 15; i++) { | ||
503 | /* Dummy read. */ | ||
504 | bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); | ||
505 | } | ||
506 | } | ||
507 | } | 507 | } |
508 | 508 | ||
509 | void fastcall | 509 | void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) |
510 | bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) | ||
511 | { | 510 | { |
512 | u16 preamble[21] = { 0 }; | 511 | u16 preamble[21] = { 0 }; |
513 | struct bcm43xx_rxhdr *rxhdr; | 512 | struct bcm43xx_rxhdr *rxhdr; |
514 | u16 tmp; | 513 | u16 tmp, len, rxflags2; |
515 | u16 len; | 514 | int i, preamble_readwords; |
516 | int i, err; | ||
517 | int preamble_readwords; | ||
518 | struct sk_buff *skb; | 515 | struct sk_buff *skb; |
519 | 516 | ||
517 | return; | ||
520 | tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); | 518 | tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); |
521 | if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) { | 519 | if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) { |
522 | dprintkl(KERN_ERR PFX "PIO RX: No data available\n"); | 520 | dprintkl(KERN_ERR PFX "PIO RX: No data available\n");//TODO: remove this printk. |
523 | return; | 521 | return; |
524 | } | 522 | } |
525 | bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_DATAAVAILABLE); | 523 | bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, |
524 | BCM43xx_PIO_RXCTL_DATAAVAILABLE); | ||
526 | 525 | ||
527 | for (i = 0; i < 10; i++) { | 526 | for (i = 0; i < 10; i++) { |
528 | tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); | 527 | tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); |
@@ -534,13 +533,14 @@ bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) | |||
534 | return; | 533 | return; |
535 | data_ready: | 534 | data_ready: |
536 | 535 | ||
536 | //FIXME: endianess in this function. | ||
537 | len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); | 537 | len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); |
538 | if (unlikely(len > 0x700)) { | 538 | if (unlikely(len > 0x700)) { |
539 | pio_rx_error(queue, "len > 0x700"); | 539 | pio_rx_error(queue, 0, "len > 0x700"); |
540 | return; | 540 | return; |
541 | } | 541 | } |
542 | if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) { | 542 | if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) { |
543 | pio_rx_error(queue, "len == 0"); | 543 | pio_rx_error(queue, 0, "len == 0"); |
544 | return; | 544 | return; |
545 | } | 545 | } |
546 | preamble[0] = cpu_to_le16(len); | 546 | preamble[0] = cpu_to_le16(len); |
@@ -550,28 +550,38 @@ data_ready: | |||
550 | preamble_readwords = 18 / sizeof(u16); | 550 | preamble_readwords = 18 / sizeof(u16); |
551 | for (i = 0; i < preamble_readwords; i++) { | 551 | for (i = 0; i < preamble_readwords; i++) { |
552 | tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); | 552 | tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); |
553 | preamble[i + 1] = cpu_to_be16(tmp); | 553 | preamble[i + 1] = cpu_to_be16(tmp);//FIXME? |
554 | } | 554 | } |
555 | rxhdr = (struct bcm43xx_rxhdr *)preamble; | 555 | rxhdr = (struct bcm43xx_rxhdr *)preamble; |
556 | if (unlikely(rxhdr->flags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) { | 556 | rxflags2 = le16_to_cpu(rxhdr->flags2); |
557 | pio_rx_error(queue, "invalid frame"); | 557 | if (unlikely(rxflags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) { |
558 | if (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE) { | 558 | pio_rx_error(queue, |
559 | for (i = 0; i < 15; i++) | 559 | (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE), |
560 | bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); /* dummy read. */ | 560 | "invalid frame"); |
561 | } | ||
562 | return; | 561 | return; |
563 | } | 562 | } |
564 | //FIXME | ||
565 | #if 0 | ||
566 | if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) { | 563 | if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) { |
567 | bcm43xx_rx_transmitstatus(queue->bcm, | 564 | /* We received an xmit status. */ |
568 | (const struct bcm43xx_hwxmitstatus *)(preamble + 1)); | 565 | struct bcm43xx_hwxmitstatus *hw; |
566 | struct bcm43xx_xmitstatus stat; | ||
567 | |||
568 | hw = (struct bcm43xx_hwxmitstatus *)(preamble + 1); | ||
569 | stat.cookie = le16_to_cpu(hw->cookie); | ||
570 | stat.flags = hw->flags; | ||
571 | stat.cnt1 = hw->cnt1; | ||
572 | stat.cnt2 = hw->cnt2; | ||
573 | stat.seq = le16_to_cpu(hw->seq); | ||
574 | stat.unknown = le16_to_cpu(hw->unknown); | ||
575 | |||
576 | bcm43xx_debugfs_log_txstat(queue->bcm, &stat); | ||
577 | bcm43xx_pio_handle_xmitstatus(queue->bcm, &stat); | ||
578 | |||
569 | return; | 579 | return; |
570 | } | 580 | } |
571 | #endif | 581 | |
572 | skb = dev_alloc_skb(len); | 582 | skb = dev_alloc_skb(len); |
573 | if (unlikely(!skb)) { | 583 | if (unlikely(!skb)) { |
574 | pio_rx_error(queue, "out of memory"); | 584 | pio_rx_error(queue, 1, "OOM"); |
575 | return; | 585 | return; |
576 | } | 586 | } |
577 | skb_put(skb, len); | 587 | skb_put(skb, len); |
@@ -580,13 +590,14 @@ data_ready: | |||
580 | *((u16 *)(skb->data + i)) = tmp; | 590 | *((u16 *)(skb->data + i)) = tmp; |
581 | } | 591 | } |
582 | if (len % 2) { | 592 | if (len % 2) { |
583 | tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); | 593 | tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); |
584 | skb->data[len - 1] = (tmp & 0x00FF); | 594 | skb->data[len - 1] = (tmp & 0x00FF); |
585 | skb->data[0] = (tmp & 0xFF00) >> 8; | 595 | if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) |
596 | skb->data[0x20] = (tmp & 0xFF00) >> 8; | ||
597 | else | ||
598 | skb->data[0x1E] = (tmp & 0xFF00) >> 8; | ||
586 | } | 599 | } |
587 | err = bcm43xx_rx(queue->bcm, skb, rxhdr); | 600 | bcm43xx_rx(queue->bcm, skb, rxhdr); |
588 | if (unlikely(err)) | ||
589 | dev_kfree_skb_irq(skb); | ||
590 | } | 601 | } |
591 | 602 | ||
592 | /* vim: set ts=8 sw=8 sts=8: */ | 603 | /* vim: set ts=8 sw=8 sts=8: */ |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h index 71b92ee34169..970627bc1769 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h | |||
@@ -3,9 +3,8 @@ | |||
3 | 3 | ||
4 | #include "bcm43xx.h" | 4 | #include "bcm43xx.h" |
5 | 5 | ||
6 | #include <linux/interrupt.h> | ||
6 | #include <linux/list.h> | 7 | #include <linux/list.h> |
7 | #include <linux/spinlock.h> | ||
8 | #include <linux/workqueue.h> | ||
9 | #include <linux/skbuff.h> | 8 | #include <linux/skbuff.h> |
10 | 9 | ||
11 | 10 | ||
@@ -32,6 +31,10 @@ | |||
32 | #define BCM43xx_PIO_MAXTXPACKETS 256 | 31 | #define BCM43xx_PIO_MAXTXPACKETS 256 |
33 | 32 | ||
34 | 33 | ||
34 | |||
35 | #ifdef CONFIG_BCM43XX_PIO | ||
36 | |||
37 | |||
35 | struct bcm43xx_pioqueue; | 38 | struct bcm43xx_pioqueue; |
36 | struct bcm43xx_xmitstatus; | 39 | struct bcm43xx_xmitstatus; |
37 | 40 | ||
@@ -44,13 +47,14 @@ struct bcm43xx_pio_txpacket { | |||
44 | u16 xmitted_octets; | 47 | u16 xmitted_octets; |
45 | }; | 48 | }; |
46 | 49 | ||
47 | #define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->__tx_packets_cache)) | 50 | #define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache)) |
48 | 51 | ||
49 | struct bcm43xx_pioqueue { | 52 | struct bcm43xx_pioqueue { |
50 | struct bcm43xx_private *bcm; | 53 | struct bcm43xx_private *bcm; |
51 | u16 mmio_base; | 54 | u16 mmio_base; |
52 | 55 | ||
53 | u8 tx_suspended:1; | 56 | u8 tx_suspended:1, |
57 | need_workarounds:1; /* Workarounds needed for core.rev < 3 */ | ||
54 | 58 | ||
55 | /* Adjusted size of the device internal TX buffer. */ | 59 | /* Adjusted size of the device internal TX buffer. */ |
56 | u16 tx_devq_size; | 60 | u16 tx_devq_size; |
@@ -62,6 +66,7 @@ struct bcm43xx_pioqueue { | |||
62 | * be taken on incoming TX requests. | 66 | * be taken on incoming TX requests. |
63 | */ | 67 | */ |
64 | struct list_head txfree; | 68 | struct list_head txfree; |
69 | unsigned int nr_txfree; | ||
65 | /* Packets on the txqueue are queued, | 70 | /* Packets on the txqueue are queued, |
66 | * but not completely written to the chip, yet. | 71 | * but not completely written to the chip, yet. |
67 | */ | 72 | */ |
@@ -70,19 +75,64 @@ struct bcm43xx_pioqueue { | |||
70 | * posted to the device. We are waiting for the txstatus. | 75 | * posted to the device. We are waiting for the txstatus. |
71 | */ | 76 | */ |
72 | struct list_head txrunning; | 77 | struct list_head txrunning; |
73 | /* Locking of the TX queues and the accounting. */ | 78 | /* Total number or packets sent. |
74 | spinlock_t txlock; | 79 | * (This counter can obviously wrap). |
75 | struct work_struct txwork; | 80 | */ |
76 | struct bcm43xx_pio_txpacket __tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS]; | 81 | unsigned int nr_tx_packets; |
82 | struct tasklet_struct txtask; | ||
83 | struct bcm43xx_pio_txpacket tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS]; | ||
77 | }; | 84 | }; |
78 | 85 | ||
86 | static inline | ||
87 | u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue, | ||
88 | u16 offset) | ||
89 | { | ||
90 | return bcm43xx_read16(queue->bcm, queue->mmio_base + offset); | ||
91 | } | ||
92 | |||
93 | static inline | ||
94 | void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue, | ||
95 | u16 offset, u16 value) | ||
96 | { | ||
97 | bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value); | ||
98 | } | ||
99 | |||
100 | |||
79 | int bcm43xx_pio_init(struct bcm43xx_private *bcm); | 101 | int bcm43xx_pio_init(struct bcm43xx_private *bcm); |
80 | void bcm43xx_pio_free(struct bcm43xx_private *bcm); | 102 | void bcm43xx_pio_free(struct bcm43xx_private *bcm); |
81 | 103 | ||
82 | int FASTCALL(bcm43xx_pio_transfer_txb(struct bcm43xx_private *bcm, | 104 | int bcm43xx_pio_tx(struct bcm43xx_private *bcm, |
83 | struct ieee80211_txb *txb)); | 105 | struct ieee80211_txb *txb); |
84 | void FASTCALL(bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, | 106 | void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, |
85 | struct bcm43xx_xmitstatus *status)); | 107 | struct bcm43xx_xmitstatus *status); |
86 | 108 | void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue); | |
87 | void FASTCALL(bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)); | 109 | |
110 | #else /* CONFIG_BCM43XX_PIO */ | ||
111 | |||
112 | static inline | ||
113 | int bcm43xx_pio_init(struct bcm43xx_private *bcm) | ||
114 | { | ||
115 | return 0; | ||
116 | } | ||
117 | static inline | ||
118 | void bcm43xx_pio_free(struct bcm43xx_private *bcm) | ||
119 | { | ||
120 | } | ||
121 | static inline | ||
122 | int bcm43xx_pio_tx(struct bcm43xx_private *bcm, | ||
123 | struct ieee80211_txb *txb) | ||
124 | { | ||
125 | return 0; | ||
126 | } | ||
127 | static inline | ||
128 | void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, | ||
129 | struct bcm43xx_xmitstatus *status) | ||
130 | { | ||
131 | } | ||
132 | static inline | ||
133 | void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) | ||
134 | { | ||
135 | } | ||
136 | |||
137 | #endif /* CONFIG_BCM43XX_PIO */ | ||
88 | #endif /* BCM43xx_PIO_H_ */ | 138 | #endif /* BCM43xx_PIO_H_ */ |